Merge "Add synthetic element in Ksp corresponds to @JvmStatic annotated companion method copied to enclosing class by Compiler in KAPT" into androidx-main
diff --git a/OWNERS b/OWNERS
index 9104654..f47cc78 100644
--- a/OWNERS
+++ b/OWNERS
@@ -27,7 +27,7 @@
per-file *settings.gradle = alanv@google.com, aurimas@google.com
per-file *libraryversions.toml = jnichol@google.com
per-file *libraryversions.toml = diegovela@google.com, akulian@google.com, kchyn@google.com
-per-file *docs-public/build.gradle = juanrdz@google.com
+per-file *docs-public/build.gradle = juanrdz@google.com, diegovela@google.com
# Copybara can self-approve CLs within synced docs.
per-file docs/** = copybara-worker-blackhole@google.com
\ No newline at end of file
diff --git a/appactions/builtintypes/builtintypes-core/api/current.txt b/appactions/builtintypes/builtintypes-core/api/current.txt
index 4033c72..f2534f8 100644
--- a/appactions/builtintypes/builtintypes-core/api/current.txt
+++ b/appactions/builtintypes/builtintypes-core/api/current.txt
@@ -39,63 +39,63 @@
}
public final class EndDate {
+ ctor public EndDate(java.time.Instant instant);
ctor public EndDate(java.time.LocalDate date);
ctor public EndDate(java.time.LocalDateTime localDateTime);
- ctor public EndDate(java.time.ZonedDateTime zonedDateTime);
method public java.time.LocalDate? getAsDate();
+ method public java.time.Instant? getAsInstant();
method public java.time.LocalDateTime? getAsLocalDateTime();
- method public java.time.ZonedDateTime? getAsZonedDateTime();
method public <R> R mapWhen(androidx.appactions.builtintypes.properties.EndDate.Mapper<R> mapper);
property public final java.time.LocalDate? asDate;
+ property public final java.time.Instant? asInstant;
property public final java.time.LocalDateTime? asLocalDateTime;
- property public final java.time.ZonedDateTime? asZonedDateTime;
}
public static interface EndDate.Mapper<R> {
method public default R date(java.time.LocalDate instance);
+ method public default R instant(java.time.Instant instance);
method public default R localDateTime(java.time.LocalDateTime instance);
method public R orElse();
- method public default R zonedDateTime(java.time.ZonedDateTime instance);
}
public final class EndTime {
+ ctor public EndTime(java.time.Instant instant);
ctor public EndTime(java.time.LocalDateTime localDateTime);
ctor public EndTime(java.time.LocalTime time);
- ctor public EndTime(java.time.ZonedDateTime zonedDateTime);
+ method public java.time.Instant? getAsInstant();
method public java.time.LocalDateTime? getAsLocalDateTime();
method public java.time.LocalTime? getAsTime();
- method public java.time.ZonedDateTime? getAsZonedDateTime();
method public <R> R mapWhen(androidx.appactions.builtintypes.properties.EndTime.Mapper<R> mapper);
+ property public final java.time.Instant? asInstant;
property public final java.time.LocalDateTime? asLocalDateTime;
property public final java.time.LocalTime? asTime;
- property public final java.time.ZonedDateTime? asZonedDateTime;
}
public static interface EndTime.Mapper<R> {
+ method public default R instant(java.time.Instant instance);
method public default R localDateTime(java.time.LocalDateTime instance);
method public R orElse();
method public default R time(java.time.LocalTime instance);
- method public default R zonedDateTime(java.time.ZonedDateTime instance);
}
public final class ExceptDate {
+ ctor public ExceptDate(java.time.Instant instant);
ctor public ExceptDate(java.time.LocalDate date);
ctor public ExceptDate(java.time.LocalDateTime localDateTime);
- ctor public ExceptDate(java.time.ZonedDateTime zonedDateTime);
method public java.time.LocalDate? getAsDate();
+ method public java.time.Instant? getAsInstant();
method public java.time.LocalDateTime? getAsLocalDateTime();
- method public java.time.ZonedDateTime? getAsZonedDateTime();
method public <R> R mapWhen(androidx.appactions.builtintypes.properties.ExceptDate.Mapper<R> mapper);
property public final java.time.LocalDate? asDate;
+ property public final java.time.Instant? asInstant;
property public final java.time.LocalDateTime? asLocalDateTime;
- property public final java.time.ZonedDateTime? asZonedDateTime;
}
public static interface ExceptDate.Mapper<R> {
method public default R date(java.time.LocalDate instance);
+ method public default R instant(java.time.Instant instance);
method public default R localDateTime(java.time.LocalDateTime instance);
method public R orElse();
- method public default R zonedDateTime(java.time.ZonedDateTime instance);
}
public final class Name {
@@ -121,49 +121,520 @@
}
public final class StartDate {
+ ctor public StartDate(java.time.Instant instant);
ctor public StartDate(java.time.LocalDate date);
ctor public StartDate(java.time.LocalDateTime localDateTime);
- ctor public StartDate(java.time.ZonedDateTime zonedDateTime);
method public java.time.LocalDate? getAsDate();
+ method public java.time.Instant? getAsInstant();
method public java.time.LocalDateTime? getAsLocalDateTime();
- method public java.time.ZonedDateTime? getAsZonedDateTime();
method public <R> R mapWhen(androidx.appactions.builtintypes.properties.StartDate.Mapper<R> mapper);
property public final java.time.LocalDate? asDate;
+ property public final java.time.Instant? asInstant;
property public final java.time.LocalDateTime? asLocalDateTime;
- property public final java.time.ZonedDateTime? asZonedDateTime;
}
public static interface StartDate.Mapper<R> {
method public default R date(java.time.LocalDate instance);
+ method public default R instant(java.time.Instant instance);
method public default R localDateTime(java.time.LocalDateTime instance);
method public R orElse();
- method public default R zonedDateTime(java.time.ZonedDateTime instance);
}
public final class StartTime {
+ ctor public StartTime(java.time.Instant instant);
ctor public StartTime(java.time.LocalDateTime localDateTime);
ctor public StartTime(java.time.LocalTime time);
- ctor public StartTime(java.time.ZonedDateTime zonedDateTime);
+ method public java.time.Instant? getAsInstant();
method public java.time.LocalDateTime? getAsLocalDateTime();
method public java.time.LocalTime? getAsTime();
- method public java.time.ZonedDateTime? getAsZonedDateTime();
method public <R> R mapWhen(androidx.appactions.builtintypes.properties.StartTime.Mapper<R> mapper);
+ property public final java.time.Instant? asInstant;
property public final java.time.LocalDateTime? asLocalDateTime;
property public final java.time.LocalTime? asTime;
- property public final java.time.ZonedDateTime? asZonedDateTime;
}
public static interface StartTime.Mapper<R> {
+ method public default R instant(java.time.Instant instance);
method public default R localDateTime(java.time.LocalDateTime instance);
method public R orElse();
method public default R time(java.time.LocalTime instance);
- method public default R zonedDateTime(java.time.ZonedDateTime instance);
}
}
package androidx.appactions.builtintypes.types {
+ public abstract class AbstractAlarm<Self extends androidx.appactions.builtintypes.types.AbstractAlarm<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractAlarm.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Alarm {
+ ctor public AbstractAlarm(androidx.appactions.builtintypes.types.Alarm alarm);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.types.Schedule? getAlarmSchedule();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.types.Schedule? alarmSchedule;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractAlarm.Builder<Self extends androidx.appactions.builtintypes.types.AbstractAlarm.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractAlarm<Built, Self>> implements androidx.appactions.builtintypes.types.Alarm.Builder<Self> {
+ ctor public AbstractAlarm.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromAlarm(androidx.appactions.builtintypes.types.Alarm alarm);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setAlarmSchedule(androidx.appactions.builtintypes.types.Schedule? schedule);
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractExecutionStatus<Self extends androidx.appactions.builtintypes.types.AbstractExecutionStatus<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractExecutionStatus.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.ExecutionStatus {
+ ctor public AbstractExecutionStatus(androidx.appactions.builtintypes.types.ExecutionStatus executionStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractExecutionStatus.Builder<Self extends androidx.appactions.builtintypes.types.AbstractExecutionStatus.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractExecutionStatus<Built, Self>> implements androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self> {
+ ctor public AbstractExecutionStatus.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromExecutionStatus(androidx.appactions.builtintypes.types.ExecutionStatus executionStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractGenericErrorStatus<Self extends androidx.appactions.builtintypes.types.AbstractGenericErrorStatus<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractGenericErrorStatus.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.GenericErrorStatus {
+ ctor public AbstractGenericErrorStatus(androidx.appactions.builtintypes.types.GenericErrorStatus genericErrorStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractGenericErrorStatus.Builder<Self extends androidx.appactions.builtintypes.types.AbstractGenericErrorStatus.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractGenericErrorStatus<Built, Self>> implements androidx.appactions.builtintypes.types.GenericErrorStatus.Builder<Self> {
+ ctor public AbstractGenericErrorStatus.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromGenericErrorStatus(androidx.appactions.builtintypes.types.GenericErrorStatus genericErrorStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractIntangible<Self extends androidx.appactions.builtintypes.types.AbstractIntangible<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractIntangible.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Intangible {
+ ctor public AbstractIntangible(androidx.appactions.builtintypes.types.Intangible intangible);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractIntangible.Builder<Self extends androidx.appactions.builtintypes.types.AbstractIntangible.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractIntangible<Built, Self>> implements androidx.appactions.builtintypes.types.Intangible.Builder<Self> {
+ ctor public AbstractIntangible.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromIntangible(androidx.appactions.builtintypes.types.Intangible intangible);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractObjectCreationLimitReachedStatus<Self extends androidx.appactions.builtintypes.types.AbstractObjectCreationLimitReachedStatus<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractObjectCreationLimitReachedStatus.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus {
+ ctor public AbstractObjectCreationLimitReachedStatus(androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus objectCreationLimitReachedStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractObjectCreationLimitReachedStatus.Builder<Self extends androidx.appactions.builtintypes.types.AbstractObjectCreationLimitReachedStatus.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractObjectCreationLimitReachedStatus<Built, Self>> implements androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Builder<Self> {
+ ctor public AbstractObjectCreationLimitReachedStatus.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromObjectCreationLimitReachedStatus(androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus objectCreationLimitReachedStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractPerson<Self extends androidx.appactions.builtintypes.types.AbstractPerson<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractPerson.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Person {
+ ctor public AbstractPerson(androidx.appactions.builtintypes.types.Person person);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getEmail();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? email;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractPerson.Builder<Self extends androidx.appactions.builtintypes.types.AbstractPerson.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractPerson<Built, Self>> implements androidx.appactions.builtintypes.types.Person.Builder<Self> {
+ ctor public AbstractPerson.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromPerson(androidx.appactions.builtintypes.types.Person person);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setEmail(String? text);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractSchedule<Self extends androidx.appactions.builtintypes.types.AbstractSchedule<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractSchedule.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Schedule {
+ ctor public AbstractSchedule(androidx.appactions.builtintypes.types.Schedule schedule);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final java.util.List<androidx.appactions.builtintypes.properties.ByDay> getByDays();
+ method public final java.util.List<java.lang.Long> getByMonthDays();
+ method public final java.util.List<java.lang.Long> getByMonthWeeks();
+ method public final java.util.List<java.lang.Long> getByMonths();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final androidx.appactions.builtintypes.properties.EndDate? getEndDate();
+ method public final androidx.appactions.builtintypes.properties.EndTime? getEndTime();
+ method public final androidx.appactions.builtintypes.properties.ExceptDate? getExceptDate();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method public final Long? getRepeatCount();
+ method public final androidx.appactions.builtintypes.properties.RepeatFrequency? getRepeatFrequency();
+ method public final String? getScheduleTimezone();
+ method protected abstract String getSelfTypeName();
+ method public final androidx.appactions.builtintypes.properties.StartDate? getStartDate();
+ method public final androidx.appactions.builtintypes.properties.StartTime? getStartTime();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final java.util.List<androidx.appactions.builtintypes.properties.ByDay> byDays;
+ property public final java.util.List<java.lang.Long> byMonthDays;
+ property public final java.util.List<java.lang.Long> byMonthWeeks;
+ property public final java.util.List<java.lang.Long> byMonths;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final androidx.appactions.builtintypes.properties.EndDate? endDate;
+ property public final androidx.appactions.builtintypes.properties.EndTime? endTime;
+ property public final androidx.appactions.builtintypes.properties.ExceptDate? exceptDate;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property public final Long? repeatCount;
+ property public final androidx.appactions.builtintypes.properties.RepeatFrequency? repeatFrequency;
+ property public final String? scheduleTimezone;
+ property protected abstract String selfTypeName;
+ property public final androidx.appactions.builtintypes.properties.StartDate? startDate;
+ property public final androidx.appactions.builtintypes.properties.StartTime? startTime;
+ }
+
+ public abstract static class AbstractSchedule.Builder<Self extends androidx.appactions.builtintypes.types.AbstractSchedule.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractSchedule<Built, Self>> implements androidx.appactions.builtintypes.types.Schedule.Builder<Self> {
+ ctor public AbstractSchedule.Builder();
+ method public final Self addByDay(androidx.appactions.builtintypes.properties.ByDay byDay);
+ method public final Self addByDays(Iterable<androidx.appactions.builtintypes.properties.ByDay> values);
+ method public final Self addByMonth(long integer);
+ method public final Self addByMonthDay(long integer);
+ method public final Self addByMonthDays(Iterable<java.lang.Long> values);
+ method public final Self addByMonthWeek(long integer);
+ method public final Self addByMonthWeeks(Iterable<java.lang.Long> values);
+ method public final Self addByMonths(Iterable<java.lang.Long> values);
+ method public final Built build();
+ method protected abstract Built buildFromSchedule(androidx.appactions.builtintypes.types.Schedule schedule);
+ method public final Self clearByDays();
+ method public final Self clearByMonthDays();
+ method public final Self clearByMonthWeeks();
+ method public final Self clearByMonths();
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setEndDate(androidx.appactions.builtintypes.properties.EndDate? endDate);
+ method public final Self setEndTime(androidx.appactions.builtintypes.properties.EndTime? endTime);
+ method public final Self setExceptDate(androidx.appactions.builtintypes.properties.ExceptDate? exceptDate);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final Self setRepeatCount(Long? integer);
+ method public final Self setRepeatFrequency(androidx.appactions.builtintypes.properties.RepeatFrequency? repeatFrequency);
+ method public final Self setScheduleTimezone(String? text);
+ method public final Self setStartDate(androidx.appactions.builtintypes.properties.StartDate? startDate);
+ method public final Self setStartTime(androidx.appactions.builtintypes.properties.StartTime? startTime);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractSuccessStatus<Self extends androidx.appactions.builtintypes.types.AbstractSuccessStatus<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractSuccessStatus.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.SuccessStatus {
+ ctor public AbstractSuccessStatus(androidx.appactions.builtintypes.types.SuccessStatus successStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractSuccessStatus.Builder<Self extends androidx.appactions.builtintypes.types.AbstractSuccessStatus.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractSuccessStatus<Built, Self>> implements androidx.appactions.builtintypes.types.SuccessStatus.Builder<Self> {
+ ctor public AbstractSuccessStatus.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromSuccessStatus(androidx.appactions.builtintypes.types.SuccessStatus successStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractThing<Self extends androidx.appactions.builtintypes.types.AbstractThing<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractThing.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Thing {
+ ctor public AbstractThing(androidx.appactions.builtintypes.types.Thing thing);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractThing.Builder<Self extends androidx.appactions.builtintypes.types.AbstractThing.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractThing<Built, Self>> implements androidx.appactions.builtintypes.types.Thing.Builder<Self> {
+ ctor public AbstractThing.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromThing(androidx.appactions.builtintypes.types.Thing thing);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractTimer<Self extends androidx.appactions.builtintypes.types.AbstractTimer<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractTimer.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Timer {
+ ctor public AbstractTimer(androidx.appactions.builtintypes.types.Timer timer);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final java.time.Duration? getDuration();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final java.time.Duration? duration;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractTimer.Builder<Self extends androidx.appactions.builtintypes.types.AbstractTimer.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractTimer<Built, Self>> implements androidx.appactions.builtintypes.types.Timer.Builder<Self> {
+ ctor public AbstractTimer.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromTimer(androidx.appactions.builtintypes.types.Timer timer);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setDuration(java.time.Duration? duration);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractUnsupportedOperationStatus<Self extends androidx.appactions.builtintypes.types.AbstractUnsupportedOperationStatus<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractUnsupportedOperationStatus.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.UnsupportedOperationStatus {
+ ctor public AbstractUnsupportedOperationStatus(androidx.appactions.builtintypes.types.UnsupportedOperationStatus unsupportedOperationStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractUnsupportedOperationStatus.Builder<Self extends androidx.appactions.builtintypes.types.AbstractUnsupportedOperationStatus.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractUnsupportedOperationStatus<Built, Self>> implements androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Builder<Self> {
+ ctor public AbstractUnsupportedOperationStatus.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromUnsupportedOperationStatus(androidx.appactions.builtintypes.types.UnsupportedOperationStatus unsupportedOperationStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
public interface Alarm extends androidx.appactions.builtintypes.types.Thing {
method public default static androidx.appactions.builtintypes.types.Alarm.Builder<?> Builder();
method public androidx.appactions.builtintypes.types.Schedule? getAlarmSchedule();
@@ -222,267 +693,32 @@
method public default R wednesday();
}
- public abstract class GenericAlarm<Self extends androidx.appactions.builtintypes.types.GenericAlarm<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericAlarm.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Alarm {
- ctor public GenericAlarm(androidx.appactions.builtintypes.types.Alarm alarm);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final androidx.appactions.builtintypes.types.Schedule? getAlarmSchedule();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final androidx.appactions.builtintypes.types.Schedule? alarmSchedule;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property protected abstract String selfTypeName;
+ public interface ExecutionStatus extends androidx.appactions.builtintypes.types.Intangible {
+ method public default static androidx.appactions.builtintypes.types.ExecutionStatus.Builder<?> Builder();
+ method public androidx.appactions.builtintypes.types.ExecutionStatus.Builder<?> toBuilder();
+ field public static final androidx.appactions.builtintypes.types.ExecutionStatus.Companion Companion;
}
- public abstract static class GenericAlarm.Builder<Self extends androidx.appactions.builtintypes.types.GenericAlarm.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericAlarm<Built, Self>> implements androidx.appactions.builtintypes.types.Alarm.Builder<Self> {
- ctor public GenericAlarm.Builder();
- method public final Built build();
- method protected abstract Built buildFromAlarm(androidx.appactions.builtintypes.types.Alarm alarm);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setAlarmSchedule(androidx.appactions.builtintypes.types.Schedule? schedule);
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
+ public static interface ExecutionStatus.Builder<Self extends androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self>> extends androidx.appactions.builtintypes.types.Intangible.Builder<Self> {
+ method public androidx.appactions.builtintypes.types.ExecutionStatus build();
}
- public abstract class GenericIntangible<Self extends androidx.appactions.builtintypes.types.GenericIntangible<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericIntangible.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Intangible {
- ctor public GenericIntangible(androidx.appactions.builtintypes.types.Intangible intangible);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property protected abstract String selfTypeName;
+ public static final class ExecutionStatus.Companion {
+ method public androidx.appactions.builtintypes.types.ExecutionStatus.Builder<?> Builder();
}
- public abstract static class GenericIntangible.Builder<Self extends androidx.appactions.builtintypes.types.GenericIntangible.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericIntangible<Built, Self>> implements androidx.appactions.builtintypes.types.Intangible.Builder<Self> {
- ctor public GenericIntangible.Builder();
- method public final Built build();
- method protected abstract Built buildFromIntangible(androidx.appactions.builtintypes.types.Intangible intangible);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
+ public interface GenericErrorStatus extends androidx.appactions.builtintypes.types.ExecutionStatus {
+ method public default static androidx.appactions.builtintypes.types.GenericErrorStatus.Builder<?> Builder();
+ method public androidx.appactions.builtintypes.types.GenericErrorStatus.Builder<?> toBuilder();
+ field public static final androidx.appactions.builtintypes.types.GenericErrorStatus.Companion Companion;
}
- public abstract class GenericPerson<Self extends androidx.appactions.builtintypes.types.GenericPerson<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericPerson.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Person {
- ctor public GenericPerson(androidx.appactions.builtintypes.types.Person person);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final String? getEmail();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final String? email;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property protected abstract String selfTypeName;
+ public static interface GenericErrorStatus.Builder<Self extends androidx.appactions.builtintypes.types.GenericErrorStatus.Builder<Self>> extends androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self> {
+ method public androidx.appactions.builtintypes.types.GenericErrorStatus build();
}
- public abstract static class GenericPerson.Builder<Self extends androidx.appactions.builtintypes.types.GenericPerson.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericPerson<Built, Self>> implements androidx.appactions.builtintypes.types.Person.Builder<Self> {
- ctor public GenericPerson.Builder();
- method public final Built build();
- method protected abstract Built buildFromPerson(androidx.appactions.builtintypes.types.Person person);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setEmail(String? text);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
- }
-
- public abstract class GenericSchedule<Self extends androidx.appactions.builtintypes.types.GenericSchedule<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericSchedule.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Schedule {
- ctor public GenericSchedule(androidx.appactions.builtintypes.types.Schedule schedule);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final java.util.List<androidx.appactions.builtintypes.properties.ByDay> getByDays();
- method public final java.util.List<java.lang.Long> getByMonthDays();
- method public final java.util.List<java.lang.Long> getByMonthWeeks();
- method public final java.util.List<java.lang.Long> getByMonths();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final androidx.appactions.builtintypes.properties.EndDate? getEndDate();
- method public final androidx.appactions.builtintypes.properties.EndTime? getEndTime();
- method public final androidx.appactions.builtintypes.properties.ExceptDate? getExceptDate();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method public final Long? getRepeatCount();
- method public final androidx.appactions.builtintypes.properties.RepeatFrequency? getRepeatFrequency();
- method public final String? getScheduleTimezone();
- method protected abstract String getSelfTypeName();
- method public final androidx.appactions.builtintypes.properties.StartDate? getStartDate();
- method public final androidx.appactions.builtintypes.properties.StartTime? getStartTime();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final java.util.List<androidx.appactions.builtintypes.properties.ByDay> byDays;
- property public final java.util.List<java.lang.Long> byMonthDays;
- property public final java.util.List<java.lang.Long> byMonthWeeks;
- property public final java.util.List<java.lang.Long> byMonths;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final androidx.appactions.builtintypes.properties.EndDate? endDate;
- property public final androidx.appactions.builtintypes.properties.EndTime? endTime;
- property public final androidx.appactions.builtintypes.properties.ExceptDate? exceptDate;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property public final Long? repeatCount;
- property public final androidx.appactions.builtintypes.properties.RepeatFrequency? repeatFrequency;
- property public final String? scheduleTimezone;
- property protected abstract String selfTypeName;
- property public final androidx.appactions.builtintypes.properties.StartDate? startDate;
- property public final androidx.appactions.builtintypes.properties.StartTime? startTime;
- }
-
- public abstract static class GenericSchedule.Builder<Self extends androidx.appactions.builtintypes.types.GenericSchedule.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericSchedule<Built, Self>> implements androidx.appactions.builtintypes.types.Schedule.Builder<Self> {
- ctor public GenericSchedule.Builder();
- method public final Self addByDay(androidx.appactions.builtintypes.properties.ByDay byDay);
- method public final Self addByDays(Iterable<androidx.appactions.builtintypes.properties.ByDay> values);
- method public final Self addByMonth(long integer);
- method public final Self addByMonthDay(long integer);
- method public final Self addByMonthDays(Iterable<java.lang.Long> values);
- method public final Self addByMonthWeek(long integer);
- method public final Self addByMonthWeeks(Iterable<java.lang.Long> values);
- method public final Self addByMonths(Iterable<java.lang.Long> values);
- method public final Built build();
- method protected abstract Built buildFromSchedule(androidx.appactions.builtintypes.types.Schedule schedule);
- method public final Self clearByDays();
- method public final Self clearByMonthDays();
- method public final Self clearByMonthWeeks();
- method public final Self clearByMonths();
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setEndDate(androidx.appactions.builtintypes.properties.EndDate? endDate);
- method public final Self setEndTime(androidx.appactions.builtintypes.properties.EndTime? endTime);
- method public final Self setExceptDate(androidx.appactions.builtintypes.properties.ExceptDate? exceptDate);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final Self setRepeatCount(Long? integer);
- method public final Self setRepeatFrequency(androidx.appactions.builtintypes.properties.RepeatFrequency? repeatFrequency);
- method public final Self setScheduleTimezone(String? text);
- method public final Self setStartDate(androidx.appactions.builtintypes.properties.StartDate? startDate);
- method public final Self setStartTime(androidx.appactions.builtintypes.properties.StartTime? startTime);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
- }
-
- public abstract class GenericThing<Self extends androidx.appactions.builtintypes.types.GenericThing<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericThing.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Thing {
- ctor public GenericThing(androidx.appactions.builtintypes.types.Thing thing);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property protected abstract String selfTypeName;
- }
-
- public abstract static class GenericThing.Builder<Self extends androidx.appactions.builtintypes.types.GenericThing.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericThing<Built, Self>> implements androidx.appactions.builtintypes.types.Thing.Builder<Self> {
- ctor public GenericThing.Builder();
- method public final Built build();
- method protected abstract Built buildFromThing(androidx.appactions.builtintypes.types.Thing thing);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
- }
-
- public abstract class GenericTimer<Self extends androidx.appactions.builtintypes.types.GenericTimer<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericTimer.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Timer {
- ctor public GenericTimer(androidx.appactions.builtintypes.types.Timer timer);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final java.time.Duration? getDuration();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final java.time.Duration? duration;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property protected abstract String selfTypeName;
- }
-
- public abstract static class GenericTimer.Builder<Self extends androidx.appactions.builtintypes.types.GenericTimer.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericTimer<Built, Self>> implements androidx.appactions.builtintypes.types.Timer.Builder<Self> {
- ctor public GenericTimer.Builder();
- method public final Built build();
- method protected abstract Built buildFromTimer(androidx.appactions.builtintypes.types.Timer timer);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setDuration(java.time.Duration? duration);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
+ public static final class GenericErrorStatus.Companion {
+ method public androidx.appactions.builtintypes.types.GenericErrorStatus.Builder<?> Builder();
}
public interface Intangible extends androidx.appactions.builtintypes.types.Thing {
@@ -499,6 +735,20 @@
method public androidx.appactions.builtintypes.types.Intangible.Builder<?> Builder();
}
+ public interface ObjectCreationLimitReachedStatus extends androidx.appactions.builtintypes.types.ExecutionStatus {
+ method public default static androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Builder<?> Builder();
+ method public androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Builder<?> toBuilder();
+ field public static final androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Companion Companion;
+ }
+
+ public static interface ObjectCreationLimitReachedStatus.Builder<Self extends androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Builder<Self>> extends androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self> {
+ method public androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus build();
+ }
+
+ public static final class ObjectCreationLimitReachedStatus.Companion {
+ method public androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Builder<?> Builder();
+ }
+
public interface Person extends androidx.appactions.builtintypes.types.Thing {
method public default static androidx.appactions.builtintypes.types.Person.Builder<?> Builder();
method public String? getEmail();
@@ -563,45 +813,61 @@
method public Self clearByMonthWeeks();
method public Self clearByMonths();
method public Self setEndDate(androidx.appactions.builtintypes.properties.EndDate? endDate);
+ method public default Self setEndDate(java.time.Instant instant);
method public default Self setEndDate(java.time.LocalDate date);
method public default Self setEndDate(java.time.LocalDateTime localDateTime);
- method public default Self setEndDate(java.time.ZonedDateTime zonedDateTime);
method public Self setEndTime(androidx.appactions.builtintypes.properties.EndTime? endTime);
+ method public default Self setEndTime(java.time.Instant instant);
method public default Self setEndTime(java.time.LocalDateTime localDateTime);
method public default Self setEndTime(java.time.LocalTime time);
- method public default Self setEndTime(java.time.ZonedDateTime zonedDateTime);
method public Self setExceptDate(androidx.appactions.builtintypes.properties.ExceptDate? exceptDate);
+ method public default Self setExceptDate(java.time.Instant instant);
method public default Self setExceptDate(java.time.LocalDate date);
method public default Self setExceptDate(java.time.LocalDateTime localDateTime);
- method public default Self setExceptDate(java.time.ZonedDateTime zonedDateTime);
method public Self setRepeatCount(Long? integer);
method public Self setRepeatFrequency(androidx.appactions.builtintypes.properties.RepeatFrequency? repeatFrequency);
method public default Self setRepeatFrequency(String text);
method public default Self setRepeatFrequency(java.time.Duration duration);
method public Self setScheduleTimezone(String? text);
method public Self setStartDate(androidx.appactions.builtintypes.properties.StartDate? startDate);
+ method public default Self setStartDate(java.time.Instant instant);
method public default Self setStartDate(java.time.LocalDate date);
method public default Self setStartDate(java.time.LocalDateTime localDateTime);
- method public default Self setStartDate(java.time.ZonedDateTime zonedDateTime);
method public Self setStartTime(androidx.appactions.builtintypes.properties.StartTime? startTime);
+ method public default Self setStartTime(java.time.Instant instant);
method public default Self setStartTime(java.time.LocalDateTime localDateTime);
method public default Self setStartTime(java.time.LocalTime time);
- method public default Self setStartTime(java.time.ZonedDateTime zonedDateTime);
}
public static final class Schedule.Companion {
method public androidx.appactions.builtintypes.types.Schedule.Builder<?> Builder();
}
+ public interface SuccessStatus extends androidx.appactions.builtintypes.types.ExecutionStatus {
+ method public default static androidx.appactions.builtintypes.types.SuccessStatus.Builder<?> Builder();
+ method public androidx.appactions.builtintypes.types.SuccessStatus.Builder<?> toBuilder();
+ field public static final androidx.appactions.builtintypes.types.SuccessStatus.Companion Companion;
+ }
+
+ public static interface SuccessStatus.Builder<Self extends androidx.appactions.builtintypes.types.SuccessStatus.Builder<Self>> extends androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self> {
+ method public androidx.appactions.builtintypes.types.SuccessStatus build();
+ }
+
+ public static final class SuccessStatus.Companion {
+ method public androidx.appactions.builtintypes.types.SuccessStatus.Builder<?> Builder();
+ }
+
public interface Thing {
method public default static androidx.appactions.builtintypes.types.Thing.Builder<?> Builder();
method public androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
method public String? getIdentifier();
method public androidx.appactions.builtintypes.properties.Name? getName();
+ method public String? getNamespace();
method public androidx.appactions.builtintypes.types.Thing.Builder<?> toBuilder();
property public abstract androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
property public abstract String? identifier;
property public abstract androidx.appactions.builtintypes.properties.Name? name;
+ property public abstract String? namespace;
field public static final androidx.appactions.builtintypes.types.Thing.Companion Companion;
}
@@ -612,6 +878,7 @@
method public Self setIdentifier(String? text);
method public Self setName(androidx.appactions.builtintypes.properties.Name? name);
method public default Self setName(String text);
+ method public Self setNamespace(String? namespace);
}
public static final class Thing.Companion {
@@ -635,5 +902,19 @@
method public androidx.appactions.builtintypes.types.Timer.Builder<?> Builder();
}
+ public interface UnsupportedOperationStatus extends androidx.appactions.builtintypes.types.ExecutionStatus {
+ method public default static androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Builder<?> Builder();
+ method public androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Builder<?> toBuilder();
+ field public static final androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Companion Companion;
+ }
+
+ public static interface UnsupportedOperationStatus.Builder<Self extends androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Builder<Self>> extends androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self> {
+ method public androidx.appactions.builtintypes.types.UnsupportedOperationStatus build();
+ }
+
+ public static final class UnsupportedOperationStatus.Companion {
+ method public androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Builder<?> Builder();
+ }
+
}
diff --git a/appactions/builtintypes/builtintypes-core/api/restricted_current.txt b/appactions/builtintypes/builtintypes-core/api/restricted_current.txt
index 4033c72..f2534f8 100644
--- a/appactions/builtintypes/builtintypes-core/api/restricted_current.txt
+++ b/appactions/builtintypes/builtintypes-core/api/restricted_current.txt
@@ -39,63 +39,63 @@
}
public final class EndDate {
+ ctor public EndDate(java.time.Instant instant);
ctor public EndDate(java.time.LocalDate date);
ctor public EndDate(java.time.LocalDateTime localDateTime);
- ctor public EndDate(java.time.ZonedDateTime zonedDateTime);
method public java.time.LocalDate? getAsDate();
+ method public java.time.Instant? getAsInstant();
method public java.time.LocalDateTime? getAsLocalDateTime();
- method public java.time.ZonedDateTime? getAsZonedDateTime();
method public <R> R mapWhen(androidx.appactions.builtintypes.properties.EndDate.Mapper<R> mapper);
property public final java.time.LocalDate? asDate;
+ property public final java.time.Instant? asInstant;
property public final java.time.LocalDateTime? asLocalDateTime;
- property public final java.time.ZonedDateTime? asZonedDateTime;
}
public static interface EndDate.Mapper<R> {
method public default R date(java.time.LocalDate instance);
+ method public default R instant(java.time.Instant instance);
method public default R localDateTime(java.time.LocalDateTime instance);
method public R orElse();
- method public default R zonedDateTime(java.time.ZonedDateTime instance);
}
public final class EndTime {
+ ctor public EndTime(java.time.Instant instant);
ctor public EndTime(java.time.LocalDateTime localDateTime);
ctor public EndTime(java.time.LocalTime time);
- ctor public EndTime(java.time.ZonedDateTime zonedDateTime);
+ method public java.time.Instant? getAsInstant();
method public java.time.LocalDateTime? getAsLocalDateTime();
method public java.time.LocalTime? getAsTime();
- method public java.time.ZonedDateTime? getAsZonedDateTime();
method public <R> R mapWhen(androidx.appactions.builtintypes.properties.EndTime.Mapper<R> mapper);
+ property public final java.time.Instant? asInstant;
property public final java.time.LocalDateTime? asLocalDateTime;
property public final java.time.LocalTime? asTime;
- property public final java.time.ZonedDateTime? asZonedDateTime;
}
public static interface EndTime.Mapper<R> {
+ method public default R instant(java.time.Instant instance);
method public default R localDateTime(java.time.LocalDateTime instance);
method public R orElse();
method public default R time(java.time.LocalTime instance);
- method public default R zonedDateTime(java.time.ZonedDateTime instance);
}
public final class ExceptDate {
+ ctor public ExceptDate(java.time.Instant instant);
ctor public ExceptDate(java.time.LocalDate date);
ctor public ExceptDate(java.time.LocalDateTime localDateTime);
- ctor public ExceptDate(java.time.ZonedDateTime zonedDateTime);
method public java.time.LocalDate? getAsDate();
+ method public java.time.Instant? getAsInstant();
method public java.time.LocalDateTime? getAsLocalDateTime();
- method public java.time.ZonedDateTime? getAsZonedDateTime();
method public <R> R mapWhen(androidx.appactions.builtintypes.properties.ExceptDate.Mapper<R> mapper);
property public final java.time.LocalDate? asDate;
+ property public final java.time.Instant? asInstant;
property public final java.time.LocalDateTime? asLocalDateTime;
- property public final java.time.ZonedDateTime? asZonedDateTime;
}
public static interface ExceptDate.Mapper<R> {
method public default R date(java.time.LocalDate instance);
+ method public default R instant(java.time.Instant instance);
method public default R localDateTime(java.time.LocalDateTime instance);
method public R orElse();
- method public default R zonedDateTime(java.time.ZonedDateTime instance);
}
public final class Name {
@@ -121,49 +121,520 @@
}
public final class StartDate {
+ ctor public StartDate(java.time.Instant instant);
ctor public StartDate(java.time.LocalDate date);
ctor public StartDate(java.time.LocalDateTime localDateTime);
- ctor public StartDate(java.time.ZonedDateTime zonedDateTime);
method public java.time.LocalDate? getAsDate();
+ method public java.time.Instant? getAsInstant();
method public java.time.LocalDateTime? getAsLocalDateTime();
- method public java.time.ZonedDateTime? getAsZonedDateTime();
method public <R> R mapWhen(androidx.appactions.builtintypes.properties.StartDate.Mapper<R> mapper);
property public final java.time.LocalDate? asDate;
+ property public final java.time.Instant? asInstant;
property public final java.time.LocalDateTime? asLocalDateTime;
- property public final java.time.ZonedDateTime? asZonedDateTime;
}
public static interface StartDate.Mapper<R> {
method public default R date(java.time.LocalDate instance);
+ method public default R instant(java.time.Instant instance);
method public default R localDateTime(java.time.LocalDateTime instance);
method public R orElse();
- method public default R zonedDateTime(java.time.ZonedDateTime instance);
}
public final class StartTime {
+ ctor public StartTime(java.time.Instant instant);
ctor public StartTime(java.time.LocalDateTime localDateTime);
ctor public StartTime(java.time.LocalTime time);
- ctor public StartTime(java.time.ZonedDateTime zonedDateTime);
+ method public java.time.Instant? getAsInstant();
method public java.time.LocalDateTime? getAsLocalDateTime();
method public java.time.LocalTime? getAsTime();
- method public java.time.ZonedDateTime? getAsZonedDateTime();
method public <R> R mapWhen(androidx.appactions.builtintypes.properties.StartTime.Mapper<R> mapper);
+ property public final java.time.Instant? asInstant;
property public final java.time.LocalDateTime? asLocalDateTime;
property public final java.time.LocalTime? asTime;
- property public final java.time.ZonedDateTime? asZonedDateTime;
}
public static interface StartTime.Mapper<R> {
+ method public default R instant(java.time.Instant instance);
method public default R localDateTime(java.time.LocalDateTime instance);
method public R orElse();
method public default R time(java.time.LocalTime instance);
- method public default R zonedDateTime(java.time.ZonedDateTime instance);
}
}
package androidx.appactions.builtintypes.types {
+ public abstract class AbstractAlarm<Self extends androidx.appactions.builtintypes.types.AbstractAlarm<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractAlarm.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Alarm {
+ ctor public AbstractAlarm(androidx.appactions.builtintypes.types.Alarm alarm);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.types.Schedule? getAlarmSchedule();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.types.Schedule? alarmSchedule;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractAlarm.Builder<Self extends androidx.appactions.builtintypes.types.AbstractAlarm.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractAlarm<Built, Self>> implements androidx.appactions.builtintypes.types.Alarm.Builder<Self> {
+ ctor public AbstractAlarm.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromAlarm(androidx.appactions.builtintypes.types.Alarm alarm);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setAlarmSchedule(androidx.appactions.builtintypes.types.Schedule? schedule);
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractExecutionStatus<Self extends androidx.appactions.builtintypes.types.AbstractExecutionStatus<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractExecutionStatus.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.ExecutionStatus {
+ ctor public AbstractExecutionStatus(androidx.appactions.builtintypes.types.ExecutionStatus executionStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractExecutionStatus.Builder<Self extends androidx.appactions.builtintypes.types.AbstractExecutionStatus.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractExecutionStatus<Built, Self>> implements androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self> {
+ ctor public AbstractExecutionStatus.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromExecutionStatus(androidx.appactions.builtintypes.types.ExecutionStatus executionStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractGenericErrorStatus<Self extends androidx.appactions.builtintypes.types.AbstractGenericErrorStatus<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractGenericErrorStatus.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.GenericErrorStatus {
+ ctor public AbstractGenericErrorStatus(androidx.appactions.builtintypes.types.GenericErrorStatus genericErrorStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractGenericErrorStatus.Builder<Self extends androidx.appactions.builtintypes.types.AbstractGenericErrorStatus.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractGenericErrorStatus<Built, Self>> implements androidx.appactions.builtintypes.types.GenericErrorStatus.Builder<Self> {
+ ctor public AbstractGenericErrorStatus.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromGenericErrorStatus(androidx.appactions.builtintypes.types.GenericErrorStatus genericErrorStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractIntangible<Self extends androidx.appactions.builtintypes.types.AbstractIntangible<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractIntangible.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Intangible {
+ ctor public AbstractIntangible(androidx.appactions.builtintypes.types.Intangible intangible);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractIntangible.Builder<Self extends androidx.appactions.builtintypes.types.AbstractIntangible.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractIntangible<Built, Self>> implements androidx.appactions.builtintypes.types.Intangible.Builder<Self> {
+ ctor public AbstractIntangible.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromIntangible(androidx.appactions.builtintypes.types.Intangible intangible);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractObjectCreationLimitReachedStatus<Self extends androidx.appactions.builtintypes.types.AbstractObjectCreationLimitReachedStatus<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractObjectCreationLimitReachedStatus.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus {
+ ctor public AbstractObjectCreationLimitReachedStatus(androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus objectCreationLimitReachedStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractObjectCreationLimitReachedStatus.Builder<Self extends androidx.appactions.builtintypes.types.AbstractObjectCreationLimitReachedStatus.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractObjectCreationLimitReachedStatus<Built, Self>> implements androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Builder<Self> {
+ ctor public AbstractObjectCreationLimitReachedStatus.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromObjectCreationLimitReachedStatus(androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus objectCreationLimitReachedStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractPerson<Self extends androidx.appactions.builtintypes.types.AbstractPerson<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractPerson.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Person {
+ ctor public AbstractPerson(androidx.appactions.builtintypes.types.Person person);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getEmail();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? email;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractPerson.Builder<Self extends androidx.appactions.builtintypes.types.AbstractPerson.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractPerson<Built, Self>> implements androidx.appactions.builtintypes.types.Person.Builder<Self> {
+ ctor public AbstractPerson.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromPerson(androidx.appactions.builtintypes.types.Person person);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setEmail(String? text);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractSchedule<Self extends androidx.appactions.builtintypes.types.AbstractSchedule<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractSchedule.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Schedule {
+ ctor public AbstractSchedule(androidx.appactions.builtintypes.types.Schedule schedule);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final java.util.List<androidx.appactions.builtintypes.properties.ByDay> getByDays();
+ method public final java.util.List<java.lang.Long> getByMonthDays();
+ method public final java.util.List<java.lang.Long> getByMonthWeeks();
+ method public final java.util.List<java.lang.Long> getByMonths();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final androidx.appactions.builtintypes.properties.EndDate? getEndDate();
+ method public final androidx.appactions.builtintypes.properties.EndTime? getEndTime();
+ method public final androidx.appactions.builtintypes.properties.ExceptDate? getExceptDate();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method public final Long? getRepeatCount();
+ method public final androidx.appactions.builtintypes.properties.RepeatFrequency? getRepeatFrequency();
+ method public final String? getScheduleTimezone();
+ method protected abstract String getSelfTypeName();
+ method public final androidx.appactions.builtintypes.properties.StartDate? getStartDate();
+ method public final androidx.appactions.builtintypes.properties.StartTime? getStartTime();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final java.util.List<androidx.appactions.builtintypes.properties.ByDay> byDays;
+ property public final java.util.List<java.lang.Long> byMonthDays;
+ property public final java.util.List<java.lang.Long> byMonthWeeks;
+ property public final java.util.List<java.lang.Long> byMonths;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final androidx.appactions.builtintypes.properties.EndDate? endDate;
+ property public final androidx.appactions.builtintypes.properties.EndTime? endTime;
+ property public final androidx.appactions.builtintypes.properties.ExceptDate? exceptDate;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property public final Long? repeatCount;
+ property public final androidx.appactions.builtintypes.properties.RepeatFrequency? repeatFrequency;
+ property public final String? scheduleTimezone;
+ property protected abstract String selfTypeName;
+ property public final androidx.appactions.builtintypes.properties.StartDate? startDate;
+ property public final androidx.appactions.builtintypes.properties.StartTime? startTime;
+ }
+
+ public abstract static class AbstractSchedule.Builder<Self extends androidx.appactions.builtintypes.types.AbstractSchedule.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractSchedule<Built, Self>> implements androidx.appactions.builtintypes.types.Schedule.Builder<Self> {
+ ctor public AbstractSchedule.Builder();
+ method public final Self addByDay(androidx.appactions.builtintypes.properties.ByDay byDay);
+ method public final Self addByDays(Iterable<androidx.appactions.builtintypes.properties.ByDay> values);
+ method public final Self addByMonth(long integer);
+ method public final Self addByMonthDay(long integer);
+ method public final Self addByMonthDays(Iterable<java.lang.Long> values);
+ method public final Self addByMonthWeek(long integer);
+ method public final Self addByMonthWeeks(Iterable<java.lang.Long> values);
+ method public final Self addByMonths(Iterable<java.lang.Long> values);
+ method public final Built build();
+ method protected abstract Built buildFromSchedule(androidx.appactions.builtintypes.types.Schedule schedule);
+ method public final Self clearByDays();
+ method public final Self clearByMonthDays();
+ method public final Self clearByMonthWeeks();
+ method public final Self clearByMonths();
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setEndDate(androidx.appactions.builtintypes.properties.EndDate? endDate);
+ method public final Self setEndTime(androidx.appactions.builtintypes.properties.EndTime? endTime);
+ method public final Self setExceptDate(androidx.appactions.builtintypes.properties.ExceptDate? exceptDate);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final Self setRepeatCount(Long? integer);
+ method public final Self setRepeatFrequency(androidx.appactions.builtintypes.properties.RepeatFrequency? repeatFrequency);
+ method public final Self setScheduleTimezone(String? text);
+ method public final Self setStartDate(androidx.appactions.builtintypes.properties.StartDate? startDate);
+ method public final Self setStartTime(androidx.appactions.builtintypes.properties.StartTime? startTime);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractSuccessStatus<Self extends androidx.appactions.builtintypes.types.AbstractSuccessStatus<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractSuccessStatus.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.SuccessStatus {
+ ctor public AbstractSuccessStatus(androidx.appactions.builtintypes.types.SuccessStatus successStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractSuccessStatus.Builder<Self extends androidx.appactions.builtintypes.types.AbstractSuccessStatus.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractSuccessStatus<Built, Self>> implements androidx.appactions.builtintypes.types.SuccessStatus.Builder<Self> {
+ ctor public AbstractSuccessStatus.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromSuccessStatus(androidx.appactions.builtintypes.types.SuccessStatus successStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractThing<Self extends androidx.appactions.builtintypes.types.AbstractThing<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractThing.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Thing {
+ ctor public AbstractThing(androidx.appactions.builtintypes.types.Thing thing);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractThing.Builder<Self extends androidx.appactions.builtintypes.types.AbstractThing.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractThing<Built, Self>> implements androidx.appactions.builtintypes.types.Thing.Builder<Self> {
+ ctor public AbstractThing.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromThing(androidx.appactions.builtintypes.types.Thing thing);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractTimer<Self extends androidx.appactions.builtintypes.types.AbstractTimer<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractTimer.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Timer {
+ ctor public AbstractTimer(androidx.appactions.builtintypes.types.Timer timer);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final java.time.Duration? getDuration();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final java.time.Duration? duration;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractTimer.Builder<Self extends androidx.appactions.builtintypes.types.AbstractTimer.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractTimer<Built, Self>> implements androidx.appactions.builtintypes.types.Timer.Builder<Self> {
+ ctor public AbstractTimer.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromTimer(androidx.appactions.builtintypes.types.Timer timer);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setDuration(java.time.Duration? duration);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract class AbstractUnsupportedOperationStatus<Self extends androidx.appactions.builtintypes.types.AbstractUnsupportedOperationStatus<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.AbstractUnsupportedOperationStatus.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.UnsupportedOperationStatus {
+ ctor public AbstractUnsupportedOperationStatus(androidx.appactions.builtintypes.types.UnsupportedOperationStatus unsupportedOperationStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
+ method public final String? getIdentifier();
+ method public final androidx.appactions.builtintypes.properties.Name? getName();
+ method public final String? getNamespace();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Builder toBuilder();
+ method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
+ property public final String? identifier;
+ property public final androidx.appactions.builtintypes.properties.Name? name;
+ property public final String? namespace;
+ property protected abstract String selfTypeName;
+ }
+
+ public abstract static class AbstractUnsupportedOperationStatus.Builder<Self extends androidx.appactions.builtintypes.types.AbstractUnsupportedOperationStatus.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.AbstractUnsupportedOperationStatus<Built, Self>> implements androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Builder<Self> {
+ ctor public AbstractUnsupportedOperationStatus.Builder();
+ method public final Built build();
+ method protected abstract Built buildFromUnsupportedOperationStatus(androidx.appactions.builtintypes.types.UnsupportedOperationStatus unsupportedOperationStatus);
+ method public final boolean equals(Object? other);
+ method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
+ method protected abstract String getSelfTypeName();
+ method public final int hashCode();
+ method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
+ method public final Self setIdentifier(String? text);
+ method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
+ method public final Self setNamespace(String? namespace);
+ method public final String toString();
+ property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
+ property protected abstract String selfTypeName;
+ }
+
public interface Alarm extends androidx.appactions.builtintypes.types.Thing {
method public default static androidx.appactions.builtintypes.types.Alarm.Builder<?> Builder();
method public androidx.appactions.builtintypes.types.Schedule? getAlarmSchedule();
@@ -222,267 +693,32 @@
method public default R wednesday();
}
- public abstract class GenericAlarm<Self extends androidx.appactions.builtintypes.types.GenericAlarm<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericAlarm.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Alarm {
- ctor public GenericAlarm(androidx.appactions.builtintypes.types.Alarm alarm);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final androidx.appactions.builtintypes.types.Schedule? getAlarmSchedule();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final androidx.appactions.builtintypes.types.Schedule? alarmSchedule;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property protected abstract String selfTypeName;
+ public interface ExecutionStatus extends androidx.appactions.builtintypes.types.Intangible {
+ method public default static androidx.appactions.builtintypes.types.ExecutionStatus.Builder<?> Builder();
+ method public androidx.appactions.builtintypes.types.ExecutionStatus.Builder<?> toBuilder();
+ field public static final androidx.appactions.builtintypes.types.ExecutionStatus.Companion Companion;
}
- public abstract static class GenericAlarm.Builder<Self extends androidx.appactions.builtintypes.types.GenericAlarm.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericAlarm<Built, Self>> implements androidx.appactions.builtintypes.types.Alarm.Builder<Self> {
- ctor public GenericAlarm.Builder();
- method public final Built build();
- method protected abstract Built buildFromAlarm(androidx.appactions.builtintypes.types.Alarm alarm);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setAlarmSchedule(androidx.appactions.builtintypes.types.Schedule? schedule);
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
+ public static interface ExecutionStatus.Builder<Self extends androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self>> extends androidx.appactions.builtintypes.types.Intangible.Builder<Self> {
+ method public androidx.appactions.builtintypes.types.ExecutionStatus build();
}
- public abstract class GenericIntangible<Self extends androidx.appactions.builtintypes.types.GenericIntangible<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericIntangible.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Intangible {
- ctor public GenericIntangible(androidx.appactions.builtintypes.types.Intangible intangible);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property protected abstract String selfTypeName;
+ public static final class ExecutionStatus.Companion {
+ method public androidx.appactions.builtintypes.types.ExecutionStatus.Builder<?> Builder();
}
- public abstract static class GenericIntangible.Builder<Self extends androidx.appactions.builtintypes.types.GenericIntangible.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericIntangible<Built, Self>> implements androidx.appactions.builtintypes.types.Intangible.Builder<Self> {
- ctor public GenericIntangible.Builder();
- method public final Built build();
- method protected abstract Built buildFromIntangible(androidx.appactions.builtintypes.types.Intangible intangible);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
+ public interface GenericErrorStatus extends androidx.appactions.builtintypes.types.ExecutionStatus {
+ method public default static androidx.appactions.builtintypes.types.GenericErrorStatus.Builder<?> Builder();
+ method public androidx.appactions.builtintypes.types.GenericErrorStatus.Builder<?> toBuilder();
+ field public static final androidx.appactions.builtintypes.types.GenericErrorStatus.Companion Companion;
}
- public abstract class GenericPerson<Self extends androidx.appactions.builtintypes.types.GenericPerson<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericPerson.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Person {
- ctor public GenericPerson(androidx.appactions.builtintypes.types.Person person);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final String? getEmail();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final String? email;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property protected abstract String selfTypeName;
+ public static interface GenericErrorStatus.Builder<Self extends androidx.appactions.builtintypes.types.GenericErrorStatus.Builder<Self>> extends androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self> {
+ method public androidx.appactions.builtintypes.types.GenericErrorStatus build();
}
- public abstract static class GenericPerson.Builder<Self extends androidx.appactions.builtintypes.types.GenericPerson.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericPerson<Built, Self>> implements androidx.appactions.builtintypes.types.Person.Builder<Self> {
- ctor public GenericPerson.Builder();
- method public final Built build();
- method protected abstract Built buildFromPerson(androidx.appactions.builtintypes.types.Person person);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setEmail(String? text);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
- }
-
- public abstract class GenericSchedule<Self extends androidx.appactions.builtintypes.types.GenericSchedule<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericSchedule.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Schedule {
- ctor public GenericSchedule(androidx.appactions.builtintypes.types.Schedule schedule);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final java.util.List<androidx.appactions.builtintypes.properties.ByDay> getByDays();
- method public final java.util.List<java.lang.Long> getByMonthDays();
- method public final java.util.List<java.lang.Long> getByMonthWeeks();
- method public final java.util.List<java.lang.Long> getByMonths();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final androidx.appactions.builtintypes.properties.EndDate? getEndDate();
- method public final androidx.appactions.builtintypes.properties.EndTime? getEndTime();
- method public final androidx.appactions.builtintypes.properties.ExceptDate? getExceptDate();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method public final Long? getRepeatCount();
- method public final androidx.appactions.builtintypes.properties.RepeatFrequency? getRepeatFrequency();
- method public final String? getScheduleTimezone();
- method protected abstract String getSelfTypeName();
- method public final androidx.appactions.builtintypes.properties.StartDate? getStartDate();
- method public final androidx.appactions.builtintypes.properties.StartTime? getStartTime();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final java.util.List<androidx.appactions.builtintypes.properties.ByDay> byDays;
- property public final java.util.List<java.lang.Long> byMonthDays;
- property public final java.util.List<java.lang.Long> byMonthWeeks;
- property public final java.util.List<java.lang.Long> byMonths;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final androidx.appactions.builtintypes.properties.EndDate? endDate;
- property public final androidx.appactions.builtintypes.properties.EndTime? endTime;
- property public final androidx.appactions.builtintypes.properties.ExceptDate? exceptDate;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property public final Long? repeatCount;
- property public final androidx.appactions.builtintypes.properties.RepeatFrequency? repeatFrequency;
- property public final String? scheduleTimezone;
- property protected abstract String selfTypeName;
- property public final androidx.appactions.builtintypes.properties.StartDate? startDate;
- property public final androidx.appactions.builtintypes.properties.StartTime? startTime;
- }
-
- public abstract static class GenericSchedule.Builder<Self extends androidx.appactions.builtintypes.types.GenericSchedule.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericSchedule<Built, Self>> implements androidx.appactions.builtintypes.types.Schedule.Builder<Self> {
- ctor public GenericSchedule.Builder();
- method public final Self addByDay(androidx.appactions.builtintypes.properties.ByDay byDay);
- method public final Self addByDays(Iterable<androidx.appactions.builtintypes.properties.ByDay> values);
- method public final Self addByMonth(long integer);
- method public final Self addByMonthDay(long integer);
- method public final Self addByMonthDays(Iterable<java.lang.Long> values);
- method public final Self addByMonthWeek(long integer);
- method public final Self addByMonthWeeks(Iterable<java.lang.Long> values);
- method public final Self addByMonths(Iterable<java.lang.Long> values);
- method public final Built build();
- method protected abstract Built buildFromSchedule(androidx.appactions.builtintypes.types.Schedule schedule);
- method public final Self clearByDays();
- method public final Self clearByMonthDays();
- method public final Self clearByMonthWeeks();
- method public final Self clearByMonths();
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setEndDate(androidx.appactions.builtintypes.properties.EndDate? endDate);
- method public final Self setEndTime(androidx.appactions.builtintypes.properties.EndTime? endTime);
- method public final Self setExceptDate(androidx.appactions.builtintypes.properties.ExceptDate? exceptDate);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final Self setRepeatCount(Long? integer);
- method public final Self setRepeatFrequency(androidx.appactions.builtintypes.properties.RepeatFrequency? repeatFrequency);
- method public final Self setScheduleTimezone(String? text);
- method public final Self setStartDate(androidx.appactions.builtintypes.properties.StartDate? startDate);
- method public final Self setStartTime(androidx.appactions.builtintypes.properties.StartTime? startTime);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
- }
-
- public abstract class GenericThing<Self extends androidx.appactions.builtintypes.types.GenericThing<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericThing.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Thing {
- ctor public GenericThing(androidx.appactions.builtintypes.types.Thing thing);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property protected abstract String selfTypeName;
- }
-
- public abstract static class GenericThing.Builder<Self extends androidx.appactions.builtintypes.types.GenericThing.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericThing<Built, Self>> implements androidx.appactions.builtintypes.types.Thing.Builder<Self> {
- ctor public GenericThing.Builder();
- method public final Built build();
- method protected abstract Built buildFromThing(androidx.appactions.builtintypes.types.Thing thing);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
- }
-
- public abstract class GenericTimer<Self extends androidx.appactions.builtintypes.types.GenericTimer<Self, Builder>, Builder extends androidx.appactions.builtintypes.types.GenericTimer.Builder<Builder, Self>> implements androidx.appactions.builtintypes.types.Timer {
- ctor public GenericTimer(androidx.appactions.builtintypes.types.Timer timer);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
- method public final java.time.Duration? getDuration();
- method public final String? getIdentifier();
- method public final androidx.appactions.builtintypes.properties.Name? getName();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Builder toBuilder();
- method protected abstract Builder toBuilderWithAdditionalPropertiesOnly();
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property public final androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
- property public final java.time.Duration? duration;
- property public final String? identifier;
- property public final androidx.appactions.builtintypes.properties.Name? name;
- property protected abstract String selfTypeName;
- }
-
- public abstract static class GenericTimer.Builder<Self extends androidx.appactions.builtintypes.types.GenericTimer.Builder<Self, Built>, Built extends androidx.appactions.builtintypes.types.GenericTimer<Built, Self>> implements androidx.appactions.builtintypes.types.Timer.Builder<Self> {
- ctor public GenericTimer.Builder();
- method public final Built build();
- method protected abstract Built buildFromTimer(androidx.appactions.builtintypes.types.Timer timer);
- method public final boolean equals(Object? other);
- method protected abstract java.util.Map<java.lang.String,java.lang.Object> getAdditionalProperties();
- method protected abstract String getSelfTypeName();
- method public final int hashCode();
- method public final Self setDisambiguatingDescription(androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription);
- method public final Self setDuration(java.time.Duration? duration);
- method public final Self setIdentifier(String? text);
- method public final Self setName(androidx.appactions.builtintypes.properties.Name? name);
- method public final String toString();
- property protected abstract java.util.Map<java.lang.String,java.lang.Object> additionalProperties;
- property protected abstract String selfTypeName;
+ public static final class GenericErrorStatus.Companion {
+ method public androidx.appactions.builtintypes.types.GenericErrorStatus.Builder<?> Builder();
}
public interface Intangible extends androidx.appactions.builtintypes.types.Thing {
@@ -499,6 +735,20 @@
method public androidx.appactions.builtintypes.types.Intangible.Builder<?> Builder();
}
+ public interface ObjectCreationLimitReachedStatus extends androidx.appactions.builtintypes.types.ExecutionStatus {
+ method public default static androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Builder<?> Builder();
+ method public androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Builder<?> toBuilder();
+ field public static final androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Companion Companion;
+ }
+
+ public static interface ObjectCreationLimitReachedStatus.Builder<Self extends androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Builder<Self>> extends androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self> {
+ method public androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus build();
+ }
+
+ public static final class ObjectCreationLimitReachedStatus.Companion {
+ method public androidx.appactions.builtintypes.types.ObjectCreationLimitReachedStatus.Builder<?> Builder();
+ }
+
public interface Person extends androidx.appactions.builtintypes.types.Thing {
method public default static androidx.appactions.builtintypes.types.Person.Builder<?> Builder();
method public String? getEmail();
@@ -563,45 +813,61 @@
method public Self clearByMonthWeeks();
method public Self clearByMonths();
method public Self setEndDate(androidx.appactions.builtintypes.properties.EndDate? endDate);
+ method public default Self setEndDate(java.time.Instant instant);
method public default Self setEndDate(java.time.LocalDate date);
method public default Self setEndDate(java.time.LocalDateTime localDateTime);
- method public default Self setEndDate(java.time.ZonedDateTime zonedDateTime);
method public Self setEndTime(androidx.appactions.builtintypes.properties.EndTime? endTime);
+ method public default Self setEndTime(java.time.Instant instant);
method public default Self setEndTime(java.time.LocalDateTime localDateTime);
method public default Self setEndTime(java.time.LocalTime time);
- method public default Self setEndTime(java.time.ZonedDateTime zonedDateTime);
method public Self setExceptDate(androidx.appactions.builtintypes.properties.ExceptDate? exceptDate);
+ method public default Self setExceptDate(java.time.Instant instant);
method public default Self setExceptDate(java.time.LocalDate date);
method public default Self setExceptDate(java.time.LocalDateTime localDateTime);
- method public default Self setExceptDate(java.time.ZonedDateTime zonedDateTime);
method public Self setRepeatCount(Long? integer);
method public Self setRepeatFrequency(androidx.appactions.builtintypes.properties.RepeatFrequency? repeatFrequency);
method public default Self setRepeatFrequency(String text);
method public default Self setRepeatFrequency(java.time.Duration duration);
method public Self setScheduleTimezone(String? text);
method public Self setStartDate(androidx.appactions.builtintypes.properties.StartDate? startDate);
+ method public default Self setStartDate(java.time.Instant instant);
method public default Self setStartDate(java.time.LocalDate date);
method public default Self setStartDate(java.time.LocalDateTime localDateTime);
- method public default Self setStartDate(java.time.ZonedDateTime zonedDateTime);
method public Self setStartTime(androidx.appactions.builtintypes.properties.StartTime? startTime);
+ method public default Self setStartTime(java.time.Instant instant);
method public default Self setStartTime(java.time.LocalDateTime localDateTime);
method public default Self setStartTime(java.time.LocalTime time);
- method public default Self setStartTime(java.time.ZonedDateTime zonedDateTime);
}
public static final class Schedule.Companion {
method public androidx.appactions.builtintypes.types.Schedule.Builder<?> Builder();
}
+ public interface SuccessStatus extends androidx.appactions.builtintypes.types.ExecutionStatus {
+ method public default static androidx.appactions.builtintypes.types.SuccessStatus.Builder<?> Builder();
+ method public androidx.appactions.builtintypes.types.SuccessStatus.Builder<?> toBuilder();
+ field public static final androidx.appactions.builtintypes.types.SuccessStatus.Companion Companion;
+ }
+
+ public static interface SuccessStatus.Builder<Self extends androidx.appactions.builtintypes.types.SuccessStatus.Builder<Self>> extends androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self> {
+ method public androidx.appactions.builtintypes.types.SuccessStatus build();
+ }
+
+ public static final class SuccessStatus.Companion {
+ method public androidx.appactions.builtintypes.types.SuccessStatus.Builder<?> Builder();
+ }
+
public interface Thing {
method public default static androidx.appactions.builtintypes.types.Thing.Builder<?> Builder();
method public androidx.appactions.builtintypes.properties.DisambiguatingDescription? getDisambiguatingDescription();
method public String? getIdentifier();
method public androidx.appactions.builtintypes.properties.Name? getName();
+ method public String? getNamespace();
method public androidx.appactions.builtintypes.types.Thing.Builder<?> toBuilder();
property public abstract androidx.appactions.builtintypes.properties.DisambiguatingDescription? disambiguatingDescription;
property public abstract String? identifier;
property public abstract androidx.appactions.builtintypes.properties.Name? name;
+ property public abstract String? namespace;
field public static final androidx.appactions.builtintypes.types.Thing.Companion Companion;
}
@@ -612,6 +878,7 @@
method public Self setIdentifier(String? text);
method public Self setName(androidx.appactions.builtintypes.properties.Name? name);
method public default Self setName(String text);
+ method public Self setNamespace(String? namespace);
}
public static final class Thing.Companion {
@@ -635,5 +902,19 @@
method public androidx.appactions.builtintypes.types.Timer.Builder<?> Builder();
}
+ public interface UnsupportedOperationStatus extends androidx.appactions.builtintypes.types.ExecutionStatus {
+ method public default static androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Builder<?> Builder();
+ method public androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Builder<?> toBuilder();
+ field public static final androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Companion Companion;
+ }
+
+ public static interface UnsupportedOperationStatus.Builder<Self extends androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Builder<Self>> extends androidx.appactions.builtintypes.types.ExecutionStatus.Builder<Self> {
+ method public androidx.appactions.builtintypes.types.UnsupportedOperationStatus build();
+ }
+
+ public static final class UnsupportedOperationStatus.Companion {
+ method public androidx.appactions.builtintypes.types.UnsupportedOperationStatus.Builder<?> Builder();
+ }
+
}
diff --git a/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/EndDateSamples.kt b/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/EndDateSamples.kt
index 51f745e..29c118e 100644
--- a/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/EndDateSamples.kt
+++ b/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/EndDateSamples.kt
@@ -15,9 +15,9 @@
import androidx.`annotation`.Sampled
import androidx.appactions.builtintypes.properties.EndDate
+import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
-import java.time.ZonedDateTime
import kotlin.String
@Sampled
@@ -29,8 +29,8 @@
public override fun localDateTime(instance: LocalDateTime): String =
"""Got a local DateTime: $instance"""
- public override fun zonedDateTime(instance: ZonedDateTime): String =
- """Got a zoned/absolute DateTime: $instance"""
+ public override fun instant(instance: Instant): String =
+ """Got an absolute DateTime: $instance"""
public override fun orElse(): String = """Got some unrecognized variant: $endDate"""
}
diff --git a/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/EndTimeSamples.kt b/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/EndTimeSamples.kt
index 6094ef9..2edf7d6 100644
--- a/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/EndTimeSamples.kt
+++ b/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/EndTimeSamples.kt
@@ -15,9 +15,9 @@
import androidx.`annotation`.Sampled
import androidx.appactions.builtintypes.properties.EndTime
+import java.time.Instant
import java.time.LocalDateTime
import java.time.LocalTime
-import java.time.ZonedDateTime
import kotlin.String
@Sampled
@@ -29,8 +29,8 @@
public override fun localDateTime(instance: LocalDateTime): String =
"""Got a local DateTime: $instance"""
- public override fun zonedDateTime(instance: ZonedDateTime): String =
- """Got a zoned/absolute DateTime: $instance"""
+ public override fun instant(instance: Instant): String =
+ """Got an absolute DateTime: $instance"""
public override fun orElse(): String = """Got some unrecognized variant: $endTime"""
}
diff --git a/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/ExceptDateSamples.kt b/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/ExceptDateSamples.kt
index 980a3df..ea20d43 100644
--- a/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/ExceptDateSamples.kt
+++ b/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/ExceptDateSamples.kt
@@ -15,9 +15,9 @@
import androidx.`annotation`.Sampled
import androidx.appactions.builtintypes.properties.ExceptDate
+import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
-import java.time.ZonedDateTime
import kotlin.String
@Sampled
@@ -29,8 +29,8 @@
public override fun localDateTime(instance: LocalDateTime): String =
"""Got a local DateTime: $instance"""
- public override fun zonedDateTime(instance: ZonedDateTime): String =
- """Got a zoned/absolute DateTime: $instance"""
+ public override fun instant(instance: Instant): String =
+ """Got an absolute DateTime: $instance"""
public override fun orElse(): String = """Got some unrecognized variant: $exceptDate"""
}
diff --git a/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/StartDateSamples.kt b/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/StartDateSamples.kt
index 60772b6..8dabc29 100644
--- a/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/StartDateSamples.kt
+++ b/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/StartDateSamples.kt
@@ -15,9 +15,9 @@
import androidx.`annotation`.Sampled
import androidx.appactions.builtintypes.properties.StartDate
+import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
-import java.time.ZonedDateTime
import kotlin.String
@Sampled
@@ -29,8 +29,8 @@
public override fun localDateTime(instance: LocalDateTime): String =
"""Got a local DateTime: $instance"""
- public override fun zonedDateTime(instance: ZonedDateTime): String =
- """Got a zoned/absolute DateTime: $instance"""
+ public override fun instant(instance: Instant): String =
+ """Got an absolute DateTime: $instance"""
public override fun orElse(): String = """Got some unrecognized variant: $startDate"""
}
diff --git a/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/StartTimeSamples.kt b/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/StartTimeSamples.kt
index b110553..873313e 100644
--- a/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/StartTimeSamples.kt
+++ b/appactions/builtintypes/builtintypes-core/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/StartTimeSamples.kt
@@ -15,9 +15,9 @@
import androidx.`annotation`.Sampled
import androidx.appactions.builtintypes.properties.StartTime
+import java.time.Instant
import java.time.LocalDateTime
import java.time.LocalTime
-import java.time.ZonedDateTime
import kotlin.String
@Sampled
@@ -29,8 +29,8 @@
public override fun localDateTime(instance: LocalDateTime): String =
"""Got a local DateTime: $instance"""
- public override fun zonedDateTime(instance: ZonedDateTime): String =
- """Got a zoned/absolute DateTime: $instance"""
+ public override fun instant(instance: Instant): String =
+ """Got an absolute DateTime: $instance"""
public override fun orElse(): String = """Got some unrecognized variant: $startTime"""
}
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/EndDate.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/EndDate.kt
index 785b1e6..b795c26 100644
--- a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/EndDate.kt
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/EndDate.kt
@@ -13,9 +13,9 @@
// limitations under the License.
package androidx.appactions.builtintypes.properties
+import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
-import java.time.ZonedDateTime
import java.util.Objects
import kotlin.Any
import kotlin.Boolean
@@ -32,7 +32,7 @@
* Holds one of:
* * Date i.e. [LocalDate]
* * [LocalDateTime]
- * * [ZonedDateTime]
+ * * [Instant]
*
* May hold more types over time.
*/
@@ -42,8 +42,8 @@
@get:JvmName("asDate") public val asDate: LocalDate? = null,
/** The [LocalDateTime] variant, or null if constructed using a different variant. */
@get:JvmName("asLocalDateTime") public val asLocalDateTime: LocalDateTime? = null,
- /** The [ZonedDateTime] variant, or null if constructed using a different variant. */
- @get:JvmName("asZonedDateTime") public val asZonedDateTime: ZonedDateTime? = null,
+ /** The [Instant] variant, or null if constructed using a different variant. */
+ @get:JvmName("asInstant") public val asInstant: Instant? = null,
/**
* The AppSearch document's identifier.
*
@@ -58,8 +58,8 @@
/** Constructor for the [LocalDateTime] variant. */
public constructor(localDateTime: LocalDateTime) : this(asLocalDateTime = localDateTime)
- /** Constructor for the [ZonedDateTime] variant. */
- public constructor(zonedDateTime: ZonedDateTime) : this(asZonedDateTime = zonedDateTime)
+ /** Constructor for the [Instant] variant. */
+ public constructor(instant: Instant) : this(asInstant = instant)
/**
* Maps each of the possible underlying variants to some [R].
@@ -73,7 +73,7 @@
when {
asDate != null -> mapper.date(asDate)
asLocalDateTime != null -> mapper.localDateTime(asLocalDateTime)
- asZonedDateTime != null -> mapper.zonedDateTime(asZonedDateTime)
+ asInstant != null -> mapper.instant(asInstant)
else -> error("No variant present in EndDate")
}
@@ -93,11 +93,11 @@
} else {
asLocalDateTime.toString()
}
- asZonedDateTime != null ->
+ asInstant != null ->
if (includeWrapperName) {
- """EndDate($asZonedDateTime)"""
+ """EndDate($asInstant)"""
} else {
- asZonedDateTime.toString()
+ asInstant.toString()
}
else -> error("No variant present in EndDate")
}
@@ -107,11 +107,11 @@
if (other !is EndDate) return false
if (asDate != other.asDate) return false
if (asLocalDateTime != other.asLocalDateTime) return false
- if (asZonedDateTime != other.asZonedDateTime) return false
+ if (asInstant != other.asInstant) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asDate, asLocalDateTime, asZonedDateTime)
+ public override fun hashCode(): Int = Objects.hash(asDate, asLocalDateTime, asInstant)
/** Maps each of the possible variants of [EndDate] to some [R]. */
public interface Mapper<R> {
@@ -121,8 +121,8 @@
/** Returns some [R] when the [EndDate] holds some [LocalDateTime] instance. */
public fun localDateTime(instance: LocalDateTime): R = orElse()
- /** Returns some [R] when the [EndDate] holds some [ZonedDateTime] instance. */
- public fun zonedDateTime(instance: ZonedDateTime): R = orElse()
+ /** Returns some [R] when the [EndDate] holds some [Instant] instance. */
+ public fun instant(instance: Instant): R = orElse()
/** The catch-all handler that is invoked when a particular variant isn't explicitly handled. */
public fun orElse(): R
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/EndTime.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/EndTime.kt
index a2b3b28..2785f5b 100644
--- a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/EndTime.kt
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/EndTime.kt
@@ -13,9 +13,9 @@
// limitations under the License.
package androidx.appactions.builtintypes.properties
+import java.time.Instant
import java.time.LocalDateTime
import java.time.LocalTime
-import java.time.ZonedDateTime
import java.util.Objects
import kotlin.Any
import kotlin.Boolean
@@ -37,7 +37,7 @@
* Holds one of:
* * Time i.e. [LocalTime]
* * [LocalDateTime]
- * * [ZonedDateTime]
+ * * [Instant]
*
* May hold more types over time.
*/
@@ -47,8 +47,8 @@
@get:JvmName("asTime") public val asTime: LocalTime? = null,
/** The [LocalDateTime] variant, or null if constructed using a different variant. */
@get:JvmName("asLocalDateTime") public val asLocalDateTime: LocalDateTime? = null,
- /** The [ZonedDateTime] variant, or null if constructed using a different variant. */
- @get:JvmName("asZonedDateTime") public val asZonedDateTime: ZonedDateTime? = null,
+ /** The [Instant] variant, or null if constructed using a different variant. */
+ @get:JvmName("asInstant") public val asInstant: Instant? = null,
/**
* The AppSearch document's identifier.
*
@@ -63,8 +63,8 @@
/** Constructor for the [LocalDateTime] variant. */
public constructor(localDateTime: LocalDateTime) : this(asLocalDateTime = localDateTime)
- /** Constructor for the [ZonedDateTime] variant. */
- public constructor(zonedDateTime: ZonedDateTime) : this(asZonedDateTime = zonedDateTime)
+ /** Constructor for the [Instant] variant. */
+ public constructor(instant: Instant) : this(asInstant = instant)
/**
* Maps each of the possible underlying variants to some [R].
@@ -78,7 +78,7 @@
when {
asTime != null -> mapper.time(asTime)
asLocalDateTime != null -> mapper.localDateTime(asLocalDateTime)
- asZonedDateTime != null -> mapper.zonedDateTime(asZonedDateTime)
+ asInstant != null -> mapper.instant(asInstant)
else -> error("No variant present in EndTime")
}
@@ -98,11 +98,11 @@
} else {
asLocalDateTime.toString()
}
- asZonedDateTime != null ->
+ asInstant != null ->
if (includeWrapperName) {
- """EndTime($asZonedDateTime)"""
+ """EndTime($asInstant)"""
} else {
- asZonedDateTime.toString()
+ asInstant.toString()
}
else -> error("No variant present in EndTime")
}
@@ -112,11 +112,11 @@
if (other !is EndTime) return false
if (asTime != other.asTime) return false
if (asLocalDateTime != other.asLocalDateTime) return false
- if (asZonedDateTime != other.asZonedDateTime) return false
+ if (asInstant != other.asInstant) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asTime, asLocalDateTime, asZonedDateTime)
+ public override fun hashCode(): Int = Objects.hash(asTime, asLocalDateTime, asInstant)
/** Maps each of the possible variants of [EndTime] to some [R]. */
public interface Mapper<R> {
@@ -126,8 +126,8 @@
/** Returns some [R] when the [EndTime] holds some [LocalDateTime] instance. */
public fun localDateTime(instance: LocalDateTime): R = orElse()
- /** Returns some [R] when the [EndTime] holds some [ZonedDateTime] instance. */
- public fun zonedDateTime(instance: ZonedDateTime): R = orElse()
+ /** Returns some [R] when the [EndTime] holds some [Instant] instance. */
+ public fun instant(instance: Instant): R = orElse()
/** The catch-all handler that is invoked when a particular variant isn't explicitly handled. */
public fun orElse(): R
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/ExceptDate.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/ExceptDate.kt
index ae356b4..c0dd8a3 100644
--- a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/ExceptDate.kt
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/ExceptDate.kt
@@ -13,9 +13,9 @@
// limitations under the License.
package androidx.appactions.builtintypes.properties
+import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
-import java.time.ZonedDateTime
import java.util.Objects
import kotlin.Any
import kotlin.Boolean
@@ -37,7 +37,7 @@
* Holds one of:
* * Date i.e. [LocalDate]
* * [LocalDateTime]
- * * [ZonedDateTime]
+ * * [Instant]
*
* May hold more types over time.
*/
@@ -47,8 +47,8 @@
@get:JvmName("asDate") public val asDate: LocalDate? = null,
/** The [LocalDateTime] variant, or null if constructed using a different variant. */
@get:JvmName("asLocalDateTime") public val asLocalDateTime: LocalDateTime? = null,
- /** The [ZonedDateTime] variant, or null if constructed using a different variant. */
- @get:JvmName("asZonedDateTime") public val asZonedDateTime: ZonedDateTime? = null,
+ /** The [Instant] variant, or null if constructed using a different variant. */
+ @get:JvmName("asInstant") public val asInstant: Instant? = null,
/**
* The AppSearch document's identifier.
*
@@ -63,8 +63,8 @@
/** Constructor for the [LocalDateTime] variant. */
public constructor(localDateTime: LocalDateTime) : this(asLocalDateTime = localDateTime)
- /** Constructor for the [ZonedDateTime] variant. */
- public constructor(zonedDateTime: ZonedDateTime) : this(asZonedDateTime = zonedDateTime)
+ /** Constructor for the [Instant] variant. */
+ public constructor(instant: Instant) : this(asInstant = instant)
/**
* Maps each of the possible underlying variants to some [R].
@@ -78,7 +78,7 @@
when {
asDate != null -> mapper.date(asDate)
asLocalDateTime != null -> mapper.localDateTime(asLocalDateTime)
- asZonedDateTime != null -> mapper.zonedDateTime(asZonedDateTime)
+ asInstant != null -> mapper.instant(asInstant)
else -> error("No variant present in ExceptDate")
}
@@ -98,11 +98,11 @@
} else {
asLocalDateTime.toString()
}
- asZonedDateTime != null ->
+ asInstant != null ->
if (includeWrapperName) {
- """ExceptDate($asZonedDateTime)"""
+ """ExceptDate($asInstant)"""
} else {
- asZonedDateTime.toString()
+ asInstant.toString()
}
else -> error("No variant present in ExceptDate")
}
@@ -112,11 +112,11 @@
if (other !is ExceptDate) return false
if (asDate != other.asDate) return false
if (asLocalDateTime != other.asLocalDateTime) return false
- if (asZonedDateTime != other.asZonedDateTime) return false
+ if (asInstant != other.asInstant) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asDate, asLocalDateTime, asZonedDateTime)
+ public override fun hashCode(): Int = Objects.hash(asDate, asLocalDateTime, asInstant)
/** Maps each of the possible variants of [ExceptDate] to some [R]. */
public interface Mapper<R> {
@@ -126,8 +126,8 @@
/** Returns some [R] when the [ExceptDate] holds some [LocalDateTime] instance. */
public fun localDateTime(instance: LocalDateTime): R = orElse()
- /** Returns some [R] when the [ExceptDate] holds some [ZonedDateTime] instance. */
- public fun zonedDateTime(instance: ZonedDateTime): R = orElse()
+ /** Returns some [R] when the [ExceptDate] holds some [Instant] instance. */
+ public fun instant(instance: Instant): R = orElse()
/** The catch-all handler that is invoked when a particular variant isn't explicitly handled. */
public fun orElse(): R
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/StartDate.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/StartDate.kt
index 756b162e..4eaedc3 100644
--- a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/StartDate.kt
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/StartDate.kt
@@ -13,9 +13,9 @@
// limitations under the License.
package androidx.appactions.builtintypes.properties
+import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
-import java.time.ZonedDateTime
import java.util.Objects
import kotlin.Any
import kotlin.Boolean
@@ -32,7 +32,7 @@
* Holds one of:
* * Date i.e. [LocalDate]
* * [LocalDateTime]
- * * [ZonedDateTime]
+ * * [Instant]
*
* May hold more types over time.
*/
@@ -42,8 +42,8 @@
@get:JvmName("asDate") public val asDate: LocalDate? = null,
/** The [LocalDateTime] variant, or null if constructed using a different variant. */
@get:JvmName("asLocalDateTime") public val asLocalDateTime: LocalDateTime? = null,
- /** The [ZonedDateTime] variant, or null if constructed using a different variant. */
- @get:JvmName("asZonedDateTime") public val asZonedDateTime: ZonedDateTime? = null,
+ /** The [Instant] variant, or null if constructed using a different variant. */
+ @get:JvmName("asInstant") public val asInstant: Instant? = null,
/**
* The AppSearch document's identifier.
*
@@ -58,8 +58,8 @@
/** Constructor for the [LocalDateTime] variant. */
public constructor(localDateTime: LocalDateTime) : this(asLocalDateTime = localDateTime)
- /** Constructor for the [ZonedDateTime] variant. */
- public constructor(zonedDateTime: ZonedDateTime) : this(asZonedDateTime = zonedDateTime)
+ /** Constructor for the [Instant] variant. */
+ public constructor(instant: Instant) : this(asInstant = instant)
/**
* Maps each of the possible underlying variants to some [R].
@@ -73,7 +73,7 @@
when {
asDate != null -> mapper.date(asDate)
asLocalDateTime != null -> mapper.localDateTime(asLocalDateTime)
- asZonedDateTime != null -> mapper.zonedDateTime(asZonedDateTime)
+ asInstant != null -> mapper.instant(asInstant)
else -> error("No variant present in StartDate")
}
@@ -93,11 +93,11 @@
} else {
asLocalDateTime.toString()
}
- asZonedDateTime != null ->
+ asInstant != null ->
if (includeWrapperName) {
- """StartDate($asZonedDateTime)"""
+ """StartDate($asInstant)"""
} else {
- asZonedDateTime.toString()
+ asInstant.toString()
}
else -> error("No variant present in StartDate")
}
@@ -107,11 +107,11 @@
if (other !is StartDate) return false
if (asDate != other.asDate) return false
if (asLocalDateTime != other.asLocalDateTime) return false
- if (asZonedDateTime != other.asZonedDateTime) return false
+ if (asInstant != other.asInstant) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asDate, asLocalDateTime, asZonedDateTime)
+ public override fun hashCode(): Int = Objects.hash(asDate, asLocalDateTime, asInstant)
/** Maps each of the possible variants of [StartDate] to some [R]. */
public interface Mapper<R> {
@@ -121,8 +121,8 @@
/** Returns some [R] when the [StartDate] holds some [LocalDateTime] instance. */
public fun localDateTime(instance: LocalDateTime): R = orElse()
- /** Returns some [R] when the [StartDate] holds some [ZonedDateTime] instance. */
- public fun zonedDateTime(instance: ZonedDateTime): R = orElse()
+ /** Returns some [R] when the [StartDate] holds some [Instant] instance. */
+ public fun instant(instance: Instant): R = orElse()
/** The catch-all handler that is invoked when a particular variant isn't explicitly handled. */
public fun orElse(): R
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/StartTime.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/StartTime.kt
index 8105722..bb0ce0c 100644
--- a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/StartTime.kt
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/properties/StartTime.kt
@@ -13,9 +13,9 @@
// limitations under the License.
package androidx.appactions.builtintypes.properties
+import java.time.Instant
import java.time.LocalDateTime
import java.time.LocalTime
-import java.time.ZonedDateTime
import java.util.Objects
import kotlin.Any
import kotlin.Boolean
@@ -37,7 +37,7 @@
* Holds one of:
* * Time i.e. [LocalTime]
* * [LocalDateTime]
- * * [ZonedDateTime]
+ * * [Instant]
*
* May hold more types over time.
*/
@@ -47,8 +47,8 @@
@get:JvmName("asTime") public val asTime: LocalTime? = null,
/** The [LocalDateTime] variant, or null if constructed using a different variant. */
@get:JvmName("asLocalDateTime") public val asLocalDateTime: LocalDateTime? = null,
- /** The [ZonedDateTime] variant, or null if constructed using a different variant. */
- @get:JvmName("asZonedDateTime") public val asZonedDateTime: ZonedDateTime? = null,
+ /** The [Instant] variant, or null if constructed using a different variant. */
+ @get:JvmName("asInstant") public val asInstant: Instant? = null,
/**
* The AppSearch document's identifier.
*
@@ -63,8 +63,8 @@
/** Constructor for the [LocalDateTime] variant. */
public constructor(localDateTime: LocalDateTime) : this(asLocalDateTime = localDateTime)
- /** Constructor for the [ZonedDateTime] variant. */
- public constructor(zonedDateTime: ZonedDateTime) : this(asZonedDateTime = zonedDateTime)
+ /** Constructor for the [Instant] variant. */
+ public constructor(instant: Instant) : this(asInstant = instant)
/**
* Maps each of the possible underlying variants to some [R].
@@ -78,7 +78,7 @@
when {
asTime != null -> mapper.time(asTime)
asLocalDateTime != null -> mapper.localDateTime(asLocalDateTime)
- asZonedDateTime != null -> mapper.zonedDateTime(asZonedDateTime)
+ asInstant != null -> mapper.instant(asInstant)
else -> error("No variant present in StartTime")
}
@@ -98,11 +98,11 @@
} else {
asLocalDateTime.toString()
}
- asZonedDateTime != null ->
+ asInstant != null ->
if (includeWrapperName) {
- """StartTime($asZonedDateTime)"""
+ """StartTime($asInstant)"""
} else {
- asZonedDateTime.toString()
+ asInstant.toString()
}
else -> error("No variant present in StartTime")
}
@@ -112,11 +112,11 @@
if (other !is StartTime) return false
if (asTime != other.asTime) return false
if (asLocalDateTime != other.asLocalDateTime) return false
- if (asZonedDateTime != other.asZonedDateTime) return false
+ if (asInstant != other.asInstant) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asTime, asLocalDateTime, asZonedDateTime)
+ public override fun hashCode(): Int = Objects.hash(asTime, asLocalDateTime, asInstant)
/** Maps each of the possible variants of [StartTime] to some [R]. */
public interface Mapper<R> {
@@ -126,8 +126,8 @@
/** Returns some [R] when the [StartTime] holds some [LocalDateTime] instance. */
public fun localDateTime(instance: LocalDateTime): R = orElse()
- /** Returns some [R] when the [StartTime] holds some [ZonedDateTime] instance. */
- public fun zonedDateTime(instance: ZonedDateTime): R = orElse()
+ /** Returns some [R] when the [StartTime] holds some [Instant] instance. */
+ public fun instant(instance: Instant): R = orElse()
/** The catch-all handler that is invoked when a particular variant isn't explicitly handled. */
public fun orElse(): R
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Alarm.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Alarm.kt
index fff77c1..a7fc228 100644
--- a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Alarm.kt
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Alarm.kt
@@ -36,10 +36,14 @@
* See http://schema.googleapis.com/Alarm for context.
*
* Should not be directly implemented. More properties may be added over time. Instead consider
- * using [Companion.Builder] or see [GenericAlarm] if you need to extend this type.
+ * using [Companion.Builder] or see [AbstractAlarm] if you need to extend this type.
*/
public interface Alarm : Thing {
- /** Associates an Alarm with a Schedule. */
+ /**
+ * Associates an Alarm with a Schedule.
+ *
+ * See http://schema.googleapis.com/alarmSchedule for more context.
+ */
public val alarmSchedule: Schedule?
/** Converts this [Alarm] to its builder with all the properties copied over. */
@@ -54,7 +58,7 @@
* Builder for [Alarm].
*
* Should not be directly implemented. More methods may be added over time. See
- * [GenericAlarm.Builder] if you need to extend this builder.
+ * [AbstractAlarm.Builder] if you need to extend this builder.
*/
public interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
/** Returns a built [Alarm]. */
@@ -90,7 +94,7 @@
}
/**
- * A generic implementation of [Alarm].
+ * An abstract implementation of [Alarm].
*
* Allows for extension like:
* ```kt
@@ -98,7 +102,7 @@
* alarm: Alarm,
* val foo: String,
* val bars: List<Int>,
- * ) : GenericAlarm<
+ * ) : AbstractAlarm<
* MyAlarm,
* MyAlarm.Builder
* >(alarm) {
@@ -116,18 +120,19 @@
* }
*
* class Builder :
- * GenericAlarm.Builder<
+ * AbstractAlarm.Builder<
* Builder,
* MyAlarm> {...}
* }
* ```
*
- * Also see [GenericAlarm.Builder].
+ * Also see [AbstractAlarm.Builder].
*/
@Suppress("UNCHECKED_CAST")
-public abstract class GenericAlarm<
- Self : GenericAlarm<Self, Builder>, Builder : GenericAlarm.Builder<Builder, Self>>
+public abstract class AbstractAlarm<
+ Self : AbstractAlarm<Self, Builder>, Builder : AbstractAlarm.Builder<Builder, Self>>
internal constructor(
+ public final override val namespace: String?,
public final override val alarmSchedule: Schedule?,
public final override val disambiguatingDescription: DisambiguatingDescription?,
public final override val identifier: String?,
@@ -150,13 +155,20 @@
/** A copy-constructor that copies over properties from another [Alarm] instance. */
public constructor(
alarm: Alarm
- ) : this(alarm.alarmSchedule, alarm.disambiguatingDescription, alarm.identifier, alarm.name)
+ ) : this(
+ alarm.namespace,
+ alarm.alarmSchedule,
+ alarm.disambiguatingDescription,
+ alarm.identifier,
+ alarm.name
+ )
/** Returns a concrete [Builder] with the additional, non-[Alarm] properties copied over. */
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
public final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
+ .setNamespace(namespace)
.setAlarmSchedule(alarmSchedule)
.setDisambiguatingDescription(disambiguatingDescription)
.setIdentifier(identifier)
@@ -170,15 +182,26 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
public final override fun hashCode(): Int =
- Objects.hash(alarmSchedule, disambiguatingDescription, identifier, name, additionalProperties)
+ Objects.hash(
+ alarmSchedule,
+ disambiguatingDescription,
+ identifier,
+ name,
+ namespace,
+ additionalProperties
+ )
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace
+ }
if (alarmSchedule != null) {
attributes["alarmSchedule"] = alarmSchedule.toString()
}
@@ -198,12 +221,12 @@
}
/**
- * A generic implementation of [Alarm.Builder].
+ * An abstract implementation of [Alarm.Builder].
*
* Allows for extension like:
* ```kt
* class MyAlarm :
- * : GenericAlarm<
+ * : AbstractAlarm<
* MyAlarm,
* MyAlarm.Builder>(...) {
*
@@ -246,10 +269,10 @@
* }
* ```
*
- * Also see [GenericAlarm].
+ * Also see [AbstractAlarm].
*/
@Suppress("StaticFinalBuilder")
- public abstract class Builder<Self : Builder<Self, Built>, Built : GenericAlarm<Built, Self>> :
+ public abstract class Builder<Self : Builder<Self, Built>, Built : AbstractAlarm<Built, Self>> :
Alarm.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
@@ -265,6 +288,8 @@
*/
@get:Suppress("GetterOnBuilder") protected abstract val additionalProperties: Map<String, Any?>
+ private var namespace: String? = null
+
private var alarmSchedule: Schedule? = null
private var disambiguatingDescription: DisambiguatingDescription? = null
@@ -284,7 +309,20 @@
@Suppress("BuilderSetStyle") protected abstract fun buildFromAlarm(alarm: Alarm): Built
public final override fun build(): Built =
- buildFromAlarm(AlarmImpl(alarmSchedule, disambiguatingDescription, identifier, name))
+ buildFromAlarm(
+ AlarmImpl(
+ namespace,
+ alarmSchedule,
+ disambiguatingDescription,
+ identifier,
+ name
+ )
+ )
+
+ public final override fun setNamespace(namespace: String?): Self {
+ this.namespace = namespace
+ return this as Self
+ }
public final override fun setAlarmSchedule(schedule: Schedule?): Self {
this.alarmSchedule = schedule
@@ -317,17 +355,28 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
@Suppress("BuilderSetStyle")
public final override fun hashCode(): Int =
- Objects.hash(alarmSchedule, disambiguatingDescription, identifier, name, additionalProperties)
+ Objects.hash(
+ alarmSchedule,
+ disambiguatingDescription,
+ identifier,
+ name,
+ namespace,
+ additionalProperties
+ )
@Suppress("BuilderSetStyle")
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace!!
+ }
if (alarmSchedule != null) {
attributes["alarmSchedule"] = alarmSchedule!!.toString()
}
@@ -349,7 +398,7 @@
}
}
-internal class AlarmImpl : GenericAlarm<AlarmImpl, AlarmImpl.Builder> {
+private class AlarmImpl : AbstractAlarm<AlarmImpl, AlarmImpl.Builder> {
protected override val selfTypeName: String
get() = "Alarm"
@@ -357,17 +406,18 @@
get() = emptyMap()
public constructor(
+ namespace: String?,
alarmSchedule: Schedule?,
disambiguatingDescription: DisambiguatingDescription?,
identifier: String?,
name: Name?,
- ) : super(alarmSchedule, disambiguatingDescription, identifier, name)
+ ) : super(namespace, alarmSchedule, disambiguatingDescription, identifier, name)
public constructor(alarm: Alarm) : super(alarm)
protected override fun toBuilderWithAdditionalPropertiesOnly(): Builder = Builder()
- internal class Builder : GenericAlarm.Builder<Builder, AlarmImpl>() {
+ public class Builder : AbstractAlarm.Builder<Builder, AlarmImpl>() {
protected override val selfTypeName: String
get() = "Alarm.Builder"
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/ExecutionStatus.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/ExecutionStatus.kt
new file mode 100644
index 0000000..2ead4f6
--- /dev/null
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/ExecutionStatus.kt
@@ -0,0 +1,364 @@
+// 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.appactions.builtintypes.types
+
+import androidx.appactions.builtintypes.properties.DisambiguatingDescription
+import androidx.appactions.builtintypes.properties.Name
+import java.util.Objects
+import kotlin.Any
+import kotlin.Boolean
+import kotlin.Int
+import kotlin.String
+import kotlin.Suppress
+import kotlin.collections.Map
+import kotlin.collections.emptyMap
+import kotlin.collections.joinToString
+import kotlin.collections.map
+import kotlin.collections.mutableMapOf
+import kotlin.collections.plusAssign
+import kotlin.jvm.JvmStatic
+
+/**
+ * Status of a task that was pending execution.
+ *
+ * See http://schema.googleapis.com/ExecutionStatus for context.
+ *
+ * Should not be directly implemented. More properties may be added over time. Instead consider
+ * using [Companion.Builder] or see [AbstractExecutionStatus] if you need to extend this type.
+ */
+public interface ExecutionStatus : Intangible {
+ /** Converts this [ExecutionStatus] to its builder with all the properties copied over. */
+ public override fun toBuilder(): Builder<*>
+
+ public companion object {
+ /** Returns a default implementation of [Builder] with no properties set. */
+ @JvmStatic public fun Builder(): Builder<*> = ExecutionStatusImpl.Builder()
+ }
+
+ /**
+ * Builder for [ExecutionStatus].
+ *
+ * Should not be directly implemented. More methods may be added over time. See
+ * [AbstractExecutionStatus.Builder] if you need to extend this builder.
+ */
+ public interface Builder<Self : Builder<Self>> : Intangible.Builder<Self> {
+ /** Returns a built [ExecutionStatus]. */
+ public override fun build(): ExecutionStatus
+ }
+}
+
+/**
+ * An abstract implementation of [ExecutionStatus].
+ *
+ * Allows for extension like:
+ * ```kt
+ * class MyExecutionStatus internal constructor(
+ * executionStatus: ExecutionStatus,
+ * val foo: String,
+ * val bars: List<Int>,
+ * ) : AbstractExecutionStatus<
+ * MyExecutionStatus,
+ * MyExecutionStatus.Builder
+ * >(executionStatus) {
+ *
+ * override val selfTypeName =
+ * "MyExecutionStatus"
+ *
+ * override val additionalProperties: Map<String, Any?>
+ * get() = mapOf("foo" to foo, "bars" to bars)
+ *
+ * override fun toBuilderWithAdditionalPropertiesOnly(): Builder {
+ * return Builder()
+ * .setFoo(foo)
+ * .addBars(bars)
+ * }
+ *
+ * class Builder :
+ * AbstractExecutionStatus.Builder<
+ * Builder,
+ * MyExecutionStatus> {...}
+ * }
+ * ```
+ *
+ * Also see [AbstractExecutionStatus.Builder].
+ */
+@Suppress("UNCHECKED_CAST")
+public abstract class AbstractExecutionStatus<
+ Self : AbstractExecutionStatus<Self, Builder>,
+ Builder : AbstractExecutionStatus.Builder<Builder, Self>>
+internal constructor(
+ public final override val namespace: String?,
+ public final override val disambiguatingDescription: DisambiguatingDescription?,
+ public final override val identifier: String?,
+ public final override val name: Name?,
+) : ExecutionStatus {
+ /**
+ * Human readable name for the concrete [Self] class.
+ *
+ * Used in the [toString] output.
+ */
+ protected abstract val selfTypeName: String
+
+ /**
+ * The additional properties that exist on the concrete [Self] class.
+ *
+ * Used for equality comparison and computing the hash code.
+ */
+ protected abstract val additionalProperties: Map<String, Any?>
+
+ /** A copy-constructor that copies over properties from another [ExecutionStatus] instance. */
+ public constructor(
+ executionStatus: ExecutionStatus
+ ) : this(
+ executionStatus.namespace,
+ executionStatus.disambiguatingDescription,
+ executionStatus.identifier,
+ executionStatus.name
+ )
+
+ /**
+ * Returns a concrete [Builder] with the additional, non-[ExecutionStatus] properties copied over.
+ */
+ protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
+
+ public final override fun toBuilder(): Builder =
+ toBuilderWithAdditionalPropertiesOnly()
+ .setNamespace(namespace)
+ .setDisambiguatingDescription(disambiguatingDescription)
+ .setIdentifier(identifier)
+ .setName(name)
+
+ public final override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class.java != other::class.java) return false
+ other as Self
+ if (disambiguatingDescription != other.disambiguatingDescription) return false
+ if (identifier != other.identifier) return false
+ if (name != other.name) return false
+ if (namespace != other.namespace) return false
+ if (additionalProperties != other.additionalProperties) return false
+ return true
+ }
+
+ public final override fun hashCode(): Int =
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
+
+ public final override fun toString(): String {
+ val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace
+ }
+ if (disambiguatingDescription != null) {
+ attributes["disambiguatingDescription"] =
+ disambiguatingDescription.toString(includeWrapperName = false)
+ }
+ if (identifier != null) {
+ attributes["identifier"] = identifier
+ }
+ if (name != null) {
+ attributes["name"] = name.toString(includeWrapperName = false)
+ }
+ attributes += additionalProperties.map { (k, v) -> k to v.toString() }
+ val commaSeparated = attributes.entries.joinToString(separator = ", ") { (k, v) -> """$k=$v""" }
+ return """$selfTypeName($commaSeparated)"""
+ }
+
+ /**
+ * An abstract implementation of [ExecutionStatus.Builder].
+ *
+ * Allows for extension like:
+ * ```kt
+ * class MyExecutionStatus :
+ * : AbstractExecutionStatus<
+ * MyExecutionStatus,
+ * MyExecutionStatus.Builder>(...) {
+ *
+ * class Builder
+ * : Builder<
+ * Builder,
+ * MyExecutionStatus
+ * >() {
+ * private var foo: String? = null
+ * private val bars = mutableListOf<Int>()
+ *
+ * override val selfTypeName =
+ * "MyExecutionStatus.Builder"
+ *
+ * override val additionalProperties: Map<String, Any?>
+ * get() = mapOf("foo" to foo, "bars" to bars)
+ *
+ * override fun buildFromExecutionStatus(
+ * executionStatus: ExecutionStatus
+ * ): MyExecutionStatus {
+ * return MyExecutionStatus(
+ * executionStatus,
+ * foo,
+ * bars.toList()
+ * )
+ * }
+ *
+ * fun setFoo(string: String): Builder {
+ * return apply { foo = string }
+ * }
+ *
+ * fun addBar(int: Int): Builder {
+ * return apply { bars += int }
+ * }
+ *
+ * fun addBars(values: Iterable<Int>): Builder {
+ * return apply { bars += values }
+ * }
+ * }
+ * }
+ * ```
+ *
+ * Also see [AbstractExecutionStatus].
+ */
+ @Suppress("StaticFinalBuilder")
+ public abstract class Builder<
+ Self : Builder<Self, Built>, Built : AbstractExecutionStatus<Built, Self>> :
+ ExecutionStatus.Builder<Self> {
+ /**
+ * Human readable name for the concrete [Self] class.
+ *
+ * Used in the [toString] output.
+ */
+ @get:Suppress("GetterOnBuilder") protected abstract val selfTypeName: String
+
+ /**
+ * The additional properties that exist on the concrete [Self] class.
+ *
+ * Used for equality comparison and computing the hash code.
+ */
+ @get:Suppress("GetterOnBuilder") protected abstract val additionalProperties: Map<String, Any?>
+
+ private var namespace: String? = null
+
+ private var disambiguatingDescription: DisambiguatingDescription? = null
+
+ private var identifier: String? = null
+
+ private var name: Name? = null
+
+ /**
+ * Builds a concrete [Built] instance, given a built [ExecutionStatus].
+ *
+ * Subclasses should override this method to build a concrete [Built] instance that holds both
+ * the [ExecutionStatus]-specific properties and the subclass specific [additionalProperties].
+ *
+ * See the sample code in the documentation of this class for more context.
+ */
+ @Suppress("BuilderSetStyle")
+ protected abstract fun buildFromExecutionStatus(executionStatus: ExecutionStatus): Built
+
+ public final override fun build(): Built =
+ buildFromExecutionStatus(
+ ExecutionStatusImpl(namespace, disambiguatingDescription, identifier, name)
+ )
+
+ public final override fun setNamespace(namespace: String?): Self {
+ this.namespace = namespace
+ return this as Self
+ }
+
+ public final override fun setDisambiguatingDescription(
+ disambiguatingDescription: DisambiguatingDescription?
+ ): Self {
+ this.disambiguatingDescription = disambiguatingDescription
+ return this as Self
+ }
+
+ public final override fun setIdentifier(text: String?): Self {
+ this.identifier = text
+ return this as Self
+ }
+
+ public final override fun setName(name: Name?): Self {
+ this.name = name
+ return this as Self
+ }
+
+ @Suppress("BuilderSetStyle")
+ public final override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class.java != other::class.java) return false
+ other as Self
+ if (disambiguatingDescription != other.disambiguatingDescription) return false
+ if (identifier != other.identifier) return false
+ if (name != other.name) return false
+ if (namespace != other.namespace) return false
+ if (additionalProperties != other.additionalProperties) return false
+ return true
+ }
+
+ @Suppress("BuilderSetStyle")
+ public final override fun hashCode(): Int =
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
+
+ @Suppress("BuilderSetStyle")
+ public final override fun toString(): String {
+ val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace!!
+ }
+ if (disambiguatingDescription != null) {
+ attributes["disambiguatingDescription"] =
+ disambiguatingDescription!!.toString(includeWrapperName = false)
+ }
+ if (identifier != null) {
+ attributes["identifier"] = identifier!!
+ }
+ if (name != null) {
+ attributes["name"] = name!!.toString(includeWrapperName = false)
+ }
+ attributes += additionalProperties.map { (k, v) -> k to v.toString() }
+ val commaSeparated =
+ attributes.entries.joinToString(separator = ", ") { (k, v) -> """$k=$v""" }
+ return """$selfTypeName($commaSeparated)"""
+ }
+ }
+}
+
+private class ExecutionStatusImpl :
+ AbstractExecutionStatus<ExecutionStatusImpl, ExecutionStatusImpl.Builder> {
+ protected override val selfTypeName: String
+ get() = "ExecutionStatus"
+
+ protected override val additionalProperties: Map<String, Any?>
+ get() = emptyMap()
+
+ public constructor(
+ namespace: String?,
+ disambiguatingDescription: DisambiguatingDescription?,
+ identifier: String?,
+ name: Name?,
+ ) : super(namespace, disambiguatingDescription, identifier, name)
+
+ public constructor(executionStatus: ExecutionStatus) : super(executionStatus)
+
+ protected override fun toBuilderWithAdditionalPropertiesOnly(): Builder = Builder()
+
+ public class Builder : AbstractExecutionStatus.Builder<Builder, ExecutionStatusImpl>() {
+ protected override val selfTypeName: String
+ get() = "ExecutionStatus.Builder"
+
+ protected override val additionalProperties: Map<String, Any?>
+ get() = emptyMap()
+
+ protected override fun buildFromExecutionStatus(
+ executionStatus: ExecutionStatus
+ ): ExecutionStatusImpl =
+ executionStatus as? ExecutionStatusImpl ?: ExecutionStatusImpl(executionStatus)
+ }
+}
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/GenericErrorStatus.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/GenericErrorStatus.kt
new file mode 100644
index 0000000..f9b637c
--- /dev/null
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/GenericErrorStatus.kt
@@ -0,0 +1,368 @@
+// 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.appactions.builtintypes.types
+
+import androidx.appactions.builtintypes.properties.DisambiguatingDescription
+import androidx.appactions.builtintypes.properties.Name
+import java.util.Objects
+import kotlin.Any
+import kotlin.Boolean
+import kotlin.Int
+import kotlin.String
+import kotlin.Suppress
+import kotlin.collections.Map
+import kotlin.collections.emptyMap
+import kotlin.collections.joinToString
+import kotlin.collections.map
+import kotlin.collections.mutableMapOf
+import kotlin.collections.plusAssign
+import kotlin.jvm.JvmStatic
+
+/**
+ * Status indicating that the task was not executed successfully.
+ *
+ * See http://schema.googleapis.com/GenericErrorStatus for context.
+ *
+ * Should not be directly implemented. More properties may be added over time. Instead consider
+ * using [Companion.Builder] or see [AbstractGenericErrorStatus] if you need to extend this type.
+ */
+public interface GenericErrorStatus : ExecutionStatus {
+ /** Converts this [GenericErrorStatus] to its builder with all the properties copied over. */
+ public override fun toBuilder(): Builder<*>
+
+ public companion object {
+ /** Returns a default implementation of [Builder] with no properties set. */
+ @JvmStatic public fun Builder(): Builder<*> = GenericErrorStatusImpl.Builder()
+ }
+
+ /**
+ * Builder for [GenericErrorStatus].
+ *
+ * Should not be directly implemented. More methods may be added over time. See
+ * [AbstractGenericErrorStatus.Builder] if you need to extend this builder.
+ */
+ public interface Builder<Self : Builder<Self>> : ExecutionStatus.Builder<Self> {
+ /** Returns a built [GenericErrorStatus]. */
+ public override fun build(): GenericErrorStatus
+ }
+}
+
+/**
+ * An abstract implementation of [GenericErrorStatus].
+ *
+ * Allows for extension like:
+ * ```kt
+ * class MyGenericErrorStatus internal constructor(
+ * genericErrorStatus: GenericErrorStatus,
+ * val foo: String,
+ * val bars: List<Int>,
+ * ) : AbstractGenericErrorStatus<
+ * MyGenericErrorStatus,
+ * MyGenericErrorStatus.Builder
+ * >(genericErrorStatus) {
+ *
+ * override val selfTypeName =
+ * "MyGenericErrorStatus"
+ *
+ * override val additionalProperties: Map<String, Any?>
+ * get() = mapOf("foo" to foo, "bars" to bars)
+ *
+ * override fun toBuilderWithAdditionalPropertiesOnly(): Builder {
+ * return Builder()
+ * .setFoo(foo)
+ * .addBars(bars)
+ * }
+ *
+ * class Builder :
+ * AbstractGenericErrorStatus.Builder<
+ * Builder,
+ * MyGenericErrorStatus> {...}
+ * }
+ * ```
+ *
+ * Also see [AbstractGenericErrorStatus.Builder].
+ */
+@Suppress("UNCHECKED_CAST")
+public abstract class AbstractGenericErrorStatus<
+ Self : AbstractGenericErrorStatus<Self, Builder>,
+ Builder : AbstractGenericErrorStatus.Builder<Builder, Self>>
+internal constructor(
+ public final override val namespace: String?,
+ public final override val disambiguatingDescription: DisambiguatingDescription?,
+ public final override val identifier: String?,
+ public final override val name: Name?,
+) : GenericErrorStatus {
+ /**
+ * Human readable name for the concrete [Self] class.
+ *
+ * Used in the [toString] output.
+ */
+ protected abstract val selfTypeName: String
+
+ /**
+ * The additional properties that exist on the concrete [Self] class.
+ *
+ * Used for equality comparison and computing the hash code.
+ */
+ protected abstract val additionalProperties: Map<String, Any?>
+
+ /** A copy-constructor that copies over properties from another [GenericErrorStatus] instance. */
+ public constructor(
+ genericErrorStatus: GenericErrorStatus
+ ) : this(
+ genericErrorStatus.namespace,
+ genericErrorStatus.disambiguatingDescription,
+ genericErrorStatus.identifier,
+ genericErrorStatus.name
+ )
+
+ /**
+ * Returns a concrete [Builder] with the additional, non-[GenericErrorStatus] properties copied
+ * over.
+ */
+ protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
+
+ public final override fun toBuilder(): Builder =
+ toBuilderWithAdditionalPropertiesOnly()
+ .setNamespace(namespace)
+ .setDisambiguatingDescription(disambiguatingDescription)
+ .setIdentifier(identifier)
+ .setName(name)
+
+ public final override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class.java != other::class.java) return false
+ other as Self
+ if (disambiguatingDescription != other.disambiguatingDescription) return false
+ if (identifier != other.identifier) return false
+ if (name != other.name) return false
+ if (namespace != other.namespace) return false
+ if (additionalProperties != other.additionalProperties) return false
+ return true
+ }
+
+ public final override fun hashCode(): Int =
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
+
+ public final override fun toString(): String {
+ val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace
+ }
+ if (disambiguatingDescription != null) {
+ attributes["disambiguatingDescription"] =
+ disambiguatingDescription.toString(includeWrapperName = false)
+ }
+ if (identifier != null) {
+ attributes["identifier"] = identifier
+ }
+ if (name != null) {
+ attributes["name"] = name.toString(includeWrapperName = false)
+ }
+ attributes += additionalProperties.map { (k, v) -> k to v.toString() }
+ val commaSeparated = attributes.entries.joinToString(separator = ", ") { (k, v) -> """$k=$v""" }
+ return """$selfTypeName($commaSeparated)"""
+ }
+
+ /**
+ * An abstract implementation of [GenericErrorStatus.Builder].
+ *
+ * Allows for extension like:
+ * ```kt
+ * class MyGenericErrorStatus :
+ * : AbstractGenericErrorStatus<
+ * MyGenericErrorStatus,
+ * MyGenericErrorStatus.Builder>(...) {
+ *
+ * class Builder
+ * : Builder<
+ * Builder,
+ * MyGenericErrorStatus
+ * >() {
+ * private var foo: String? = null
+ * private val bars = mutableListOf<Int>()
+ *
+ * override val selfTypeName =
+ * "MyGenericErrorStatus.Builder"
+ *
+ * override val additionalProperties: Map<String, Any?>
+ * get() = mapOf("foo" to foo, "bars" to bars)
+ *
+ * override fun buildFromGenericErrorStatus(
+ * genericErrorStatus: GenericErrorStatus
+ * ): MyGenericErrorStatus {
+ * return MyGenericErrorStatus(
+ * genericErrorStatus,
+ * foo,
+ * bars.toList()
+ * )
+ * }
+ *
+ * fun setFoo(string: String): Builder {
+ * return apply { foo = string }
+ * }
+ *
+ * fun addBar(int: Int): Builder {
+ * return apply { bars += int }
+ * }
+ *
+ * fun addBars(values: Iterable<Int>): Builder {
+ * return apply { bars += values }
+ * }
+ * }
+ * }
+ * ```
+ *
+ * Also see [AbstractGenericErrorStatus].
+ */
+ @Suppress("StaticFinalBuilder")
+ public abstract class Builder<
+ Self : Builder<Self, Built>, Built : AbstractGenericErrorStatus<Built, Self>> :
+ GenericErrorStatus.Builder<Self> {
+ /**
+ * Human readable name for the concrete [Self] class.
+ *
+ * Used in the [toString] output.
+ */
+ @get:Suppress("GetterOnBuilder") protected abstract val selfTypeName: String
+
+ /**
+ * The additional properties that exist on the concrete [Self] class.
+ *
+ * Used for equality comparison and computing the hash code.
+ */
+ @get:Suppress("GetterOnBuilder") protected abstract val additionalProperties: Map<String, Any?>
+
+ private var namespace: String? = null
+
+ private var disambiguatingDescription: DisambiguatingDescription? = null
+
+ private var identifier: String? = null
+
+ private var name: Name? = null
+
+ /**
+ * Builds a concrete [Built] instance, given a built [GenericErrorStatus].
+ *
+ * Subclasses should override this method to build a concrete [Built] instance that holds both
+ * the [GenericErrorStatus]-specific properties and the subclass specific
+ * [additionalProperties].
+ *
+ * See the sample code in the documentation of this class for more context.
+ */
+ @Suppress("BuilderSetStyle")
+ protected abstract fun buildFromGenericErrorStatus(
+ genericErrorStatus: GenericErrorStatus
+ ): Built
+
+ public final override fun build(): Built =
+ buildFromGenericErrorStatus(
+ GenericErrorStatusImpl(namespace, disambiguatingDescription, identifier, name)
+ )
+
+ public final override fun setNamespace(namespace: String?): Self {
+ this.namespace = namespace
+ return this as Self
+ }
+
+ public final override fun setDisambiguatingDescription(
+ disambiguatingDescription: DisambiguatingDescription?
+ ): Self {
+ this.disambiguatingDescription = disambiguatingDescription
+ return this as Self
+ }
+
+ public final override fun setIdentifier(text: String?): Self {
+ this.identifier = text
+ return this as Self
+ }
+
+ public final override fun setName(name: Name?): Self {
+ this.name = name
+ return this as Self
+ }
+
+ @Suppress("BuilderSetStyle")
+ public final override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class.java != other::class.java) return false
+ other as Self
+ if (disambiguatingDescription != other.disambiguatingDescription) return false
+ if (identifier != other.identifier) return false
+ if (name != other.name) return false
+ if (namespace != other.namespace) return false
+ if (additionalProperties != other.additionalProperties) return false
+ return true
+ }
+
+ @Suppress("BuilderSetStyle")
+ public final override fun hashCode(): Int =
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
+
+ @Suppress("BuilderSetStyle")
+ public final override fun toString(): String {
+ val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace!!
+ }
+ if (disambiguatingDescription != null) {
+ attributes["disambiguatingDescription"] =
+ disambiguatingDescription!!.toString(includeWrapperName = false)
+ }
+ if (identifier != null) {
+ attributes["identifier"] = identifier!!
+ }
+ if (name != null) {
+ attributes["name"] = name!!.toString(includeWrapperName = false)
+ }
+ attributes += additionalProperties.map { (k, v) -> k to v.toString() }
+ val commaSeparated =
+ attributes.entries.joinToString(separator = ", ") { (k, v) -> """$k=$v""" }
+ return """$selfTypeName($commaSeparated)"""
+ }
+ }
+}
+
+private class GenericErrorStatusImpl :
+ AbstractGenericErrorStatus<GenericErrorStatusImpl, GenericErrorStatusImpl.Builder> {
+ protected override val selfTypeName: String
+ get() = "GenericErrorStatus"
+
+ protected override val additionalProperties: Map<String, Any?>
+ get() = emptyMap()
+
+ public constructor(
+ namespace: String?,
+ disambiguatingDescription: DisambiguatingDescription?,
+ identifier: String?,
+ name: Name?,
+ ) : super(namespace, disambiguatingDescription, identifier, name)
+
+ public constructor(genericErrorStatus: GenericErrorStatus) : super(genericErrorStatus)
+
+ protected override fun toBuilderWithAdditionalPropertiesOnly(): Builder = Builder()
+
+ public class Builder : AbstractGenericErrorStatus.Builder<Builder, GenericErrorStatusImpl>() {
+ protected override val selfTypeName: String
+ get() = "GenericErrorStatus.Builder"
+
+ protected override val additionalProperties: Map<String, Any?>
+ get() = emptyMap()
+
+ protected override fun buildFromGenericErrorStatus(
+ genericErrorStatus: GenericErrorStatus
+ ): GenericErrorStatusImpl =
+ genericErrorStatus as? GenericErrorStatusImpl ?: GenericErrorStatusImpl(genericErrorStatus)
+ }
+}
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Intangible.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Intangible.kt
index e1d1386..d5100fa 100644
--- a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Intangible.kt
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Intangible.kt
@@ -36,7 +36,7 @@
* See http://schema.org/Intangible for context.
*
* Should not be directly implemented. More properties may be added over time. Instead consider
- * using [Companion.Builder] or see [GenericIntangible] if you need to extend this type.
+ * using [Companion.Builder] or see [AbstractIntangible] if you need to extend this type.
*/
public interface Intangible : Thing {
/** Converts this [Intangible] to its builder with all the properties copied over. */
@@ -51,7 +51,7 @@
* Builder for [Intangible].
*
* Should not be directly implemented. More methods may be added over time. See
- * [GenericIntangible.Builder] if you need to extend this builder.
+ * [AbstractIntangible.Builder] if you need to extend this builder.
*/
public interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
/** Returns a built [Intangible]. */
@@ -60,7 +60,7 @@
}
/**
- * A generic implementation of [Intangible].
+ * An abstract implementation of [Intangible].
*
* Allows for extension like:
* ```kt
@@ -68,7 +68,7 @@
* intangible: Intangible,
* val foo: String,
* val bars: List<Int>,
- * ) : GenericIntangible<
+ * ) : AbstractIntangible<
* MyIntangible,
* MyIntangible.Builder
* >(intangible) {
@@ -86,18 +86,19 @@
* }
*
* class Builder :
- * GenericIntangible.Builder<
+ * AbstractIntangible.Builder<
* Builder,
* MyIntangible> {...}
* }
* ```
*
- * Also see [GenericIntangible.Builder].
+ * Also see [AbstractIntangible.Builder].
*/
@Suppress("UNCHECKED_CAST")
-public abstract class GenericIntangible<
- Self : GenericIntangible<Self, Builder>, Builder : GenericIntangible.Builder<Builder, Self>>
+public abstract class AbstractIntangible<
+ Self : AbstractIntangible<Self, Builder>, Builder : AbstractIntangible.Builder<Builder, Self>>
internal constructor(
+ public final override val namespace: String?,
public final override val disambiguatingDescription: DisambiguatingDescription?,
public final override val identifier: String?,
public final override val name: Name?,
@@ -119,13 +120,19 @@
/** A copy-constructor that copies over properties from another [Intangible] instance. */
public constructor(
intangible: Intangible
- ) : this(intangible.disambiguatingDescription, intangible.identifier, intangible.name)
+ ) : this(
+ intangible.namespace,
+ intangible.disambiguatingDescription,
+ intangible.identifier,
+ intangible.name
+ )
/** Returns a concrete [Builder] with the additional, non-[Intangible] properties copied over. */
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
public final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
+ .setNamespace(namespace)
.setDisambiguatingDescription(disambiguatingDescription)
.setIdentifier(identifier)
.setName(name)
@@ -137,15 +144,19 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
public final override fun hashCode(): Int =
- Objects.hash(disambiguatingDescription, identifier, name, additionalProperties)
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace
+ }
if (disambiguatingDescription != null) {
attributes["disambiguatingDescription"] =
disambiguatingDescription.toString(includeWrapperName = false)
@@ -162,12 +173,12 @@
}
/**
- * A generic implementation of [Intangible.Builder].
+ * An abstract implementation of [Intangible.Builder].
*
* Allows for extension like:
* ```kt
* class MyIntangible :
- * : GenericIntangible<
+ * : AbstractIntangible<
* MyIntangible,
* MyIntangible.Builder>(...) {
*
@@ -210,11 +221,11 @@
* }
* ```
*
- * Also see [GenericIntangible].
+ * Also see [AbstractIntangible].
*/
@Suppress("StaticFinalBuilder")
public abstract class Builder<
- Self : Builder<Self, Built>, Built : GenericIntangible<Built, Self>> :
+ Self : Builder<Self, Built>, Built : AbstractIntangible<Built, Self>> :
Intangible.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
@@ -230,6 +241,8 @@
*/
@get:Suppress("GetterOnBuilder") protected abstract val additionalProperties: Map<String, Any?>
+ private var namespace: String? = null
+
private var disambiguatingDescription: DisambiguatingDescription? = null
private var identifier: String? = null
@@ -248,7 +261,12 @@
protected abstract fun buildFromIntangible(intangible: Intangible): Built
public final override fun build(): Built =
- buildFromIntangible(IntangibleImpl(disambiguatingDescription, identifier, name))
+ buildFromIntangible(IntangibleImpl(namespace, disambiguatingDescription, identifier, name))
+
+ public final override fun setNamespace(namespace: String?): Self {
+ this.namespace = namespace
+ return this as Self
+ }
public final override fun setDisambiguatingDescription(
disambiguatingDescription: DisambiguatingDescription?
@@ -275,17 +293,21 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
@Suppress("BuilderSetStyle")
public final override fun hashCode(): Int =
- Objects.hash(disambiguatingDescription, identifier, name, additionalProperties)
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
@Suppress("BuilderSetStyle")
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace!!
+ }
if (disambiguatingDescription != null) {
attributes["disambiguatingDescription"] =
disambiguatingDescription!!.toString(includeWrapperName = false)
@@ -304,7 +326,7 @@
}
}
-internal class IntangibleImpl : GenericIntangible<IntangibleImpl, IntangibleImpl.Builder> {
+private class IntangibleImpl : AbstractIntangible<IntangibleImpl, IntangibleImpl.Builder> {
protected override val selfTypeName: String
get() = "Intangible"
@@ -312,16 +334,17 @@
get() = emptyMap()
public constructor(
+ namespace: String?,
disambiguatingDescription: DisambiguatingDescription?,
identifier: String?,
name: Name?,
- ) : super(disambiguatingDescription, identifier, name)
+ ) : super(namespace, disambiguatingDescription, identifier, name)
public constructor(intangible: Intangible) : super(intangible)
protected override fun toBuilderWithAdditionalPropertiesOnly(): Builder = Builder()
- internal class Builder : GenericIntangible.Builder<Builder, IntangibleImpl>() {
+ public class Builder : AbstractIntangible.Builder<Builder, IntangibleImpl>() {
protected override val selfTypeName: String
get() = "Intangible.Builder"
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/ObjectCreationLimitReachedStatus.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/ObjectCreationLimitReachedStatus.kt
new file mode 100644
index 0000000..804c394
--- /dev/null
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/ObjectCreationLimitReachedStatus.kt
@@ -0,0 +1,384 @@
+// 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.appactions.builtintypes.types
+
+import androidx.appactions.builtintypes.properties.DisambiguatingDescription
+import androidx.appactions.builtintypes.properties.Name
+import java.util.Objects
+import kotlin.Any
+import kotlin.Boolean
+import kotlin.Int
+import kotlin.String
+import kotlin.Suppress
+import kotlin.collections.Map
+import kotlin.collections.emptyMap
+import kotlin.collections.joinToString
+import kotlin.collections.map
+import kotlin.collections.mutableMapOf
+import kotlin.collections.plusAssign
+import kotlin.jvm.JvmStatic
+
+/**
+ * Status indicating that the number of objects have reached the limit and more objects cannot be
+ * created.
+ *
+ * See http://schema.googleapis.com/ObjectCreationLimitReachedStatus for context.
+ *
+ * Should not be directly implemented. More properties may be added over time. Instead consider
+ * using [Companion.Builder] or see [AbstractObjectCreationLimitReachedStatus] if you need to extend
+ * this type.
+ */
+public interface ObjectCreationLimitReachedStatus : ExecutionStatus {
+ /**
+ * Converts this [ObjectCreationLimitReachedStatus] to its builder with all the properties copied
+ * over.
+ */
+ public override fun toBuilder(): Builder<*>
+
+ public companion object {
+ /** Returns a default implementation of [Builder] with no properties set. */
+ @JvmStatic public fun Builder(): Builder<*> = ObjectCreationLimitReachedStatusImpl.Builder()
+ }
+
+ /**
+ * Builder for [ObjectCreationLimitReachedStatus].
+ *
+ * Should not be directly implemented. More methods may be added over time. See
+ * [AbstractObjectCreationLimitReachedStatus.Builder] if you need to extend this builder.
+ */
+ public interface Builder<Self : Builder<Self>> : ExecutionStatus.Builder<Self> {
+ /** Returns a built [ObjectCreationLimitReachedStatus]. */
+ public override fun build(): ObjectCreationLimitReachedStatus
+ }
+}
+
+/**
+ * An abstract implementation of [ObjectCreationLimitReachedStatus].
+ *
+ * Allows for extension like:
+ * ```kt
+ * class MyObjectCreationLimitReachedStatus internal constructor(
+ * objectCreationLimitReachedStatus: ObjectCreationLimitReachedStatus,
+ * val foo: String,
+ * val bars: List<Int>,
+ * ) : AbstractObjectCreationLimitReachedStatus<
+ * MyObjectCreationLimitReachedStatus,
+ * MyObjectCreationLimitReachedStatus.Builder
+ * >(objectCreationLimitReachedStatus) {
+ *
+ * override val selfTypeName =
+ * "MyObjectCreationLimitReachedStatus"
+ *
+ * override val additionalProperties: Map<String, Any?>
+ * get() = mapOf("foo" to foo, "bars" to bars)
+ *
+ * override fun toBuilderWithAdditionalPropertiesOnly(): Builder {
+ * return Builder()
+ * .setFoo(foo)
+ * .addBars(bars)
+ * }
+ *
+ * class Builder :
+ * AbstractObjectCreationLimitReachedStatus.Builder<
+ * Builder,
+ * MyObjectCreationLimitReachedStatus> {...}
+ * }
+ * ```
+ *
+ * Also see [AbstractObjectCreationLimitReachedStatus.Builder].
+ */
+@Suppress("UNCHECKED_CAST")
+public abstract class AbstractObjectCreationLimitReachedStatus<
+ Self : AbstractObjectCreationLimitReachedStatus<Self, Builder>,
+ Builder : AbstractObjectCreationLimitReachedStatus.Builder<Builder, Self>>
+internal constructor(
+ public final override val namespace: String?,
+ public final override val disambiguatingDescription: DisambiguatingDescription?,
+ public final override val identifier: String?,
+ public final override val name: Name?,
+) : ObjectCreationLimitReachedStatus {
+ /**
+ * Human readable name for the concrete [Self] class.
+ *
+ * Used in the [toString] output.
+ */
+ protected abstract val selfTypeName: String
+
+ /**
+ * The additional properties that exist on the concrete [Self] class.
+ *
+ * Used for equality comparison and computing the hash code.
+ */
+ protected abstract val additionalProperties: Map<String, Any?>
+
+ /**
+ * A copy-constructor that copies over properties from another [ObjectCreationLimitReachedStatus]
+ * instance.
+ */
+ public constructor(
+ objectCreationLimitReachedStatus: ObjectCreationLimitReachedStatus
+ ) : this(
+ objectCreationLimitReachedStatus.namespace,
+ objectCreationLimitReachedStatus.disambiguatingDescription,
+ objectCreationLimitReachedStatus.identifier,
+ objectCreationLimitReachedStatus.name
+ )
+
+ /**
+ * Returns a concrete [Builder] with the additional, non-[ObjectCreationLimitReachedStatus]
+ * properties copied over.
+ */
+ protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
+
+ public final override fun toBuilder(): Builder =
+ toBuilderWithAdditionalPropertiesOnly()
+ .setNamespace(namespace)
+ .setDisambiguatingDescription(disambiguatingDescription)
+ .setIdentifier(identifier)
+ .setName(name)
+
+ public final override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class.java != other::class.java) return false
+ other as Self
+ if (disambiguatingDescription != other.disambiguatingDescription) return false
+ if (identifier != other.identifier) return false
+ if (name != other.name) return false
+ if (namespace != other.namespace) return false
+ if (additionalProperties != other.additionalProperties) return false
+ return true
+ }
+
+ public final override fun hashCode(): Int =
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
+
+ public final override fun toString(): String {
+ val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace
+ }
+ if (disambiguatingDescription != null) {
+ attributes["disambiguatingDescription"] =
+ disambiguatingDescription.toString(includeWrapperName = false)
+ }
+ if (identifier != null) {
+ attributes["identifier"] = identifier
+ }
+ if (name != null) {
+ attributes["name"] = name.toString(includeWrapperName = false)
+ }
+ attributes += additionalProperties.map { (k, v) -> k to v.toString() }
+ val commaSeparated = attributes.entries.joinToString(separator = ", ") { (k, v) -> """$k=$v""" }
+ return """$selfTypeName($commaSeparated)"""
+ }
+
+ /**
+ * An abstract implementation of [ObjectCreationLimitReachedStatus.Builder].
+ *
+ * Allows for extension like:
+ * ```kt
+ * class MyObjectCreationLimitReachedStatus :
+ * : AbstractObjectCreationLimitReachedStatus<
+ * MyObjectCreationLimitReachedStatus,
+ * MyObjectCreationLimitReachedStatus.Builder>(...) {
+ *
+ * class Builder
+ * : Builder<
+ * Builder,
+ * MyObjectCreationLimitReachedStatus
+ * >() {
+ * private var foo: String? = null
+ * private val bars = mutableListOf<Int>()
+ *
+ * override val selfTypeName =
+ * "MyObjectCreationLimitReachedStatus.Builder"
+ *
+ * override val additionalProperties: Map<String, Any?>
+ * get() = mapOf("foo" to foo, "bars" to bars)
+ *
+ * override fun buildFromObjectCreationLimitReachedStatus(
+ * objectCreationLimitReachedStatus: ObjectCreationLimitReachedStatus
+ * ): MyObjectCreationLimitReachedStatus {
+ * return MyObjectCreationLimitReachedStatus(
+ * objectCreationLimitReachedStatus,
+ * foo,
+ * bars.toList()
+ * )
+ * }
+ *
+ * fun setFoo(string: String): Builder {
+ * return apply { foo = string }
+ * }
+ *
+ * fun addBar(int: Int): Builder {
+ * return apply { bars += int }
+ * }
+ *
+ * fun addBars(values: Iterable<Int>): Builder {
+ * return apply { bars += values }
+ * }
+ * }
+ * }
+ * ```
+ *
+ * Also see [AbstractObjectCreationLimitReachedStatus].
+ */
+ @Suppress("StaticFinalBuilder")
+ public abstract class Builder<
+ Self : Builder<Self, Built>, Built : AbstractObjectCreationLimitReachedStatus<Built, Self>> :
+ ObjectCreationLimitReachedStatus.Builder<Self> {
+ /**
+ * Human readable name for the concrete [Self] class.
+ *
+ * Used in the [toString] output.
+ */
+ @get:Suppress("GetterOnBuilder") protected abstract val selfTypeName: String
+
+ /**
+ * The additional properties that exist on the concrete [Self] class.
+ *
+ * Used for equality comparison and computing the hash code.
+ */
+ @get:Suppress("GetterOnBuilder") protected abstract val additionalProperties: Map<String, Any?>
+
+ private var namespace: String? = null
+
+ private var disambiguatingDescription: DisambiguatingDescription? = null
+
+ private var identifier: String? = null
+
+ private var name: Name? = null
+
+ /**
+ * Builds a concrete [Built] instance, given a built [ObjectCreationLimitReachedStatus].
+ *
+ * Subclasses should override this method to build a concrete [Built] instance that holds both
+ * the [ObjectCreationLimitReachedStatus]-specific properties and the subclass specific
+ * [additionalProperties].
+ *
+ * See the sample code in the documentation of this class for more context.
+ */
+ @Suppress("BuilderSetStyle")
+ protected abstract fun buildFromObjectCreationLimitReachedStatus(
+ objectCreationLimitReachedStatus: ObjectCreationLimitReachedStatus
+ ): Built
+
+ public final override fun build(): Built =
+ buildFromObjectCreationLimitReachedStatus(
+ ObjectCreationLimitReachedStatusImpl(namespace, disambiguatingDescription, identifier, name)
+ )
+
+ public final override fun setNamespace(namespace: String?): Self {
+ this.namespace = namespace
+ return this as Self
+ }
+
+ public final override fun setDisambiguatingDescription(
+ disambiguatingDescription: DisambiguatingDescription?
+ ): Self {
+ this.disambiguatingDescription = disambiguatingDescription
+ return this as Self
+ }
+
+ public final override fun setIdentifier(text: String?): Self {
+ this.identifier = text
+ return this as Self
+ }
+
+ public final override fun setName(name: Name?): Self {
+ this.name = name
+ return this as Self
+ }
+
+ @Suppress("BuilderSetStyle")
+ public final override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class.java != other::class.java) return false
+ other as Self
+ if (disambiguatingDescription != other.disambiguatingDescription) return false
+ if (identifier != other.identifier) return false
+ if (name != other.name) return false
+ if (namespace != other.namespace) return false
+ if (additionalProperties != other.additionalProperties) return false
+ return true
+ }
+
+ @Suppress("BuilderSetStyle")
+ public final override fun hashCode(): Int =
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
+
+ @Suppress("BuilderSetStyle")
+ public final override fun toString(): String {
+ val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace!!
+ }
+ if (disambiguatingDescription != null) {
+ attributes["disambiguatingDescription"] =
+ disambiguatingDescription!!.toString(includeWrapperName = false)
+ }
+ if (identifier != null) {
+ attributes["identifier"] = identifier!!
+ }
+ if (name != null) {
+ attributes["name"] = name!!.toString(includeWrapperName = false)
+ }
+ attributes += additionalProperties.map { (k, v) -> k to v.toString() }
+ val commaSeparated =
+ attributes.entries.joinToString(separator = ", ") { (k, v) -> """$k=$v""" }
+ return """$selfTypeName($commaSeparated)"""
+ }
+ }
+}
+
+private class ObjectCreationLimitReachedStatusImpl :
+ AbstractObjectCreationLimitReachedStatus<
+ ObjectCreationLimitReachedStatusImpl, ObjectCreationLimitReachedStatusImpl.Builder
+ > {
+ protected override val selfTypeName: String
+ get() = "ObjectCreationLimitReachedStatus"
+
+ protected override val additionalProperties: Map<String, Any?>
+ get() = emptyMap()
+
+ public constructor(
+ namespace: String?,
+ disambiguatingDescription: DisambiguatingDescription?,
+ identifier: String?,
+ name: Name?,
+ ) : super(namespace, disambiguatingDescription, identifier, name)
+
+ public constructor(
+ objectCreationLimitReachedStatus: ObjectCreationLimitReachedStatus
+ ) : super(objectCreationLimitReachedStatus)
+
+ protected override fun toBuilderWithAdditionalPropertiesOnly(): Builder = Builder()
+
+ public class Builder :
+ AbstractObjectCreationLimitReachedStatus.Builder<
+ Builder, ObjectCreationLimitReachedStatusImpl
+ >() {
+ protected override val selfTypeName: String
+ get() = "ObjectCreationLimitReachedStatus.Builder"
+
+ protected override val additionalProperties: Map<String, Any?>
+ get() = emptyMap()
+
+ protected override fun buildFromObjectCreationLimitReachedStatus(
+ objectCreationLimitReachedStatus: ObjectCreationLimitReachedStatus
+ ): ObjectCreationLimitReachedStatusImpl =
+ objectCreationLimitReachedStatus as? ObjectCreationLimitReachedStatusImpl
+ ?: ObjectCreationLimitReachedStatusImpl(objectCreationLimitReachedStatus)
+ }
+}
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Person.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Person.kt
index 37403bb..471b97b 100644
--- a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Person.kt
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Person.kt
@@ -35,10 +35,14 @@
* See http://schema.org/Person for context.
*
* Should not be directly implemented. More properties may be added over time. Instead consider
- * using [Companion.Builder] or see [GenericPerson] if you need to extend this type.
+ * using [Companion.Builder] or see [AbstractPerson] if you need to extend this type.
*/
public interface Person : Thing {
- /** Email address. */
+ /**
+ * Email address.
+ *
+ * See http://schema.org/email for more context.
+ */
public val email: String?
/** Converts this [Person] to its builder with all the properties copied over. */
@@ -53,7 +57,7 @@
* Builder for [Person].
*
* Should not be directly implemented. More methods may be added over time. See
- * [GenericPerson.Builder] if you need to extend this builder.
+ * [AbstractPerson.Builder] if you need to extend this builder.
*/
public interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
/** Returns a built [Person]. */
@@ -65,7 +69,7 @@
}
/**
- * A generic implementation of [Person].
+ * An abstract implementation of [Person].
*
* Allows for extension like:
* ```kt
@@ -73,7 +77,7 @@
* person: Person,
* val foo: String,
* val bars: List<Int>,
- * ) : GenericPerson<
+ * ) : AbstractPerson<
* MyPerson,
* MyPerson.Builder
* >(person) {
@@ -91,18 +95,19 @@
* }
*
* class Builder :
- * GenericPerson.Builder<
+ * AbstractPerson.Builder<
* Builder,
* MyPerson> {...}
* }
* ```
*
- * Also see [GenericPerson.Builder].
+ * Also see [AbstractPerson.Builder].
*/
@Suppress("UNCHECKED_CAST")
-public abstract class GenericPerson<
- Self : GenericPerson<Self, Builder>, Builder : GenericPerson.Builder<Builder, Self>>
+public abstract class AbstractPerson<
+ Self : AbstractPerson<Self, Builder>, Builder : AbstractPerson.Builder<Builder, Self>>
internal constructor(
+ public final override val namespace: String?,
public final override val email: String?,
public final override val disambiguatingDescription: DisambiguatingDescription?,
public final override val identifier: String?,
@@ -125,13 +130,20 @@
/** A copy-constructor that copies over properties from another [Person] instance. */
public constructor(
person: Person
- ) : this(person.email, person.disambiguatingDescription, person.identifier, person.name)
+ ) : this(
+ person.namespace,
+ person.email,
+ person.disambiguatingDescription,
+ person.identifier,
+ person.name
+ )
/** Returns a concrete [Builder] with the additional, non-[Person] properties copied over. */
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
public final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
+ .setNamespace(namespace)
.setEmail(email)
.setDisambiguatingDescription(disambiguatingDescription)
.setIdentifier(identifier)
@@ -145,15 +157,26 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
public final override fun hashCode(): Int =
- Objects.hash(email, disambiguatingDescription, identifier, name, additionalProperties)
+ Objects.hash(
+ email,
+ disambiguatingDescription,
+ identifier,
+ name,
+ namespace,
+ additionalProperties
+ )
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace
+ }
if (email != null) {
attributes["email"] = email
}
@@ -173,12 +196,12 @@
}
/**
- * A generic implementation of [Person.Builder].
+ * An abstract implementation of [Person.Builder].
*
* Allows for extension like:
* ```kt
* class MyPerson :
- * : GenericPerson<
+ * : AbstractPerson<
* MyPerson,
* MyPerson.Builder>(...) {
*
@@ -221,10 +244,10 @@
* }
* ```
*
- * Also see [GenericPerson].
+ * Also see [AbstractPerson].
*/
@Suppress("StaticFinalBuilder")
- public abstract class Builder<Self : Builder<Self, Built>, Built : GenericPerson<Built, Self>> :
+ public abstract class Builder<Self : Builder<Self, Built>, Built : AbstractPerson<Built, Self>> :
Person.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
@@ -240,6 +263,8 @@
*/
@get:Suppress("GetterOnBuilder") protected abstract val additionalProperties: Map<String, Any?>
+ private var namespace: String? = null
+
private var email: String? = null
private var disambiguatingDescription: DisambiguatingDescription? = null
@@ -259,7 +284,12 @@
@Suppress("BuilderSetStyle") protected abstract fun buildFromPerson(person: Person): Built
public final override fun build(): Built =
- buildFromPerson(PersonImpl(email, disambiguatingDescription, identifier, name))
+ buildFromPerson(PersonImpl(namespace, email, disambiguatingDescription, identifier, name))
+
+ public final override fun setNamespace(namespace: String?): Self {
+ this.namespace = namespace
+ return this as Self
+ }
public final override fun setEmail(text: String?): Self {
this.email = text
@@ -292,17 +322,28 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
@Suppress("BuilderSetStyle")
public final override fun hashCode(): Int =
- Objects.hash(email, disambiguatingDescription, identifier, name, additionalProperties)
+ Objects.hash(
+ email,
+ disambiguatingDescription,
+ identifier,
+ name,
+ namespace,
+ additionalProperties
+ )
@Suppress("BuilderSetStyle")
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace!!
+ }
if (email != null) {
attributes["email"] = email!!
}
@@ -324,7 +365,7 @@
}
}
-internal class PersonImpl : GenericPerson<PersonImpl, PersonImpl.Builder> {
+private class PersonImpl : AbstractPerson<PersonImpl, PersonImpl.Builder> {
protected override val selfTypeName: String
get() = "Person"
@@ -332,17 +373,18 @@
get() = emptyMap()
public constructor(
+ namespace: String?,
email: String?,
disambiguatingDescription: DisambiguatingDescription?,
identifier: String?,
name: Name?,
- ) : super(email, disambiguatingDescription, identifier, name)
+ ) : super(namespace, email, disambiguatingDescription, identifier, name)
public constructor(person: Person) : super(person)
protected override fun toBuilderWithAdditionalPropertiesOnly(): Builder = Builder()
- internal class Builder : GenericPerson.Builder<Builder, PersonImpl>() {
+ public class Builder : AbstractPerson.Builder<Builder, PersonImpl>() {
protected override val selfTypeName: String
get() = "Person.Builder"
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Schedule.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Schedule.kt
index 216380d..07e103c 100644
--- a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Schedule.kt
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Schedule.kt
@@ -23,10 +23,10 @@
import androidx.appactions.builtintypes.properties.StartDate
import androidx.appactions.builtintypes.properties.StartTime
import java.time.Duration
+import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
-import java.time.ZonedDateTime
import java.util.Objects
import kotlin.Any
import kotlin.Boolean
@@ -59,21 +59,29 @@
* See http://schema.org/Schedule for context.
*
* Should not be directly implemented. More properties may be added over time. Instead consider
- * using [Companion.Builder] or see [GenericSchedule] if you need to extend this type.
+ * using [Companion.Builder] or see [AbstractSchedule] if you need to extend this type.
*/
public interface Schedule : Intangible {
- /** Defines the day(s) of the week on which a recurring Event takes place. */
+ /**
+ * Defines the day(s) of the week on which a recurring Event takes place.
+ *
+ * See http://schema.org/byDay for more context.
+ */
public val byDays: List<ByDay>
/**
* Defines the month(s) of the year on which a recurring Event takes place. Specified as an
* Integer between 1-12. January is 1.
+ *
+ * See http://schema.org/byMonth for more context.
*/
public val byMonths: List<Long>
/**
* Defines the day(s) of the month on which a recurring Event takes place. Specified as an Integer
* between 1-31.
+ *
+ * See http://schema.org/byMonthDay for more context.
*/
public val byMonthDays: List<Long>
@@ -81,10 +89,16 @@
* Defines the week(s) of the month on which a recurring Event takes place. Specified as an
* Integer between 1-5. For clarity, byMonthWeek is best used in conjunction with byDay to
* indicate concepts like the first and third Mondays of a month.
+ *
+ * See http://schema.org/byMonthWeek for more context.
*/
public val byMonthWeeks: List<Long>
- /** The end date and time of the item. */
+ /**
+ * The end date and time of the item.
+ *
+ * See http://schema.org/endDate for more context.
+ */
public val endDate: EndDate?
/**
@@ -94,6 +108,8 @@
* expected to end. For actions that span a period of time, when the action was performed. E.g.
* John wrote a book from January to *December*. For media, including audio and video, it's the
* time offset of the end of a clip within a larger file.
+ *
+ * See http://schema.org/endTime for more context.
*/
public val endTime: EndTime?
@@ -104,25 +120,39 @@
* excluded from the schedule. If an exception is specified as a `Date` then any event that is
* scheduled for that 24 hour period should be excluded from the schedule. This allows a whole day
* to be excluded from the schedule without having to itemise every scheduled event.
+ *
+ * See http://schema.org/exceptDate for more context.
*/
public val exceptDate: ExceptDate?
- /** Defines the number of times a recurring `Event` will take place. */
+ /**
+ * Defines the number of times a recurring `Event` will take place.
+ *
+ * See http://schema.org/repeatCount for more context.
+ */
@get:Suppress("AutoBoxing") public val repeatCount: Long?
/**
* Defines the frequency at which `Event`s will occur according to a schedule `Schedule`. The
* intervals between events should be defined as a `Duration` of time.
+ *
+ * See http://schema.org/repeatFrequency for more context.
*/
public val repeatFrequency: RepeatFrequency?
/**
* Indicates the timezone for which the time(s) indicated in the `Schedule` are given. The value
* provided should be among those listed in the IANA Time Zone Database.
+ *
+ * See http://schema.org/scheduleTimezone for more context.
*/
public val scheduleTimezone: String?
- /** The start date and time of the item. */
+ /**
+ * The start date and time of the item.
+ *
+ * See http://schema.org/startDate for more context.
+ */
public val startDate: StartDate?
/**
@@ -132,6 +162,8 @@
* expected to start. For actions that span a period of time, when the action was performed. E.g.
* John wrote a book from *January* to December. For media, including audio and video, it's the
* time offset of the start of a clip within a larger file.
+ *
+ * See http://schema.org/startTime for more context.
*/
public val startTime: StartTime?
@@ -147,7 +179,7 @@
* Builder for [Schedule].
*
* Should not be directly implemented. More methods may be added over time. See
- * [GenericSchedule.Builder] if you need to extend this builder.
+ * [AbstractSchedule.Builder] if you need to extend this builder.
*/
public interface Builder<Self : Builder<Self>> : Intangible.Builder<Self> {
/** Returns a built [Schedule]. */
@@ -201,8 +233,8 @@
/** Sets the `endDate` to [LocalDateTime]. */
public fun setEndDate(localDateTime: LocalDateTime): Self = setEndDate(EndDate(localDateTime))
- /** Sets the `endDate` to [ZonedDateTime]. */
- public fun setEndDate(zonedDateTime: ZonedDateTime): Self = setEndDate(EndDate(zonedDateTime))
+ /** Sets the `endDate` to [Instant]. */
+ public fun setEndDate(instant: Instant): Self = setEndDate(EndDate(instant))
/** Sets the `endDate`. */
public fun setEndDate(endDate: EndDate?): Self
@@ -213,8 +245,8 @@
/** Sets the `endTime` to [LocalDateTime]. */
public fun setEndTime(localDateTime: LocalDateTime): Self = setEndTime(EndTime(localDateTime))
- /** Sets the `endTime` to [ZonedDateTime]. */
- public fun setEndTime(zonedDateTime: ZonedDateTime): Self = setEndTime(EndTime(zonedDateTime))
+ /** Sets the `endTime` to [Instant]. */
+ public fun setEndTime(instant: Instant): Self = setEndTime(EndTime(instant))
/** Sets the `endTime`. */
public fun setEndTime(endTime: EndTime?): Self
@@ -226,9 +258,8 @@
public fun setExceptDate(localDateTime: LocalDateTime): Self =
setExceptDate(ExceptDate(localDateTime))
- /** Sets the `exceptDate` to [ZonedDateTime]. */
- public fun setExceptDate(zonedDateTime: ZonedDateTime): Self =
- setExceptDate(ExceptDate(zonedDateTime))
+ /** Sets the `exceptDate` to [Instant]. */
+ public fun setExceptDate(instant: Instant): Self = setExceptDate(ExceptDate(instant))
/** Sets the `exceptDate`. */
public fun setExceptDate(exceptDate: ExceptDate?): Self
@@ -256,9 +287,8 @@
public fun setStartDate(localDateTime: LocalDateTime): Self =
setStartDate(StartDate(localDateTime))
- /** Sets the `startDate` to [ZonedDateTime]. */
- public fun setStartDate(zonedDateTime: ZonedDateTime): Self =
- setStartDate(StartDate(zonedDateTime))
+ /** Sets the `startDate` to [Instant]. */
+ public fun setStartDate(instant: Instant): Self = setStartDate(StartDate(instant))
/** Sets the `startDate`. */
public fun setStartDate(startDate: StartDate?): Self
@@ -270,9 +300,8 @@
public fun setStartTime(localDateTime: LocalDateTime): Self =
setStartTime(StartTime(localDateTime))
- /** Sets the `startTime` to [ZonedDateTime]. */
- public fun setStartTime(zonedDateTime: ZonedDateTime): Self =
- setStartTime(StartTime(zonedDateTime))
+ /** Sets the `startTime` to [Instant]. */
+ public fun setStartTime(instant: Instant): Self = setStartTime(StartTime(instant))
/** Sets the `startTime`. */
public fun setStartTime(startTime: StartTime?): Self
@@ -280,7 +309,7 @@
}
/**
- * A generic implementation of [Schedule].
+ * An abstract implementation of [Schedule].
*
* Allows for extension like:
* ```kt
@@ -288,7 +317,7 @@
* schedule: Schedule,
* val foo: String,
* val bars: List<Int>,
- * ) : GenericSchedule<
+ * ) : AbstractSchedule<
* MySchedule,
* MySchedule.Builder
* >(schedule) {
@@ -306,18 +335,19 @@
* }
*
* class Builder :
- * GenericSchedule.Builder<
+ * AbstractSchedule.Builder<
* Builder,
* MySchedule> {...}
* }
* ```
*
- * Also see [GenericSchedule.Builder].
+ * Also see [AbstractSchedule.Builder].
*/
@Suppress("UNCHECKED_CAST")
-public abstract class GenericSchedule<
- Self : GenericSchedule<Self, Builder>, Builder : GenericSchedule.Builder<Builder, Self>>
+public abstract class AbstractSchedule<
+ Self : AbstractSchedule<Self, Builder>, Builder : AbstractSchedule.Builder<Builder, Self>>
internal constructor(
+ public final override val namespace: String?,
public final override val byDays: List<ByDay>,
public final override val byMonths: List<Long>,
public final override val byMonthDays: List<Long>,
@@ -352,6 +382,7 @@
public constructor(
schedule: Schedule
) : this(
+ schedule.namespace,
schedule.byDays,
schedule.byMonths,
schedule.byMonthDays,
@@ -374,6 +405,7 @@
public final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
+ .setNamespace(namespace)
.addByDays(byDays)
.addByMonths(byMonths)
.addByMonthDays(byMonthDays)
@@ -409,6 +441,7 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
@@ -430,11 +463,15 @@
disambiguatingDescription,
identifier,
name,
+ namespace,
additionalProperties
)
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace
+ }
if (byDays.isNotEmpty()) {
attributes["byDays"] = byDays.map { it.toString(includeWrapperName = false) }.toString()
}
@@ -487,12 +524,12 @@
}
/**
- * A generic implementation of [Schedule.Builder].
+ * An abstract implementation of [Schedule.Builder].
*
* Allows for extension like:
* ```kt
* class MySchedule :
- * : GenericSchedule<
+ * : AbstractSchedule<
* MySchedule,
* MySchedule.Builder>(...) {
*
@@ -535,11 +572,11 @@
* }
* ```
*
- * Also see [GenericSchedule].
+ * Also see [AbstractSchedule].
*/
@Suppress("StaticFinalBuilder")
- public abstract class Builder<Self : Builder<Self, Built>, Built : GenericSchedule<Built, Self>> :
- Schedule.Builder<Self> {
+ public abstract class Builder<
+ Self : Builder<Self, Built>, Built : AbstractSchedule<Built, Self>> : Schedule.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
*
@@ -554,6 +591,8 @@
*/
@get:Suppress("GetterOnBuilder") protected abstract val additionalProperties: Map<String, Any?>
+ private var namespace: String? = null
+
private val byDays: MutableList<ByDay> = mutableListOf()
private val byMonths: MutableList<Long> = mutableListOf()
@@ -597,6 +636,7 @@
public final override fun build(): Built =
buildFromSchedule(
ScheduleImpl(
+ namespace,
byDays.toList(),
byMonths.toList(),
byMonthDays.toList(),
@@ -615,6 +655,11 @@
)
)
+ public final override fun setNamespace(namespace: String?): Self {
+ this.namespace = namespace
+ return this as Self
+ }
+
public final override fun addByDay(byDay: ByDay): Self {
byDays += byDay
return this as Self
@@ -752,6 +797,7 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
@@ -774,12 +820,16 @@
disambiguatingDescription,
identifier,
name,
+ namespace,
additionalProperties
)
@Suppress("BuilderSetStyle")
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace!!
+ }
if (byDays.isNotEmpty()) {
attributes["byDays"] = byDays.map { it.toString(includeWrapperName = false) }.toString()
}
@@ -834,7 +884,7 @@
}
}
-internal class ScheduleImpl : GenericSchedule<ScheduleImpl, ScheduleImpl.Builder> {
+private class ScheduleImpl : AbstractSchedule<ScheduleImpl, ScheduleImpl.Builder> {
protected override val selfTypeName: String
get() = "Schedule"
@@ -842,6 +892,7 @@
get() = emptyMap()
public constructor(
+ namespace: String?,
byDays: List<ByDay>,
byMonths: List<Long>,
byMonthDays: List<Long>,
@@ -858,6 +909,7 @@
identifier: String?,
name: Name?,
) : super(
+ namespace,
byDays,
byMonths,
byMonthDays,
@@ -879,7 +931,7 @@
protected override fun toBuilderWithAdditionalPropertiesOnly(): Builder = Builder()
- internal class Builder : GenericSchedule.Builder<Builder, ScheduleImpl>() {
+ public class Builder : AbstractSchedule.Builder<Builder, ScheduleImpl>() {
protected override val selfTypeName: String
get() = "Schedule.Builder"
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/SuccessStatus.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/SuccessStatus.kt
new file mode 100644
index 0000000..8655af4
--- /dev/null
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/SuccessStatus.kt
@@ -0,0 +1,362 @@
+// 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.appactions.builtintypes.types
+
+import androidx.appactions.builtintypes.properties.DisambiguatingDescription
+import androidx.appactions.builtintypes.properties.Name
+import java.util.Objects
+import kotlin.Any
+import kotlin.Boolean
+import kotlin.Int
+import kotlin.String
+import kotlin.Suppress
+import kotlin.collections.Map
+import kotlin.collections.emptyMap
+import kotlin.collections.joinToString
+import kotlin.collections.map
+import kotlin.collections.mutableMapOf
+import kotlin.collections.plusAssign
+import kotlin.jvm.JvmStatic
+
+/**
+ * Status indicating that the task was executed successfully.
+ *
+ * See http://schema.googleapis.com/SuccessStatus for context.
+ *
+ * Should not be directly implemented. More properties may be added over time. Instead consider
+ * using [Companion.Builder] or see [AbstractSuccessStatus] if you need to extend this type.
+ */
+public interface SuccessStatus : ExecutionStatus {
+ /** Converts this [SuccessStatus] to its builder with all the properties copied over. */
+ public override fun toBuilder(): Builder<*>
+
+ public companion object {
+ /** Returns a default implementation of [Builder] with no properties set. */
+ @JvmStatic public fun Builder(): Builder<*> = SuccessStatusImpl.Builder()
+ }
+
+ /**
+ * Builder for [SuccessStatus].
+ *
+ * Should not be directly implemented. More methods may be added over time. See
+ * [AbstractSuccessStatus.Builder] if you need to extend this builder.
+ */
+ public interface Builder<Self : Builder<Self>> : ExecutionStatus.Builder<Self> {
+ /** Returns a built [SuccessStatus]. */
+ public override fun build(): SuccessStatus
+ }
+}
+
+/**
+ * An abstract implementation of [SuccessStatus].
+ *
+ * Allows for extension like:
+ * ```kt
+ * class MySuccessStatus internal constructor(
+ * successStatus: SuccessStatus,
+ * val foo: String,
+ * val bars: List<Int>,
+ * ) : AbstractSuccessStatus<
+ * MySuccessStatus,
+ * MySuccessStatus.Builder
+ * >(successStatus) {
+ *
+ * override val selfTypeName =
+ * "MySuccessStatus"
+ *
+ * override val additionalProperties: Map<String, Any?>
+ * get() = mapOf("foo" to foo, "bars" to bars)
+ *
+ * override fun toBuilderWithAdditionalPropertiesOnly(): Builder {
+ * return Builder()
+ * .setFoo(foo)
+ * .addBars(bars)
+ * }
+ *
+ * class Builder :
+ * AbstractSuccessStatus.Builder<
+ * Builder,
+ * MySuccessStatus> {...}
+ * }
+ * ```
+ *
+ * Also see [AbstractSuccessStatus.Builder].
+ */
+@Suppress("UNCHECKED_CAST")
+public abstract class AbstractSuccessStatus<
+ Self : AbstractSuccessStatus<Self, Builder>,
+ Builder : AbstractSuccessStatus.Builder<Builder, Self>>
+internal constructor(
+ public final override val namespace: String?,
+ public final override val disambiguatingDescription: DisambiguatingDescription?,
+ public final override val identifier: String?,
+ public final override val name: Name?,
+) : SuccessStatus {
+ /**
+ * Human readable name for the concrete [Self] class.
+ *
+ * Used in the [toString] output.
+ */
+ protected abstract val selfTypeName: String
+
+ /**
+ * The additional properties that exist on the concrete [Self] class.
+ *
+ * Used for equality comparison and computing the hash code.
+ */
+ protected abstract val additionalProperties: Map<String, Any?>
+
+ /** A copy-constructor that copies over properties from another [SuccessStatus] instance. */
+ public constructor(
+ successStatus: SuccessStatus
+ ) : this(
+ successStatus.namespace,
+ successStatus.disambiguatingDescription,
+ successStatus.identifier,
+ successStatus.name
+ )
+
+ /**
+ * Returns a concrete [Builder] with the additional, non-[SuccessStatus] properties copied over.
+ */
+ protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
+
+ public final override fun toBuilder(): Builder =
+ toBuilderWithAdditionalPropertiesOnly()
+ .setNamespace(namespace)
+ .setDisambiguatingDescription(disambiguatingDescription)
+ .setIdentifier(identifier)
+ .setName(name)
+
+ public final override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class.java != other::class.java) return false
+ other as Self
+ if (disambiguatingDescription != other.disambiguatingDescription) return false
+ if (identifier != other.identifier) return false
+ if (name != other.name) return false
+ if (namespace != other.namespace) return false
+ if (additionalProperties != other.additionalProperties) return false
+ return true
+ }
+
+ public final override fun hashCode(): Int =
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
+
+ public final override fun toString(): String {
+ val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace
+ }
+ if (disambiguatingDescription != null) {
+ attributes["disambiguatingDescription"] =
+ disambiguatingDescription.toString(includeWrapperName = false)
+ }
+ if (identifier != null) {
+ attributes["identifier"] = identifier
+ }
+ if (name != null) {
+ attributes["name"] = name.toString(includeWrapperName = false)
+ }
+ attributes += additionalProperties.map { (k, v) -> k to v.toString() }
+ val commaSeparated = attributes.entries.joinToString(separator = ", ") { (k, v) -> """$k=$v""" }
+ return """$selfTypeName($commaSeparated)"""
+ }
+
+ /**
+ * An abstract implementation of [SuccessStatus.Builder].
+ *
+ * Allows for extension like:
+ * ```kt
+ * class MySuccessStatus :
+ * : AbstractSuccessStatus<
+ * MySuccessStatus,
+ * MySuccessStatus.Builder>(...) {
+ *
+ * class Builder
+ * : Builder<
+ * Builder,
+ * MySuccessStatus
+ * >() {
+ * private var foo: String? = null
+ * private val bars = mutableListOf<Int>()
+ *
+ * override val selfTypeName =
+ * "MySuccessStatus.Builder"
+ *
+ * override val additionalProperties: Map<String, Any?>
+ * get() = mapOf("foo" to foo, "bars" to bars)
+ *
+ * override fun buildFromSuccessStatus(
+ * successStatus: SuccessStatus
+ * ): MySuccessStatus {
+ * return MySuccessStatus(
+ * successStatus,
+ * foo,
+ * bars.toList()
+ * )
+ * }
+ *
+ * fun setFoo(string: String): Builder {
+ * return apply { foo = string }
+ * }
+ *
+ * fun addBar(int: Int): Builder {
+ * return apply { bars += int }
+ * }
+ *
+ * fun addBars(values: Iterable<Int>): Builder {
+ * return apply { bars += values }
+ * }
+ * }
+ * }
+ * ```
+ *
+ * Also see [AbstractSuccessStatus].
+ */
+ @Suppress("StaticFinalBuilder")
+ public abstract class Builder<
+ Self : Builder<Self, Built>, Built : AbstractSuccessStatus<Built, Self>> :
+ SuccessStatus.Builder<Self> {
+ /**
+ * Human readable name for the concrete [Self] class.
+ *
+ * Used in the [toString] output.
+ */
+ @get:Suppress("GetterOnBuilder") protected abstract val selfTypeName: String
+
+ /**
+ * The additional properties that exist on the concrete [Self] class.
+ *
+ * Used for equality comparison and computing the hash code.
+ */
+ @get:Suppress("GetterOnBuilder") protected abstract val additionalProperties: Map<String, Any?>
+
+ private var namespace: String? = null
+
+ private var disambiguatingDescription: DisambiguatingDescription? = null
+
+ private var identifier: String? = null
+
+ private var name: Name? = null
+
+ /**
+ * Builds a concrete [Built] instance, given a built [SuccessStatus].
+ *
+ * Subclasses should override this method to build a concrete [Built] instance that holds both
+ * the [SuccessStatus]-specific properties and the subclass specific [additionalProperties].
+ *
+ * See the sample code in the documentation of this class for more context.
+ */
+ @Suppress("BuilderSetStyle")
+ protected abstract fun buildFromSuccessStatus(successStatus: SuccessStatus): Built
+
+ public final override fun build(): Built =
+ buildFromSuccessStatus(
+ SuccessStatusImpl(namespace, disambiguatingDescription, identifier, name)
+ )
+
+ public final override fun setNamespace(namespace: String?): Self {
+ this.namespace = namespace
+ return this as Self
+ }
+
+ public final override fun setDisambiguatingDescription(
+ disambiguatingDescription: DisambiguatingDescription?
+ ): Self {
+ this.disambiguatingDescription = disambiguatingDescription
+ return this as Self
+ }
+
+ public final override fun setIdentifier(text: String?): Self {
+ this.identifier = text
+ return this as Self
+ }
+
+ public final override fun setName(name: Name?): Self {
+ this.name = name
+ return this as Self
+ }
+
+ @Suppress("BuilderSetStyle")
+ public final override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class.java != other::class.java) return false
+ other as Self
+ if (disambiguatingDescription != other.disambiguatingDescription) return false
+ if (identifier != other.identifier) return false
+ if (name != other.name) return false
+ if (namespace != other.namespace) return false
+ if (additionalProperties != other.additionalProperties) return false
+ return true
+ }
+
+ @Suppress("BuilderSetStyle")
+ public final override fun hashCode(): Int =
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
+
+ @Suppress("BuilderSetStyle")
+ public final override fun toString(): String {
+ val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace!!
+ }
+ if (disambiguatingDescription != null) {
+ attributes["disambiguatingDescription"] =
+ disambiguatingDescription!!.toString(includeWrapperName = false)
+ }
+ if (identifier != null) {
+ attributes["identifier"] = identifier!!
+ }
+ if (name != null) {
+ attributes["name"] = name!!.toString(includeWrapperName = false)
+ }
+ attributes += additionalProperties.map { (k, v) -> k to v.toString() }
+ val commaSeparated =
+ attributes.entries.joinToString(separator = ", ") { (k, v) -> """$k=$v""" }
+ return """$selfTypeName($commaSeparated)"""
+ }
+ }
+}
+
+private class SuccessStatusImpl :
+ AbstractSuccessStatus<SuccessStatusImpl, SuccessStatusImpl.Builder> {
+ protected override val selfTypeName: String
+ get() = "SuccessStatus"
+
+ protected override val additionalProperties: Map<String, Any?>
+ get() = emptyMap()
+
+ public constructor(
+ namespace: String?,
+ disambiguatingDescription: DisambiguatingDescription?,
+ identifier: String?,
+ name: Name?,
+ ) : super(namespace, disambiguatingDescription, identifier, name)
+
+ public constructor(successStatus: SuccessStatus) : super(successStatus)
+
+ protected override fun toBuilderWithAdditionalPropertiesOnly(): Builder = Builder()
+
+ public class Builder : AbstractSuccessStatus.Builder<Builder, SuccessStatusImpl>() {
+ protected override val selfTypeName: String
+ get() = "SuccessStatus.Builder"
+
+ protected override val additionalProperties: Map<String, Any?>
+ get() = emptyMap()
+
+ protected override fun buildFromSuccessStatus(successStatus: SuccessStatus): SuccessStatusImpl =
+ successStatus as? SuccessStatusImpl ?: SuccessStatusImpl(successStatus)
+ }
+}
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Thing.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Thing.kt
index 3080c42..feb6dda 100644
--- a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Thing.kt
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Thing.kt
@@ -35,23 +35,34 @@
* See http://schema.org/Thing for context.
*
* Should not be directly implemented. More properties may be added over time. Instead consider
- * using [Companion.Builder] or see [GenericThing] if you need to extend this type.
+ * using [Companion.Builder] or see [AbstractThing] if you need to extend this type.
*/
public interface Thing {
+ /** Represents the AppSearch document's namespace. */
+ public val namespace: String?
+
/**
* A sub property of description. A short description of the item used to disambiguate from other,
* similar items. Information from other properties (in particular, name) may be necessary for the
* description to be useful for disambiguation.
+ *
+ * See http://schema.org/disambiguatingDescription for more context.
*/
public val disambiguatingDescription: DisambiguatingDescription?
/**
* The identifier property represents any kind of identifier for any kind of Thing, such as ISBNs,
* GTIN codes, UUIDs etc.
+ *
+ * See http://schema.org/identifier for more context.
*/
public val identifier: String?
- /** The name of the item. */
+ /**
+ * The name of the item.
+ *
+ * See http://schema.org/name for more context.
+ */
public val name: Name?
/** Converts this [Thing] to its builder with all the properties copied over. */
@@ -66,13 +77,15 @@
* Builder for [Thing].
*
* Should not be directly implemented. More methods may be added over time. See
- * [GenericThing.Builder] if you need to extend this builder.
+ * [AbstractThing.Builder] if you need to extend this builder.
*/
@Suppress("StaticFinalBuilder")
public interface Builder<Self : Builder<Self>> {
/** Returns a built [Thing]. */
public fun build(): Thing
+ public fun setNamespace(namespace: String?): Self
+
/** Sets the `disambiguatingDescription` to [String]. */
public fun setDisambiguatingDescription(text: String): Self =
setDisambiguatingDescription(DisambiguatingDescription(text))
@@ -94,7 +107,7 @@
}
/**
- * A generic implementation of [Thing].
+ * An abstract implementation of [Thing].
*
* Allows for extension like:
* ```kt
@@ -102,7 +115,7 @@
* thing: Thing,
* val foo: String,
* val bars: List<Int>,
- * ) : GenericThing<
+ * ) : AbstractThing<
* MyThing,
* MyThing.Builder
* >(thing) {
@@ -120,18 +133,19 @@
* }
*
* class Builder :
- * GenericThing.Builder<
+ * AbstractThing.Builder<
* Builder,
* MyThing> {...}
* }
* ```
*
- * Also see [GenericThing.Builder].
+ * Also see [AbstractThing.Builder].
*/
@Suppress("UNCHECKED_CAST")
-public abstract class GenericThing<
- Self : GenericThing<Self, Builder>, Builder : GenericThing.Builder<Builder, Self>>
+public abstract class AbstractThing<
+ Self : AbstractThing<Self, Builder>, Builder : AbstractThing.Builder<Builder, Self>>
internal constructor(
+ public final override val namespace: String?,
public final override val disambiguatingDescription: DisambiguatingDescription?,
public final override val identifier: String?,
public final override val name: Name?,
@@ -153,13 +167,14 @@
/** A copy-constructor that copies over properties from another [Thing] instance. */
public constructor(
thing: Thing
- ) : this(thing.disambiguatingDescription, thing.identifier, thing.name)
+ ) : this(thing.namespace, thing.disambiguatingDescription, thing.identifier, thing.name)
/** Returns a concrete [Builder] with the additional, non-[Thing] properties copied over. */
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
public final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
+ .setNamespace(namespace)
.setDisambiguatingDescription(disambiguatingDescription)
.setIdentifier(identifier)
.setName(name)
@@ -171,15 +186,19 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
public final override fun hashCode(): Int =
- Objects.hash(disambiguatingDescription, identifier, name, additionalProperties)
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace
+ }
if (disambiguatingDescription != null) {
attributes["disambiguatingDescription"] =
disambiguatingDescription.toString(includeWrapperName = false)
@@ -196,12 +215,12 @@
}
/**
- * A generic implementation of [Thing.Builder].
+ * An abstract implementation of [Thing.Builder].
*
* Allows for extension like:
* ```kt
* class MyThing :
- * : GenericThing<
+ * : AbstractThing<
* MyThing,
* MyThing.Builder>(...) {
*
@@ -244,10 +263,10 @@
* }
* ```
*
- * Also see [GenericThing].
+ * Also see [AbstractThing].
*/
@Suppress("StaticFinalBuilder")
- public abstract class Builder<Self : Builder<Self, Built>, Built : GenericThing<Built, Self>> :
+ public abstract class Builder<Self : Builder<Self, Built>, Built : AbstractThing<Built, Self>> :
Thing.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
@@ -263,6 +282,8 @@
*/
@get:Suppress("GetterOnBuilder") protected abstract val additionalProperties: Map<String, Any?>
+ private var namespace: String? = null
+
private var disambiguatingDescription: DisambiguatingDescription? = null
private var identifier: String? = null
@@ -280,7 +301,12 @@
@Suppress("BuilderSetStyle") protected abstract fun buildFromThing(thing: Thing): Built
public final override fun build(): Built =
- buildFromThing(ThingImpl(disambiguatingDescription, identifier, name))
+ buildFromThing(ThingImpl(namespace, disambiguatingDescription, identifier, name))
+
+ public final override fun setNamespace(namespace: String?): Self {
+ this.namespace = namespace
+ return this as Self
+ }
public final override fun setDisambiguatingDescription(
disambiguatingDescription: DisambiguatingDescription?
@@ -307,17 +333,21 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
@Suppress("BuilderSetStyle")
public final override fun hashCode(): Int =
- Objects.hash(disambiguatingDescription, identifier, name, additionalProperties)
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
@Suppress("BuilderSetStyle")
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace!!
+ }
if (disambiguatingDescription != null) {
attributes["disambiguatingDescription"] =
disambiguatingDescription!!.toString(includeWrapperName = false)
@@ -336,7 +366,7 @@
}
}
-internal class ThingImpl : GenericThing<ThingImpl, ThingImpl.Builder> {
+private class ThingImpl : AbstractThing<ThingImpl, ThingImpl.Builder> {
protected override val selfTypeName: String
get() = "Thing"
@@ -344,16 +374,17 @@
get() = emptyMap()
public constructor(
+ namespace: String?,
disambiguatingDescription: DisambiguatingDescription?,
identifier: String?,
name: Name?,
- ) : super(disambiguatingDescription, identifier, name)
+ ) : super(namespace, disambiguatingDescription, identifier, name)
public constructor(thing: Thing) : super(thing)
protected override fun toBuilderWithAdditionalPropertiesOnly(): Builder = Builder()
- internal class Builder : GenericThing.Builder<Builder, ThingImpl>() {
+ public class Builder : AbstractThing.Builder<Builder, ThingImpl>() {
protected override val selfTypeName: String
get() = "Thing.Builder"
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Timer.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Timer.kt
index b9d5de4..bbbc685 100644
--- a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Timer.kt
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/Timer.kt
@@ -36,10 +36,14 @@
* See http://schema.googleapis.com/Timer for context.
*
* Should not be directly implemented. More properties may be added over time. Instead consider
- * using [Companion.Builder] or see [GenericTimer] if you need to extend this type.
+ * using [Companion.Builder] or see [AbstractTimer] if you need to extend this type.
*/
public interface Timer : Thing {
- /** The duration of the item (movie, audio recording, event, etc.). */
+ /**
+ * The duration of the item (movie, audio recording, event, etc.).
+ *
+ * See http://schema.org/duration for more context.
+ */
public val duration: Duration?
/** Converts this [Timer] to its builder with all the properties copied over. */
@@ -54,7 +58,7 @@
* Builder for [Timer].
*
* Should not be directly implemented. More methods may be added over time. See
- * [GenericTimer.Builder] if you need to extend this builder.
+ * [AbstractTimer.Builder] if you need to extend this builder.
*/
public interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
/** Returns a built [Timer]. */
@@ -66,7 +70,7 @@
}
/**
- * A generic implementation of [Timer].
+ * An abstract implementation of [Timer].
*
* Allows for extension like:
* ```kt
@@ -74,7 +78,7 @@
* timer: Timer,
* val foo: String,
* val bars: List<Int>,
- * ) : GenericTimer<
+ * ) : AbstractTimer<
* MyTimer,
* MyTimer.Builder
* >(timer) {
@@ -92,18 +96,19 @@
* }
*
* class Builder :
- * GenericTimer.Builder<
+ * AbstractTimer.Builder<
* Builder,
* MyTimer> {...}
* }
* ```
*
- * Also see [GenericTimer.Builder].
+ * Also see [AbstractTimer.Builder].
*/
@Suppress("UNCHECKED_CAST")
-public abstract class GenericTimer<
- Self : GenericTimer<Self, Builder>, Builder : GenericTimer.Builder<Builder, Self>>
+public abstract class AbstractTimer<
+ Self : AbstractTimer<Self, Builder>, Builder : AbstractTimer.Builder<Builder, Self>>
internal constructor(
+ public final override val namespace: String?,
public final override val duration: Duration?,
public final override val disambiguatingDescription: DisambiguatingDescription?,
public final override val identifier: String?,
@@ -126,13 +131,20 @@
/** A copy-constructor that copies over properties from another [Timer] instance. */
public constructor(
timer: Timer
- ) : this(timer.duration, timer.disambiguatingDescription, timer.identifier, timer.name)
+ ) : this(
+ timer.namespace,
+ timer.duration,
+ timer.disambiguatingDescription,
+ timer.identifier,
+ timer.name
+ )
/** Returns a concrete [Builder] with the additional, non-[Timer] properties copied over. */
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
public final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
+ .setNamespace(namespace)
.setDuration(duration)
.setDisambiguatingDescription(disambiguatingDescription)
.setIdentifier(identifier)
@@ -146,15 +158,26 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
public final override fun hashCode(): Int =
- Objects.hash(duration, disambiguatingDescription, identifier, name, additionalProperties)
+ Objects.hash(
+ duration,
+ disambiguatingDescription,
+ identifier,
+ name,
+ namespace,
+ additionalProperties
+ )
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace
+ }
if (duration != null) {
attributes["duration"] = duration.toString()
}
@@ -174,12 +197,12 @@
}
/**
- * A generic implementation of [Timer.Builder].
+ * An abstract implementation of [Timer.Builder].
*
* Allows for extension like:
* ```kt
* class MyTimer :
- * : GenericTimer<
+ * : AbstractTimer<
* MyTimer,
* MyTimer.Builder>(...) {
*
@@ -222,10 +245,10 @@
* }
* ```
*
- * Also see [GenericTimer].
+ * Also see [AbstractTimer].
*/
@Suppress("StaticFinalBuilder")
- public abstract class Builder<Self : Builder<Self, Built>, Built : GenericTimer<Built, Self>> :
+ public abstract class Builder<Self : Builder<Self, Built>, Built : AbstractTimer<Built, Self>> :
Timer.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
@@ -241,6 +264,8 @@
*/
@get:Suppress("GetterOnBuilder") protected abstract val additionalProperties: Map<String, Any?>
+ private var namespace: String? = null
+
private var duration: Duration? = null
private var disambiguatingDescription: DisambiguatingDescription? = null
@@ -260,7 +285,12 @@
@Suppress("BuilderSetStyle") protected abstract fun buildFromTimer(timer: Timer): Built
public final override fun build(): Built =
- buildFromTimer(TimerImpl(duration, disambiguatingDescription, identifier, name))
+ buildFromTimer(TimerImpl(namespace, duration, disambiguatingDescription, identifier, name))
+
+ public final override fun setNamespace(namespace: String?): Self {
+ this.namespace = namespace
+ return this as Self
+ }
public final override fun setDuration(duration: Duration?): Self {
this.duration = duration
@@ -293,17 +323,28 @@
if (disambiguatingDescription != other.disambiguatingDescription) return false
if (identifier != other.identifier) return false
if (name != other.name) return false
+ if (namespace != other.namespace) return false
if (additionalProperties != other.additionalProperties) return false
return true
}
@Suppress("BuilderSetStyle")
public final override fun hashCode(): Int =
- Objects.hash(duration, disambiguatingDescription, identifier, name, additionalProperties)
+ Objects.hash(
+ duration,
+ disambiguatingDescription,
+ identifier,
+ name,
+ namespace,
+ additionalProperties
+ )
@Suppress("BuilderSetStyle")
public final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace!!
+ }
if (duration != null) {
attributes["duration"] = duration!!.toString()
}
@@ -325,7 +366,7 @@
}
}
-internal class TimerImpl : GenericTimer<TimerImpl, TimerImpl.Builder> {
+private class TimerImpl : AbstractTimer<TimerImpl, TimerImpl.Builder> {
protected override val selfTypeName: String
get() = "Timer"
@@ -333,17 +374,18 @@
get() = emptyMap()
public constructor(
+ namespace: String?,
duration: Duration?,
disambiguatingDescription: DisambiguatingDescription?,
identifier: String?,
name: Name?,
- ) : super(duration, disambiguatingDescription, identifier, name)
+ ) : super(namespace, duration, disambiguatingDescription, identifier, name)
public constructor(timer: Timer) : super(timer)
protected override fun toBuilderWithAdditionalPropertiesOnly(): Builder = Builder()
- internal class Builder : GenericTimer.Builder<Builder, TimerImpl>() {
+ public class Builder : AbstractTimer.Builder<Builder, TimerImpl>() {
protected override val selfTypeName: String
get() = "Timer.Builder"
diff --git a/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/UnsupportedOperationStatus.kt b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/UnsupportedOperationStatus.kt
new file mode 100644
index 0000000..547ea02
--- /dev/null
+++ b/appactions/builtintypes/builtintypes-core/src/main/java/androidx/appactions/builtintypes/types/UnsupportedOperationStatus.kt
@@ -0,0 +1,380 @@
+// 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.appactions.builtintypes.types
+
+import androidx.appactions.builtintypes.properties.DisambiguatingDescription
+import androidx.appactions.builtintypes.properties.Name
+import java.util.Objects
+import kotlin.Any
+import kotlin.Boolean
+import kotlin.Int
+import kotlin.String
+import kotlin.Suppress
+import kotlin.collections.Map
+import kotlin.collections.emptyMap
+import kotlin.collections.joinToString
+import kotlin.collections.map
+import kotlin.collections.mutableMapOf
+import kotlin.collections.plusAssign
+import kotlin.jvm.JvmStatic
+
+/**
+ * Status indicating that the operation is not supported, e.g. updating an unsupported field.
+ *
+ * See http://schema.googleapis.com/UnsupportedOperationStatus for context.
+ *
+ * Should not be directly implemented. More properties may be added over time. Instead consider
+ * using [Companion.Builder] or see [AbstractUnsupportedOperationStatus] if you need to extend this
+ * type.
+ */
+public interface UnsupportedOperationStatus : ExecutionStatus {
+ /**
+ * Converts this [UnsupportedOperationStatus] to its builder with all the properties copied over.
+ */
+ public override fun toBuilder(): Builder<*>
+
+ public companion object {
+ /** Returns a default implementation of [Builder] with no properties set. */
+ @JvmStatic public fun Builder(): Builder<*> = UnsupportedOperationStatusImpl.Builder()
+ }
+
+ /**
+ * Builder for [UnsupportedOperationStatus].
+ *
+ * Should not be directly implemented. More methods may be added over time. See
+ * [AbstractUnsupportedOperationStatus.Builder] if you need to extend this builder.
+ */
+ public interface Builder<Self : Builder<Self>> : ExecutionStatus.Builder<Self> {
+ /** Returns a built [UnsupportedOperationStatus]. */
+ public override fun build(): UnsupportedOperationStatus
+ }
+}
+
+/**
+ * An abstract implementation of [UnsupportedOperationStatus].
+ *
+ * Allows for extension like:
+ * ```kt
+ * class MyUnsupportedOperationStatus internal constructor(
+ * unsupportedOperationStatus: UnsupportedOperationStatus,
+ * val foo: String,
+ * val bars: List<Int>,
+ * ) : AbstractUnsupportedOperationStatus<
+ * MyUnsupportedOperationStatus,
+ * MyUnsupportedOperationStatus.Builder
+ * >(unsupportedOperationStatus) {
+ *
+ * override val selfTypeName =
+ * "MyUnsupportedOperationStatus"
+ *
+ * override val additionalProperties: Map<String, Any?>
+ * get() = mapOf("foo" to foo, "bars" to bars)
+ *
+ * override fun toBuilderWithAdditionalPropertiesOnly(): Builder {
+ * return Builder()
+ * .setFoo(foo)
+ * .addBars(bars)
+ * }
+ *
+ * class Builder :
+ * AbstractUnsupportedOperationStatus.Builder<
+ * Builder,
+ * MyUnsupportedOperationStatus> {...}
+ * }
+ * ```
+ *
+ * Also see [AbstractUnsupportedOperationStatus.Builder].
+ */
+@Suppress("UNCHECKED_CAST")
+public abstract class AbstractUnsupportedOperationStatus<
+ Self : AbstractUnsupportedOperationStatus<Self, Builder>,
+ Builder : AbstractUnsupportedOperationStatus.Builder<Builder, Self>>
+internal constructor(
+ public final override val namespace: String?,
+ public final override val disambiguatingDescription: DisambiguatingDescription?,
+ public final override val identifier: String?,
+ public final override val name: Name?,
+) : UnsupportedOperationStatus {
+ /**
+ * Human readable name for the concrete [Self] class.
+ *
+ * Used in the [toString] output.
+ */
+ protected abstract val selfTypeName: String
+
+ /**
+ * The additional properties that exist on the concrete [Self] class.
+ *
+ * Used for equality comparison and computing the hash code.
+ */
+ protected abstract val additionalProperties: Map<String, Any?>
+
+ /**
+ * A copy-constructor that copies over properties from another [UnsupportedOperationStatus]
+ * instance.
+ */
+ public constructor(
+ unsupportedOperationStatus: UnsupportedOperationStatus
+ ) : this(
+ unsupportedOperationStatus.namespace,
+ unsupportedOperationStatus.disambiguatingDescription,
+ unsupportedOperationStatus.identifier,
+ unsupportedOperationStatus.name
+ )
+
+ /**
+ * Returns a concrete [Builder] with the additional, non-[UnsupportedOperationStatus] properties
+ * copied over.
+ */
+ protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
+
+ public final override fun toBuilder(): Builder =
+ toBuilderWithAdditionalPropertiesOnly()
+ .setNamespace(namespace)
+ .setDisambiguatingDescription(disambiguatingDescription)
+ .setIdentifier(identifier)
+ .setName(name)
+
+ public final override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class.java != other::class.java) return false
+ other as Self
+ if (disambiguatingDescription != other.disambiguatingDescription) return false
+ if (identifier != other.identifier) return false
+ if (name != other.name) return false
+ if (namespace != other.namespace) return false
+ if (additionalProperties != other.additionalProperties) return false
+ return true
+ }
+
+ public final override fun hashCode(): Int =
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
+
+ public final override fun toString(): String {
+ val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace
+ }
+ if (disambiguatingDescription != null) {
+ attributes["disambiguatingDescription"] =
+ disambiguatingDescription.toString(includeWrapperName = false)
+ }
+ if (identifier != null) {
+ attributes["identifier"] = identifier
+ }
+ if (name != null) {
+ attributes["name"] = name.toString(includeWrapperName = false)
+ }
+ attributes += additionalProperties.map { (k, v) -> k to v.toString() }
+ val commaSeparated = attributes.entries.joinToString(separator = ", ") { (k, v) -> """$k=$v""" }
+ return """$selfTypeName($commaSeparated)"""
+ }
+
+ /**
+ * An abstract implementation of [UnsupportedOperationStatus.Builder].
+ *
+ * Allows for extension like:
+ * ```kt
+ * class MyUnsupportedOperationStatus :
+ * : AbstractUnsupportedOperationStatus<
+ * MyUnsupportedOperationStatus,
+ * MyUnsupportedOperationStatus.Builder>(...) {
+ *
+ * class Builder
+ * : Builder<
+ * Builder,
+ * MyUnsupportedOperationStatus
+ * >() {
+ * private var foo: String? = null
+ * private val bars = mutableListOf<Int>()
+ *
+ * override val selfTypeName =
+ * "MyUnsupportedOperationStatus.Builder"
+ *
+ * override val additionalProperties: Map<String, Any?>
+ * get() = mapOf("foo" to foo, "bars" to bars)
+ *
+ * override fun buildFromUnsupportedOperationStatus(
+ * unsupportedOperationStatus: UnsupportedOperationStatus
+ * ): MyUnsupportedOperationStatus {
+ * return MyUnsupportedOperationStatus(
+ * unsupportedOperationStatus,
+ * foo,
+ * bars.toList()
+ * )
+ * }
+ *
+ * fun setFoo(string: String): Builder {
+ * return apply { foo = string }
+ * }
+ *
+ * fun addBar(int: Int): Builder {
+ * return apply { bars += int }
+ * }
+ *
+ * fun addBars(values: Iterable<Int>): Builder {
+ * return apply { bars += values }
+ * }
+ * }
+ * }
+ * ```
+ *
+ * Also see [AbstractUnsupportedOperationStatus].
+ */
+ @Suppress("StaticFinalBuilder")
+ public abstract class Builder<
+ Self : Builder<Self, Built>, Built : AbstractUnsupportedOperationStatus<Built, Self>> :
+ UnsupportedOperationStatus.Builder<Self> {
+ /**
+ * Human readable name for the concrete [Self] class.
+ *
+ * Used in the [toString] output.
+ */
+ @get:Suppress("GetterOnBuilder") protected abstract val selfTypeName: String
+
+ /**
+ * The additional properties that exist on the concrete [Self] class.
+ *
+ * Used for equality comparison and computing the hash code.
+ */
+ @get:Suppress("GetterOnBuilder") protected abstract val additionalProperties: Map<String, Any?>
+
+ private var namespace: String? = null
+
+ private var disambiguatingDescription: DisambiguatingDescription? = null
+
+ private var identifier: String? = null
+
+ private var name: Name? = null
+
+ /**
+ * Builds a concrete [Built] instance, given a built [UnsupportedOperationStatus].
+ *
+ * Subclasses should override this method to build a concrete [Built] instance that holds both
+ * the [UnsupportedOperationStatus]-specific properties and the subclass specific
+ * [additionalProperties].
+ *
+ * See the sample code in the documentation of this class for more context.
+ */
+ @Suppress("BuilderSetStyle")
+ protected abstract fun buildFromUnsupportedOperationStatus(
+ unsupportedOperationStatus: UnsupportedOperationStatus
+ ): Built
+
+ public final override fun build(): Built =
+ buildFromUnsupportedOperationStatus(
+ UnsupportedOperationStatusImpl(namespace, disambiguatingDescription, identifier, name)
+ )
+
+ public final override fun setNamespace(namespace: String?): Self {
+ this.namespace = namespace
+ return this as Self
+ }
+
+ public final override fun setDisambiguatingDescription(
+ disambiguatingDescription: DisambiguatingDescription?
+ ): Self {
+ this.disambiguatingDescription = disambiguatingDescription
+ return this as Self
+ }
+
+ public final override fun setIdentifier(text: String?): Self {
+ this.identifier = text
+ return this as Self
+ }
+
+ public final override fun setName(name: Name?): Self {
+ this.name = name
+ return this as Self
+ }
+
+ @Suppress("BuilderSetStyle")
+ public final override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class.java != other::class.java) return false
+ other as Self
+ if (disambiguatingDescription != other.disambiguatingDescription) return false
+ if (identifier != other.identifier) return false
+ if (name != other.name) return false
+ if (namespace != other.namespace) return false
+ if (additionalProperties != other.additionalProperties) return false
+ return true
+ }
+
+ @Suppress("BuilderSetStyle")
+ public final override fun hashCode(): Int =
+ Objects.hash(disambiguatingDescription, identifier, name, namespace, additionalProperties)
+
+ @Suppress("BuilderSetStyle")
+ public final override fun toString(): String {
+ val attributes = mutableMapOf<String, String>()
+ if (namespace != null) {
+ attributes["namespace"] = namespace!!
+ }
+ if (disambiguatingDescription != null) {
+ attributes["disambiguatingDescription"] =
+ disambiguatingDescription!!.toString(includeWrapperName = false)
+ }
+ if (identifier != null) {
+ attributes["identifier"] = identifier!!
+ }
+ if (name != null) {
+ attributes["name"] = name!!.toString(includeWrapperName = false)
+ }
+ attributes += additionalProperties.map { (k, v) -> k to v.toString() }
+ val commaSeparated =
+ attributes.entries.joinToString(separator = ", ") { (k, v) -> """$k=$v""" }
+ return """$selfTypeName($commaSeparated)"""
+ }
+ }
+}
+
+private class UnsupportedOperationStatusImpl :
+ AbstractUnsupportedOperationStatus<
+ UnsupportedOperationStatusImpl, UnsupportedOperationStatusImpl.Builder
+ > {
+ protected override val selfTypeName: String
+ get() = "UnsupportedOperationStatus"
+
+ protected override val additionalProperties: Map<String, Any?>
+ get() = emptyMap()
+
+ public constructor(
+ namespace: String?,
+ disambiguatingDescription: DisambiguatingDescription?,
+ identifier: String?,
+ name: Name?,
+ ) : super(namespace, disambiguatingDescription, identifier, name)
+
+ public constructor(
+ unsupportedOperationStatus: UnsupportedOperationStatus
+ ) : super(unsupportedOperationStatus)
+
+ protected override fun toBuilderWithAdditionalPropertiesOnly(): Builder = Builder()
+
+ public class Builder :
+ AbstractUnsupportedOperationStatus.Builder<Builder, UnsupportedOperationStatusImpl>() {
+ protected override val selfTypeName: String
+ get() = "UnsupportedOperationStatus.Builder"
+
+ protected override val additionalProperties: Map<String, Any?>
+ get() = emptyMap()
+
+ protected override fun buildFromUnsupportedOperationStatus(
+ unsupportedOperationStatus: UnsupportedOperationStatus
+ ): UnsupportedOperationStatusImpl =
+ unsupportedOperationStatus as? UnsupportedOperationStatusImpl
+ ?: UnsupportedOperationStatusImpl(unsupportedOperationStatus)
+ }
+}
diff --git a/appactions/builtintypes/builtintypes-core/src/test/java/androidx/appactions/builtintypes/types/ExtensionTest.kt b/appactions/builtintypes/builtintypes-core/src/test/java/androidx/appactions/builtintypes/types/ExtensionTest.kt
index 87ed941..56ae906 100644
--- a/appactions/builtintypes/builtintypes-core/src/test/java/androidx/appactions/builtintypes/types/ExtensionTest.kt
+++ b/appactions/builtintypes/builtintypes-core/src/test/java/androidx/appactions/builtintypes/types/ExtensionTest.kt
@@ -25,7 +25,7 @@
class ExtensionTest {
class MyThing internal constructor(thing: Thing, val foo: String?, val bars: List<Int>) :
- GenericThing<MyThing, MyThing.Builder>(thing) {
+ AbstractThing<MyThing, MyThing.Builder>(thing) {
override val selfTypeName = "MyThing"
override val additionalProperties: Map<String, Any?>
get() = mapOf("foo" to foo, "bars" to bars)
@@ -34,7 +34,7 @@
return Builder().setFoo(foo).addBars(bars)
}
- class Builder : GenericThing.Builder<Builder, MyThing>() {
+ class Builder : AbstractThing.Builder<Builder, MyThing>() {
private var foo: String? = null
private val bars: MutableList<Int> = mutableListOf()
diff --git a/appactions/interaction/integration-tests/testapp/build.gradle b/appactions/interaction/integration-tests/testapp/build.gradle
index eb817cc..b5834ae 100644
--- a/appactions/interaction/integration-tests/testapp/build.gradle
+++ b/appactions/interaction/integration-tests/testapp/build.gradle
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import androidx.build.Publish
plugins {
@@ -32,6 +31,8 @@
dependencies {
implementation(project(":appactions:interaction:interaction-service"))
+ implementation(project(":appactions:interaction:interaction-capabilities-core"))
+ implementation(project(":appactions:interaction:interaction-capabilities-productivity"))
implementation("androidx.core:core-ktx:1.7.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.6.0")
diff --git a/appactions/interaction/integration-tests/testapp/src/main/AndroidManifest.xml b/appactions/interaction/integration-tests/testapp/src/main/AndroidManifest.xml
index 0ad13f3..dcf7181 100644
--- a/appactions/interaction/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/appactions/interaction/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -32,15 +32,22 @@
android:name=".MainActivity"
android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
+ <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER"/>
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
-
- <meta-data
- android:name="android.app.lib_name"
- android:value=""/>
</activity>
+ <!-- Register as Android Service -->
+ <service
+ android:name=".ClockInteractionService"
+ android:exported="true">
+ <!-- Link shortcuts.xml to register capabilities -->
+ <meta-data
+ android:name="android.app.shortcuts"
+ android:resource="@xml/shortcuts" />
+ <intent-filter>
+ <action android:name="grpc.io.action.BIND" />
+ </intent-filter>
+ </service>
</application>
-
</manifest>
\ No newline at end of file
diff --git a/appactions/interaction/integration-tests/testapp/src/main/java/androidx/appactions/interaction/testapp/ClockInteractionService.kt b/appactions/interaction/integration-tests/testapp/src/main/java/androidx/appactions/interaction/testapp/ClockInteractionService.kt
new file mode 100644
index 0000000..b52f632
--- /dev/null
+++ b/appactions/interaction/integration-tests/testapp/src/main/java/androidx/appactions/interaction/testapp/ClockInteractionService.kt
@@ -0,0 +1,71 @@
+/*
+ * 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.appactions.interaction.testapp
+
+import android.os.Handler
+import android.os.Looper
+import android.widget.Toast
+import androidx.appactions.interaction.capabilities.core.Capability
+import androidx.appactions.interaction.capabilities.core.ExecutionCallback
+import androidx.appactions.interaction.capabilities.core.ExecutionResult
+import androidx.appactions.interaction.capabilities.core.properties.Property
+import androidx.appactions.interaction.capabilities.productivity.StartTimer
+import androidx.appactions.interaction.service.AppInteractionService
+import androidx.appactions.interaction.service.AppVerificationInfo
+import java.time.Duration
+
+class ClockInteractionService : AppInteractionService() {
+
+ lateinit var mHandler: Handler
+ override fun onCreate() {
+ super.onCreate()
+ mHandler = Handler(Looper.myLooper()!!)
+ }
+
+ private fun showToast(msg: String) {
+ mHandler.post(Runnable {
+ Toast.makeText(
+ this@ClockInteractionService,
+ msg,
+ Toast.LENGTH_LONG
+ ).show()
+ })
+ }
+
+ private val capability =
+ StartTimer.CapabilityBuilder()
+ .setId("start_timer_oneshot")
+ .setDurationProperty(Property.Builder<Duration>().setRequired(true).build())
+ .setExecutionCallback(ExecutionCallback<StartTimer.Arguments, StartTimer.Output> {
+ val name = it.name ?: "Default title"
+ val duration = it.duration!!
+
+ // Do execution. ie. create the Timer called $name for $duration
+ showToast(msg = "Name:$name Duration:$duration")
+
+ ExecutionResult.Builder<StartTimer.Output>().build()
+ })
+ .build()
+
+ override val registeredCapabilities: List<Capability> = listOf(capability)
+ override val allowedApps: List<AppVerificationInfo> = listOf(
+ AppVerificationInfo.Builder()
+ .addSignature(hex2Byte(ASSISTANT_SIGNATURE))
+ .setPackageName(ASSISTANT_PACKAGE)
+ .build()
+ )
+}
\ No newline at end of file
diff --git a/appactions/interaction/integration-tests/testapp/src/main/java/androidx/appactions/interaction/testapp/Signatures.kt b/appactions/interaction/integration-tests/testapp/src/main/java/androidx/appactions/interaction/testapp/Signatures.kt
new file mode 100644
index 0000000..18c3b0a
--- /dev/null
+++ b/appactions/interaction/integration-tests/testapp/src/main/java/androidx/appactions/interaction/testapp/Signatures.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.
+ */
+
+package androidx.appactions.interaction.testapp
+
+internal const val ASSISTANT_PACKAGE = "com.google.android.googlequicksearchbox"
+internal const val ASSISTANT_SIGNATURE =
+ "f0:fd:6c:5b:41:0f:25:cb:25:c3:b5:33:46:c8:97:2f:ae:30:f8:ee:74:11:df:91:04:80:ad:" +
+ "6b:2d:60:db:83"
+
+internal fun hex2Byte(s: String): ByteArray {
+ val parts = s.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+ val result = ByteArray(parts.size)
+ for (i in parts.indices) {
+ result[i] = parts[i].toInt(16).toByte()
+ }
+ return result
+}
\ No newline at end of file
diff --git a/appactions/interaction/integration-tests/testapp/src/main/res/xml/shortcuts.xml b/appactions/interaction/integration-tests/testapp/src/main/res/xml/shortcuts.xml
new file mode 100644
index 0000000..446ce53b
--- /dev/null
+++ b/appactions/interaction/integration-tests/testapp/src/main/res/xml/shortcuts.xml
@@ -0,0 +1,34 @@
+<?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.
+ -->
+
+<!-- file: res/xml/shortcuts.xml -->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
+ <capability android:name="actions.intent.START_TIMER">
+ <service
+ android:name="androidx.appactions.interaction.testapp.ClockInteractionService"
+ android:identifier="start_timer_oneshot">
+ <parameter
+ android:name="timer.identifier"
+ android:key="timer.identifier" />
+ <parameter
+ android:name="timer.name"
+ android:key="timer.name" />
+ <parameter
+ android:name="timer.duration"
+ android:key="timer.duration" />
+ </service>
+ </capability>
+</shortcuts>
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateCall.kt b/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateCall.kt
index 8fdbdc0..3dcabbf 100644
--- a/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateCall.kt
+++ b/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateCall.kt
@@ -40,7 +40,7 @@
/** A capability corresponding to actions.intent.CREATE_CALL */
@CapabilityFactory(name = CAPABILITY_NAME)
class CreateCall private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
+ internal enum class SlotMetadata(val path: String) {
CALL_FORMAT("call.callFormat"),
PARTICIPANT("call.participant")
}
@@ -50,17 +50,19 @@
CapabilityBuilder, Arguments, Output, Confirmation, ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
+ fun setCallFormatProperty(
+ callFormat: Property<Call.CanonicalValue.CallFormat>
+ ): CapabilityBuilder =
+ setProperty(
+ SlotMetadata.CALL_FORMAT.path,
+ callFormat,
+ TypeConverters.CALL_FORMAT_ENTITY_CONVERTER)
- fun setCallFormat(callFormat: Property<Call.CanonicalValue.CallFormat>): CapabilityBuilder =
- apply {
- properties[PropertyMapStrings.CALL_FORMAT.key] = callFormat
- }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setParticipantProperty(participant: Property<Participant>): CapabilityBuilder =
+ setProperty(
+ SlotMetadata.PARTICIPANT.path,
+ participant,
+ EntityConverter.of(PARTICIPANT_TYPE_SPEC))
}
class Arguments
@@ -177,29 +179,19 @@
sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
companion object {
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindParameter(
- "call.callFormat",
- { properties ->
- properties[PropertyMapStrings.CALL_FORMAT.key]
- as? Property<Call.CanonicalValue.CallFormat>
- },
+ SlotMetadata.CALL_FORMAT.path,
Arguments.Builder::setCallFormat,
- TypeConverters.CALL_FORMAT_PARAM_VALUE_CONVERTER,
- TypeConverters.CALL_FORMAT_ENTITY_CONVERTER
+ TypeConverters.CALL_FORMAT_PARAM_VALUE_CONVERTER
)
.bindRepeatedParameter(
- "call.participant",
- { properties ->
- properties[PropertyMapStrings.PARTICIPANT.key] as? Property<Participant>
- },
+ SlotMetadata.PARTICIPANT.path,
Arguments.Builder::setParticipantList,
ParticipantValue.PARAM_VALUE_CONVERTER,
- EntityConverter.of(PARTICIPANT_TYPE_SPEC)
)
.bindOutput(
"call",
diff --git a/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateMessage.kt b/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateMessage.kt
index b559a71..88f8c82 100644
--- a/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateMessage.kt
+++ b/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateMessage.kt
@@ -41,8 +41,8 @@
/** A capability corresponding to actions.intent.CREATE_MESSAGE */
@CapabilityFactory(name = CAPABILITY_NAME)
class CreateMessage private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
- MESSAGE_TEXT("message.text"),
+ internal enum class SlotMetadata(val path: String) {
+ TEXT("message.text"),
RECIPIENT("message.recipient")
}
@@ -50,21 +50,19 @@
Capability.Builder<
CapabilityBuilder, Arguments, Output, Confirmation, ExecutionSession
>(ACTION_SPEC) {
+ fun setMessageTextProperty(
+ messageText: Property<StringValue>
+ ): CapabilityBuilder = setProperty(
+ SlotMetadata.TEXT.path,
+ messageText,
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
- private var properties = mutableMapOf<String, Property<*>>()
-
- fun setMessageText(messageText: Property<StringValue>): CapabilityBuilder = apply {
- properties[PropertyMapStrings.MESSAGE_TEXT.key] = messageText
- }
-
- fun setRecipient(recipient: Property<Recipient>): CapabilityBuilder = apply {
- properties[PropertyMapStrings.RECIPIENT.key] = recipient
- }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setRecipientProperty(recipient: Property<Recipient>): CapabilityBuilder = setProperty(
+ SlotMetadata.RECIPIENT.path,
+ recipient,
+ EntityConverter.of(TypeConverters.RECIPIENT_TYPE_SPEC)
+ )
}
class Arguments
@@ -179,28 +177,19 @@
sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
companion object {
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindRepeatedParameter(
- "message.recipient",
- { properties ->
- properties[PropertyMapStrings.RECIPIENT.key] as? Property<Recipient>
- },
+ SlotMetadata.RECIPIENT.path,
Arguments.Builder::setRecipientList,
RecipientValue.PARAM_VALUE_CONVERTER,
- EntityConverter.of(RECIPIENT_TYPE_SPEC)
)
.bindParameter(
- "message.text",
- { properties ->
- properties[PropertyMapStrings.MESSAGE_TEXT.key] as? Property<StringValue>
- },
+ SlotMetadata.TEXT.path,
Arguments.Builder::setMessageText,
TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
)
.bindOutput(
"message",
diff --git a/appactions/interaction/interaction-capabilities-core/api/current.txt b/appactions/interaction/interaction-capabilities-core/api/current.txt
index 4045e23..e3b806d 100644
--- a/appactions/interaction/interaction-capabilities-core/api/current.txt
+++ b/appactions/interaction/interaction-capabilities-core/api/current.txt
@@ -17,7 +17,7 @@
method public androidx.appactions.interaction.capabilities.core.Capability build();
method public final BuilderT setExecutionCallback(androidx.appactions.interaction.capabilities.core.ExecutionCallback<ArgumentsT,OutputT> executionCallback);
method public final BuilderT setExecutionCallback(androidx.appactions.interaction.capabilities.core.ExecutionCallbackAsync<ArgumentsT,OutputT> executionCallbackAsync);
- method public BuilderT setExecutionSessionFactory(kotlin.jvm.functions.Function1<? super androidx.appactions.interaction.capabilities.core.HostProperties,? extends ExecutionSessionT> sessionFactory);
+ method protected BuilderT setExecutionSessionFactory(kotlin.jvm.functions.Function1<? super androidx.appactions.interaction.capabilities.core.HostProperties,? extends ExecutionSessionT> sessionFactory);
method public final BuilderT setId(String id);
}
diff --git a/appactions/interaction/interaction-capabilities-core/api/restricted_current.txt b/appactions/interaction/interaction-capabilities-core/api/restricted_current.txt
index 4045e23..e3b806d 100644
--- a/appactions/interaction/interaction-capabilities-core/api/restricted_current.txt
+++ b/appactions/interaction/interaction-capabilities-core/api/restricted_current.txt
@@ -17,7 +17,7 @@
method public androidx.appactions.interaction.capabilities.core.Capability build();
method public final BuilderT setExecutionCallback(androidx.appactions.interaction.capabilities.core.ExecutionCallback<ArgumentsT,OutputT> executionCallback);
method public final BuilderT setExecutionCallback(androidx.appactions.interaction.capabilities.core.ExecutionCallbackAsync<ArgumentsT,OutputT> executionCallbackAsync);
- method public BuilderT setExecutionSessionFactory(kotlin.jvm.functions.Function1<? super androidx.appactions.interaction.capabilities.core.HostProperties,? extends ExecutionSessionT> sessionFactory);
+ method protected BuilderT setExecutionSessionFactory(kotlin.jvm.functions.Function1<? super androidx.appactions.interaction.capabilities.core.HostProperties,? extends ExecutionSessionT> sessionFactory);
method public final BuilderT setId(String id);
}
diff --git a/appactions/interaction/interaction-capabilities-core/build.gradle b/appactions/interaction/interaction-capabilities-core/build.gradle
index 5d66474..91505ce 100644
--- a/appactions/interaction/interaction-capabilities-core/build.gradle
+++ b/appactions/interaction/interaction-capabilities-core/build.gradle
@@ -24,6 +24,7 @@
dependencies {
api(project(path: ":appactions:interaction:interaction-proto", configuration: "shadowJar"))
+ api(project(":appactions:builtintypes:builtintypes-core"))
api(libs.autoValueAnnotations)
implementation(libs.guavaListenableFuture)
@@ -38,6 +39,7 @@
testImplementation(libs.testCore)
testImplementation(libs.mockitoCore)
testImplementation(libs.mockitoKotlin4)
+ testImplementation(libs.kotlinCoroutinesTest)
testImplementation(libs.kotlinStdlib)
testImplementation(libs.androidLint)
testImplementation(libs.androidLintTests)
@@ -62,9 +64,8 @@
}
androidx {
- name = "androidx.appactions.interaction:interaction-capabilities-core"
+ name = "App Actions Interaction Capabiliities Core"
type = LibraryType.PUBLISHED_LIBRARY
inceptionYear = "2023"
description = "App Interaction library core capabilities API and implementation."
- failOnDeprecationWarnings = false
}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/experimental/types/Alarm.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/experimental/types/Alarm.kt
deleted file mode 100644
index d968db2a1..0000000
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/experimental/types/Alarm.kt
+++ /dev/null
@@ -1,53 +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.appactions.builtintypes.experimental.types
-
-import androidx.appactions.builtintypes.experimental.properties.Name
-
-interface Alarm : Thing {
- override fun toBuilder(): Builder<*>
-
- companion object {
- @JvmStatic
- fun Builder(): Builder<*> = AlarmBuilderImpl()
- }
-
- interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
- override fun build(): Alarm
- }
-}
-
-private class AlarmBuilderImpl : Alarm.Builder<AlarmBuilderImpl> {
-
- private var identifier: String? = null
- private var name: Name? = null
-
- override fun build() = AlarmImpl(identifier, name)
-
- override fun setIdentifier(text: String?): AlarmBuilderImpl = apply { identifier = text }
-
- override fun setName(text: String): AlarmBuilderImpl = apply { name = Name(text) }
-
- override fun setName(name: Name?): AlarmBuilderImpl = apply { this.name = name }
-
- override fun clearName(): AlarmBuilderImpl = apply { name = null }
-}
-
-private class AlarmImpl(override val identifier: String?, override val name: Name?) : Alarm {
- override fun toBuilder(): Alarm.Builder<*> =
- AlarmBuilderImpl().setIdentifier(identifier).setName(name)
-}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/experimental/types/Timer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/experimental/types/Timer.kt
deleted file mode 100644
index b90d44b..0000000
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/experimental/types/Timer.kt
+++ /dev/null
@@ -1,61 +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.appactions.builtintypes.experimental.types
-
-import androidx.appactions.builtintypes.experimental.properties.Name
-
-interface Timer : Thing {
- override fun toBuilder(): Builder<*>
-
- companion object {
- @JvmStatic
- fun Builder(): Builder<*> = TimerBuilderImpl()
- }
-
- interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
- override fun build(): Timer
- }
-}
-
-private class TimerBuilderImpl : Timer.Builder<TimerBuilderImpl> {
-
- private var identifier: String? = null
- private var name: Name? = null
-
- override fun build() = TimerImpl(identifier, name)
-
- override fun setIdentifier(text: String?): TimerBuilderImpl = apply { identifier = text }
-
- override fun setName(text: String): TimerBuilderImpl = apply { name = Name(text) }
-
- override fun setName(name: Name?): TimerBuilderImpl = apply { this.name = name }
-
- override fun clearName(): TimerBuilderImpl = apply { name = null }
-}
-
-private class TimerImpl(override val identifier: String?, override val name: Name?) : Timer {
- override fun toBuilder(): Timer.Builder<*> =
- TimerBuilderImpl().setIdentifier(identifier).setName(name)
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (other !is TimerImpl) return false
- if (identifier != other.identifier) return false
- if (name != other.name) return false
- return true
- }
-}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/Capability.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/Capability.kt
index 0fcd4a2..77af3e3 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/Capability.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/Capability.kt
@@ -20,7 +20,9 @@
import androidx.annotation.RestrictTo
import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession
import androidx.appactions.interaction.capabilities.core.impl.SingleTurnCapabilityImpl
+import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
+import androidx.appactions.interaction.capabilities.core.impl.spec.BoundProperty
import androidx.appactions.interaction.capabilities.core.impl.task.EmptyTaskUpdater
import androidx.appactions.interaction.capabilities.core.impl.task.SessionBridge
import androidx.appactions.interaction.capabilities.core.impl.task.TaskCapabilityImpl
@@ -71,10 +73,10 @@
ExecutionSessionT : BaseExecutionSession<ArgumentsT, OutputT>
> private constructor() {
private var id: String? = null
- private var property: Map<String, Property<*>>? = null
+ private val boundPropertyMap = mutableMapOf<String, BoundProperty<*>>()
private var executionCallback: ExecutionCallback<ArgumentsT, OutputT>? = null
private var sessionFactory:
- (hostProperties: HostProperties?) -> ExecutionSessionT? = { _ -> null }
+ ((hostProperties: HostProperties?) -> ExecutionSessionT)? = null
private var actionSpec: ActionSpec<ArgumentsT, OutputT>? = null
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -107,11 +109,14 @@
}
/**
- * Sets the Property instance for this capability.
- */
+ * Sets a single slot property for this capability, and associated entity converter. */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- fun setProperty(property: Map<String, Property<*>>) = asBuilder().apply {
- this.property = property
+ protected fun <T> setProperty(
+ slotName: String,
+ property: Property<T>,
+ entityConverter: EntityConverter<T>,
+ ) = asBuilder().apply {
+ this.boundPropertyMap[slotName] = BoundProperty(slotName, property, entityConverter)
}
/**
@@ -153,32 +158,43 @@
* calling one will nullify the other.
*/
@SuppressLint("MissingGetterMatchingBuilder")
- open fun setExecutionSessionFactory(
+ protected open fun setExecutionSessionFactory(
sessionFactory: (hostProperties: HostProperties?) -> ExecutionSessionT
): BuilderT = asBuilder().apply {
this.sessionFactory = sessionFactory
}
- /** Builds and returns this Capability. */
+ /**
+ * Builds and returns this Capability.
+ * [setId] must be called before [build].
+ * either [setExecutionCabllack] or [setSessionFactory] must be called before [build].
+ * child classes may enforce additional required properties to be set before [build].
+ * An [IllegalStateException] will be thrown if above requirements are not met.
+ */
open fun build(): Capability {
- val checkedId = requireNotNull(id) { "setId must be called before build" }
- val checkedProperty = requireNotNull(property) { "property must not be null." }
+ val checkedId = id ?: throw IllegalStateException("setId must be called before build")
+ val boundProperties = boundPropertyMap.values.toList()
if (executionCallback != null) {
return SingleTurnCapabilityImpl(
checkedId,
actionSpec!!,
- checkedProperty,
+ boundProperties,
executionCallback!!
)
- } else {
+ } else if (sessionFactory != null) {
return TaskCapabilityImpl(
checkedId,
actionSpec!!,
- checkedProperty,
- sessionFactory,
+ boundProperties,
+ sessionFactory!!,
sessionBridge!!,
::EmptyTaskUpdater
)
+ } else {
+ throw IllegalStateException(
+ """either setExecutionCallback or setExecutionSessionFactory must be called
+ before capability '$id' can be built"""
+ )
}
}
}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityProvider.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityProvider.kt
index 8a7514b..564e051 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityProvider.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityProvider.kt
@@ -17,7 +17,7 @@
package androidx.appactions.interaction.capabilities.core.entity
import androidx.annotation.RestrictTo
-import androidx.appactions.builtintypes.experimental.types.Thing
+import androidx.appactions.builtintypes.types.Thing
import androidx.appactions.interaction.capabilities.core.SearchAction
import androidx.appactions.interaction.capabilities.core.impl.concurrent.Futures
import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
@@ -53,6 +53,7 @@
*
* @param request The request includes e.g. entity, search metadata, etc.
* @return an [EntityLookupResponse] instance
+ * * TODO(dennistwo) lookup request should contain a different generic type (filter type)
*/
open suspend fun lookup(request: EntityLookupRequest<T>): EntityLookupResponse<T> {
return lookupAsync(request).await()
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/ArgumentsWrapper.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/ArgumentsWrapper.kt
index f6178d5..ae2bc6e 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/ArgumentsWrapper.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/ArgumentsWrapper.kt
@@ -58,21 +58,12 @@
}
}
- @Suppress(
- "DEPRECATION",
- ) // Convert the deprecated "fp.valuesList" property to the new format.
internal fun convertToArgumentMap(
fulfillment: Fulfillment,
): Map<String, List<FulfillmentValue>> {
val result = mutableMapOf<String, List<FulfillmentValue>>()
for (fp in fulfillment.paramsList) {
- // Normalize deprecated param value list into new FulfillmentValue.
- if (fp.valuesList.isNotEmpty()) {
- result[fp.name] =
- fp.valuesList.map { FulfillmentValue.newBuilder().setValue(it).build() }
- } else {
- result[fp.name] = fp.fulfillmentValuesList
- }
+ result[fp.name] = fp.fulfillmentValuesList
}
return result.toMap()
}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/ErrorStatusInternal.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/ErrorStatusInternal.java
index 0600dbb..f7599df 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/ErrorStatusInternal.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/ErrorStatusInternal.java
@@ -21,22 +21,21 @@
/** A class to define exceptions that are reported from dialog capability API. */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public enum ErrorStatusInternal {
- CANCELLED(0),
- TIMEOUT(1),
- INVALID_REQUEST(2),
- UNCHANGED_DISAMBIG_STATE(3),
- INVALID_RESOLVER(4),
- STRUCT_CONVERSION_FAILURE(5),
- EXTERNAL_EXCEPTION(9),
- SESSION_ALREADY_DESTROYED(10);
-
- private final int mCode;
-
- ErrorStatusInternal(int code) {
- this.mCode = code;
- }
-
- public int getCode() {
- return mCode;
- }
+ // Unexpected error which doesn't fall into any other error status.
+ UNKNOWN_ERROR_STATUS,
+ // Exception occurred which is internal to the capabilities library.
+ INTERNAL,
+ // The current capability session was cancelled, likely because a new request was sent to the
+ // capability before the first had time to complete.
+ CANCELED,
+ // Developer provided callback has timed out.
+ TIMEOUT,
+ // Invalid data was sent to the capability. This could be a nonsensical request Type or
+ // malformed arguments (e.g. wrong data format for a BII argument).
+ INVALID_REQUEST,
+ // An exception was thrown from a developer-provided callback.
+ EXTERNAL_EXCEPTION,
+ // Tried to send request to a particular capability session, but that session never started
+ // or has already ended.
+ SESSION_NOT_FOUND,
}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityImpl.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityImpl.kt
index 862385b..a939b03 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityImpl.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityImpl.kt
@@ -21,9 +21,8 @@
import androidx.appactions.interaction.capabilities.core.ExecutionCallback
import androidx.appactions.interaction.capabilities.core.HostProperties
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
-import androidx.appactions.interaction.capabilities.core.properties.Property
+import androidx.appactions.interaction.capabilities.core.impl.spec.BoundProperty
import androidx.appactions.interaction.proto.AppActionsContext.AppAction
-import androidx.appactions.interaction.proto.TaskInfo
import kotlinx.coroutines.sync.Mutex
@RestrictTo(RestrictTo.Scope.LIBRARY)
@@ -33,16 +32,16 @@
> constructor(
id: String,
val actionSpec: ActionSpec<ArgumentsT, OutputT>,
- val property: Map<String, Property<*>>,
+ val boundProperties: List<BoundProperty<*>>,
val executionCallback: ExecutionCallback<ArgumentsT, OutputT>,
) : Capability(id) {
private val mutex = Mutex()
- override val appAction: AppAction get() =
- actionSpec.convertPropertyToProto(property).toBuilder()
- .setTaskInfo(TaskInfo.newBuilder().setSupportsPartialFulfillment(false))
- .setIdentifier(id)
- .build()
+ override val appAction: AppAction get() = actionSpec.createAppAction(
+ id,
+ boundProperties,
+ supportsPartialFulfillment = false
+ )
override fun createSession(
sessionId: String,
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilitySession.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilitySession.kt
index dabe1cd..2d7fd2d 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilitySession.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilitySession.kt
@@ -67,7 +67,7 @@
callback: CallbackInternal,
) {
if (!isActiveAtomic.getAndSet(false)) {
- callback.onError(ErrorStatusInternal.CANCELLED)
+ callback.onError(ErrorStatusInternal.SESSION_NOT_FOUND)
return
}
val paramValuesMap: Map<String, List<ParamValue>> =
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/EntityConverter.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/EntityConverter.kt
index 05072dd..164fa59 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/EntityConverter.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/EntityConverter.kt
@@ -35,6 +35,7 @@
/**
* @param typeSpec the TypeSpec of the structured type.
*/
+ @JvmStatic
fun <T> of(typeSpec: TypeSpec<T>): EntityConverter<T> {
return EntityConverter { obj ->
val builder = valueToEntity(typeSpec.toValue(obj)).toBuilder()
@@ -43,7 +44,7 @@
}
}
- private fun valueToEntity(value: Value): Entity {
+ internal fun valueToEntity(value: Value): Entity {
val builder = Entity.newBuilder()
when {
value.hasStringValue() -> builder.stringValue = value.stringValue
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConverters.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConverters.java
index 8d26ad7..9e209f1 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConverters.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConverters.java
@@ -25,7 +25,6 @@
import androidx.appactions.builtintypes.experimental.properties.Recipient;
import androidx.appactions.builtintypes.experimental.properties.StartDate;
import androidx.appactions.builtintypes.experimental.properties.Text;
-import androidx.appactions.builtintypes.experimental.types.Alarm;
import androidx.appactions.builtintypes.experimental.types.CalendarEvent;
import androidx.appactions.builtintypes.experimental.types.Call;
import androidx.appactions.builtintypes.experimental.types.ItemList;
@@ -33,7 +32,6 @@
import androidx.appactions.builtintypes.experimental.types.Message;
import androidx.appactions.builtintypes.experimental.types.Person;
import androidx.appactions.builtintypes.experimental.types.SafetyCheck;
-import androidx.appactions.builtintypes.experimental.types.Timer;
import androidx.appactions.interaction.capabilities.core.SearchAction;
import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException;
import androidx.appactions.interaction.capabilities.core.properties.StringValue;
@@ -45,7 +43,6 @@
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Optional;
@@ -90,12 +87,6 @@
.orElse(null),
Person.Builder::setName)
.build();
- public static final TypeSpec<Alarm> ALARM_TYPE_SPEC =
- TypeSpecBuilder.newBuilderForThing(
- "Alarm", Alarm::Builder, Alarm.Builder::build).build();
- public static final TypeSpec<Timer> TIMER_TYPE_SPEC =
- TypeSpecBuilder.newBuilderForThing(
- "Timer", Timer::Builder, Timer.Builder::build).build();
public static final TypeSpec<Attendee> ATTENDEE_TYPE_SPEC =
new UnionTypeSpec.Builder<Attendee>()
.bindMemberType(
@@ -198,55 +189,11 @@
ParamValueConverter.of(TypeSpec.STRING_TYPE_SPEC);
public static final ParamValueConverter<LocalDate> LOCAL_DATE_PARAM_VALUE_CONVERTER =
- new ParamValueConverter<LocalDate>() {
- @NonNull
- @Override
- public ParamValue toParamValue(LocalDate value) {
- return ParamValue.newBuilder()
- .setStringValue(value.format(DateTimeFormatter.ISO_LOCAL_DATE))
- .build();
- }
+ ParamValueConverter.of(TypeSpec.LOCAL_DATE_TYPE_SPEC);
- @Override
- public LocalDate fromParamValue(@NonNull ParamValue paramValue)
- throws StructConversionException {
- if (paramValue.hasStringValue()) {
- try {
- return LocalDate.parse(paramValue.getStringValue());
- } catch (DateTimeParseException e) {
- throw new StructConversionException(
- "Failed to parse ISO 8601 string to LocalDate", e);
- }
- }
- throw new StructConversionException(
- "Cannot parse date because string_value is missing from ParamValue.");
- }
- };
public static final ParamValueConverter<LocalTime> LOCAL_TIME_PARAM_VALUE_CONVERTER =
- new ParamValueConverter<LocalTime>() {
- @NonNull
- @Override
- public ParamValue toParamValue(LocalTime value) {
- return ParamValue.newBuilder()
- .setStringValue(value.format(DateTimeFormatter.ISO_LOCAL_TIME))
- .build();
- }
+ ParamValueConverter.of(TypeSpec.LOCAL_TIME_TYPE_SPEC);
- @Override
- public LocalTime fromParamValue(@NonNull ParamValue paramValue)
- throws StructConversionException {
- if (paramValue.hasStringValue()) {
- try {
- return LocalTime.parse(paramValue.getStringValue());
- } catch (DateTimeParseException e) {
- throw new StructConversionException(
- "Failed to parse ISO 8601 string to LocalTime", e);
- }
- }
- throw new StructConversionException(
- "Cannot parse time because string_value is missing from ParamValue.");
- }
- };
public static final ParamValueConverter<ZoneId> ZONE_ID_PARAM_VALUE_CONVERTER =
new ParamValueConverter<ZoneId>() {
@NonNull
@@ -270,56 +217,10 @@
"Cannot parse ZoneId because string_value is missing from ParamValue.");
}
};
- public static final ParamValueConverter<ZonedDateTime> ZONED_DATETIME_PARAM_VALUE_CONVERTER =
- new ParamValueConverter<ZonedDateTime>() {
- @NonNull
- @Override
- public ParamValue toParamValue(ZonedDateTime value) {
- return ParamValue.newBuilder()
- .setStringValue(value.format(DateTimeFormatter.ISO_ZONED_DATE_TIME))
- .build();
- }
-
- @Override
- public ZonedDateTime fromParamValue(@NonNull ParamValue paramValue)
- throws StructConversionException {
- if (paramValue.hasStringValue()) {
- try {
- return ZonedDateTime.parse(paramValue.getStringValue());
- } catch (DateTimeParseException e) {
- throw new StructConversionException(
- "Failed to parse ISO 8601 string to ZonedDateTime", e);
- }
- }
- throw new StructConversionException(
- "Cannot parse datetime because string_value"
- + " is missing from ParamValue.");
- }
- };
+ public static final ParamValueConverter<ZonedDateTime> ZONED_DATE_TIME_PARAM_VALUE_CONVERTER =
+ ParamValueConverter.of(TypeSpec.ZONED_DATE_TIME_TYPE_SPEC);
public static final ParamValueConverter<Duration> DURATION_PARAM_VALUE_CONVERTER =
- new ParamValueConverter<Duration>() {
- @NonNull
- @Override
- public ParamValue toParamValue(Duration value) {
- return ParamValue.newBuilder().setStringValue(value.toString()).build();
- }
-
- @Override
- public Duration fromParamValue(@NonNull ParamValue paramValue)
- throws StructConversionException {
- if (!paramValue.hasStringValue()) {
- throw new StructConversionException(
- "Cannot parse duration because string_value"
- + " is missing from ParamValue.");
- }
- try {
- return Duration.parse(paramValue.getStringValue());
- } catch (DateTimeParseException e) {
- throw new StructConversionException(
- "Failed to parse ISO 8601 string to Duration", e);
- }
- }
- };
+ ParamValueConverter.of(TypeSpec.DURATION_TYPE_SPEC);
public static final ParamValueConverter<Call.CanonicalValue.CallFormat>
CALL_FORMAT_PARAM_VALUE_CONVERTER =
new ParamValueConverter<Call.CanonicalValue.CallFormat>() {
@@ -353,15 +254,12 @@
.setName(stringValue.getName())
.addAllAlternateNames(stringValue.getAlternateNames())
.build();
- public static final EntityConverter<ZonedDateTime> ZONED_DATETIME_ENTITY_CONVERTER =
- (zonedDateTime) ->
- Entity.newBuilder()
- .setStringValue(zonedDateTime.toOffsetDateTime().toString())
- .build();
+ public static final EntityConverter<ZonedDateTime> ZONED_DATE_TIME_ENTITY_CONVERTER =
+ EntityConverter.of(TypeSpec.ZONED_DATE_TIME_TYPE_SPEC);
public static final EntityConverter<LocalTime> LOCAL_TIME_ENTITY_CONVERTER =
- (localTime) -> Entity.newBuilder().setStringValue(localTime.toString()).build();
+ EntityConverter.of(TypeSpec.LOCAL_TIME_TYPE_SPEC);
public static final EntityConverter<Duration> DURATION_ENTITY_CONVERTER =
- (duration) -> Entity.newBuilder().setStringValue(duration.toString()).build();
+ EntityConverter.of(TypeSpec.DURATION_TYPE_SPEC);
public static final EntityConverter<Call.CanonicalValue.CallFormat>
CALL_FORMAT_ENTITY_CONVERTER =
(callFormat) ->
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpec.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpec.kt
index 4656db6..57000bb 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpec.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpec.kt
@@ -18,6 +18,14 @@
import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException
import androidx.appactions.interaction.protobuf.Value
+import java.time.Duration
+import java.time.Instant
+import java.time.LocalDate
+import java.time.LocalDateTime
+import java.time.LocalTime
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+import java.time.format.DateTimeParseException
/**
* TypeSpec is used to convert between native objects in capabilities/values and Value proto.
@@ -38,21 +46,29 @@
fun fromValue(value: Value): T
companion object {
- @JvmField
- val STRING_TYPE_SPEC = object : TypeSpec<String> {
- override fun getIdentifier(obj: String): String? = null
-
- override fun toValue(
- obj: String,
- ): Value = Value.newBuilder().setStringValue(obj).build()
-
- override fun fromValue(value: Value): String = when {
- value.hasStringValue() -> value.stringValue
- else -> throw StructConversionException("STRING_TYPE_SPEC cannot convert $value")
+ /** Create a TypeSpec that serializes to/from Value.stringValue. */
+ @JvmStatic
+ fun <T> createStringBasedTypeSpec(
+ toString: (T) -> String,
+ fromString: (String) -> T
+ ): TypeSpec<T> = object : TypeSpec<T> {
+ override fun getIdentifier(obj: T): String? = null
+ override fun toValue(obj: T): Value = Value.newBuilder()
+ .setStringValue(toString(obj)).build()
+ override fun fromValue(value: Value): T = when {
+ value.hasStringValue() -> fromString(value.stringValue)
+ else -> throw StructConversionException(
+ "cannot convert $value, expected Value.stringValue to be present")
}
}
@JvmField
+ val STRING_TYPE_SPEC = createStringBasedTypeSpec<String>(
+ toString = { it },
+ fromString = { it }
+ )
+
+ @JvmField
val BOOL_TYPE_SPEC = object : TypeSpec<Boolean> {
override fun getIdentifier(obj: Boolean): String? = null
@@ -93,5 +109,87 @@
else -> throw StructConversionException("INTEGER_TYPE_SPEC cannot convert $value")
}
}
+
+ // TODO(remove this when Long is no longer used in BIT library)
+ @JvmField
+ /** Serialize Long to/from string field due to precision limit with nunmber value. */
+ val LONG_TYPE_SPEC = object : TypeSpec<Long> {
+ override fun getIdentifier(obj: Long): String? = null
+
+ override fun toValue(
+ obj: Long,
+ ): Value = Value.newBuilder().setNumberValue(obj.toDouble()).build()
+
+ override fun fromValue(value: Value): Long = when {
+ value.hasNumberValue() -> value.numberValue.toLong()
+ else -> throw StructConversionException("LONG_TYPE_SPEC cannot convert $value")
+ }
+ }
+
+ @JvmField
+ val LOCAL_DATE_TYPE_SPEC = createStringBasedTypeSpec<LocalDate>(
+ toString = { it.format(DateTimeFormatter.ISO_LOCAL_DATE) },
+ fromString = { try {
+ LocalDate.parse(it)
+ } catch (e: DateTimeParseException) {
+ throw StructConversionException(
+ "Failed to parse ISO 8601 string to LocalDate", e)
+ } }
+ )
+
+ @JvmField
+ val LOCAL_TIME_TYPE_SPEC = createStringBasedTypeSpec<LocalTime>(
+ toString = { it.format(DateTimeFormatter.ISO_LOCAL_TIME) },
+ fromString = { try {
+ LocalTime.parse(it)
+ } catch (e: DateTimeParseException) {
+ throw StructConversionException(
+ "Failed to parse ISO 8601 string to LocalTime", e)
+ } }
+ )
+
+ @JvmField
+ val LOCAL_DATE_TIME_TYPE_SPEC = createStringBasedTypeSpec<LocalDateTime>(
+ toString = { it.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) },
+ fromString = { try {
+ LocalDateTime.parse(it)
+ } catch (e: DateTimeParseException) {
+ throw StructConversionException(
+ "Failed to parse ISO 8601 string to LocalDateTime", e)
+ } }
+ )
+
+ @JvmField
+ val ZONED_DATE_TIME_TYPE_SPEC = createStringBasedTypeSpec<ZonedDateTime>(
+ toString = { it.format(DateTimeFormatter.ISO_ZONED_DATE_TIME) },
+ fromString = { try {
+ ZonedDateTime.parse(it)
+ } catch (e: DateTimeParseException) {
+ throw StructConversionException(
+ "Failed to parse ISO 8601 string to ZonedDateTime", e)
+ } }
+ )
+
+ @JvmField
+ val INSTANT_TYPE_SPEC = createStringBasedTypeSpec<Instant>(
+ toString = Instant::toString,
+ fromString = { try {
+ Instant.parse(it)
+ } catch (e: DateTimeParseException) {
+ throw StructConversionException(
+ "Failed to parse ISO 8601 string to Instant", e)
+ } }
+ )
+
+ @JvmField
+ val DURATION_TYPE_SPEC = createStringBasedTypeSpec<Duration>(
+ toString = Duration::toString,
+ fromString = { try {
+ Duration.parse(it)
+ } catch (e: DateTimeParseException) {
+ throw StructConversionException(
+ "Failed to parse ISO 8601 string to Duration", e)
+ } }
+ )
}
}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecBuilder.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecBuilder.java
index 279e65c..7d8aeda 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecBuilder.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecBuilder.java
@@ -18,6 +18,8 @@
import static androidx.appactions.interaction.capabilities.core.impl.utils.ImmutableCollectors.toImmutableList;
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
import androidx.appactions.builtintypes.experimental.types.Thing;
import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException;
import androidx.appactions.interaction.protobuf.ListValue;
@@ -35,8 +37,13 @@
import java.util.function.Function;
import java.util.function.Supplier;
-/** Builder for {@link TypeSpec}. */
-final class TypeSpecBuilder<T, BuilderT> {
+/**
+ * Builder for {@link TypeSpec}. TypeSpec converts T instance to and from {@code Value.structValue}
+ * @param <T> the type this TypeSpec is for
+ * @param <BuilderT> the type that builds T objects
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class TypeSpecBuilder<T, BuilderT> {
private final List<FieldBinding<T, BuilderT>> mBindings = new ArrayList<>();
private final Supplier<BuilderT> mBuilderSupplier;
private final Function<BuilderT, T> mBuilderFinalizer;
@@ -90,10 +97,18 @@
}
}
- static <T, BuilderT> TypeSpecBuilder<T, BuilderT> newBuilder(
- String typeName,
- Supplier<BuilderT> builderSupplier,
- Function<BuilderT, T> builderFinalizer) {
+ /**
+ * Creates a new instance of TypeSpecBuilder.
+ *
+ * @param typeName the name of the type.
+ * @param builderSupplier a function which supplies new Builder instances for the type.
+ * @param builderFinalizer a function that gets the built object from the builder.
+ */
+ @NonNull
+ public static <T, BuilderT> TypeSpecBuilder<T, BuilderT> newBuilder(
+ @NonNull String typeName,
+ @NonNull Supplier<BuilderT> builderSupplier,
+ @NonNull Function<BuilderT, T> builderFinalizer) {
return new TypeSpecBuilder<>(typeName, builderSupplier, builderFinalizer);
}
@@ -127,7 +142,13 @@
return this;
}
- TypeSpecBuilder<T, BuilderT> bindIdentifier(Function<T, String> identifierGetter) {
+ /**
+ * Binds a function that returns the identifier of the object.
+ */
+ @NonNull
+ public TypeSpecBuilder<T, BuilderT> bindIdentifier(
+ @NonNull Function<T, String> identifierGetter
+ ) {
this.mIdentifierGetter = identifierGetter;
return this;
}
@@ -175,10 +196,11 @@
}
/** binds a String field to read from / write to Struct */
- TypeSpecBuilder<T, BuilderT> bindStringField(
- String name,
- Function<T, String> stringGetter,
- BiConsumer<BuilderT, String> stringSetter) {
+ @NonNull
+ public TypeSpecBuilder<T, BuilderT> bindStringField(
+ @NonNull String name,
+ @NonNull Function<T, String> stringGetter,
+ @NonNull BiConsumer<BuilderT, String> stringSetter) {
return bindFieldInternal(
name,
(object) -> {
@@ -291,11 +313,13 @@
}
/** Binds a spec field to read from / write to Struct. */
- <V> TypeSpecBuilder<T, BuilderT> bindSpecField(
- String name,
- Function<T, V> valueGetter,
- BiConsumer<BuilderT, V> valueSetter,
- TypeSpec<V> spec) {
+ @SuppressWarnings("LambdaLast")
+ @NonNull
+ public <V> TypeSpecBuilder<T, BuilderT> bindSpecField(
+ @NonNull String name,
+ @NonNull Function<T, V> valueGetter,
+ @NonNull BiConsumer<BuilderT, V> valueSetter,
+ @NonNull TypeSpec<V> spec) {
return bindFieldInternal(
name,
(object) -> {
@@ -309,11 +333,13 @@
}
/** binds a repeated spec field to read from / write to Struct. */
- <V> TypeSpecBuilder<T, BuilderT> bindRepeatedSpecField(
- String name,
- Function<T, List<V>> valueGetter,
- BiConsumer<BuilderT, List<V>> valueSetter,
- TypeSpec<V> spec) {
+ @SuppressWarnings("LambdaLast")
+ @NonNull
+ public <V> TypeSpecBuilder<T, BuilderT> bindRepeatedSpecField(
+ @NonNull String name,
+ @NonNull Function<T, List<V>> valueGetter,
+ @NonNull BiConsumer<BuilderT, List<V>> valueSetter,
+ @NonNull TypeSpec<V> spec) {
return bindRepeatedFieldInternal(
name,
valueGetter,
@@ -322,7 +348,11 @@
spec::fromValue);
}
- TypeSpec<T> build() {
+ /**
+ * Builds the TypeSpec instance.
+ */
+ @NonNull
+ public TypeSpec<T> build() {
return new TypeSpecImpl<>(
mIdentifierGetter,
mBindings,
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/UnionTypeSpec.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/UnionTypeSpec.kt
index 025c5fa..0e79006 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/UnionTypeSpec.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/UnionTypeSpec.kt
@@ -81,6 +81,7 @@
class Builder<T : Any> {
private val bindings = mutableListOf<MemberBinding<T, *>>()
+ /** During deserialization, bindings will be tried in the order they are bound. */
fun <M> bindMemberType(
memberGetter: (T) -> M?,
ctor: (M) -> T,
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpec.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpec.kt
index 450d3d3..1cc28f8 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpec.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpec.kt
@@ -17,7 +17,6 @@
package androidx.appactions.interaction.capabilities.core.impl.spec
import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException
-import androidx.appactions.interaction.capabilities.core.properties.Property
import androidx.appactions.interaction.proto.AppActionsContext
import androidx.appactions.interaction.proto.FulfillmentResponse
import androidx.appactions.interaction.proto.ParamValue
@@ -30,8 +29,18 @@
*/
interface ActionSpec<ArgumentsT, OutputT> {
- /** Converts the property to the `AppAction` proto. */
- fun convertPropertyToProto(property: Map<String, Property<*>>): AppActionsContext.AppAction
+ /**
+ * Converts the input parameters to the `AppAction` proto.
+ * @param identifier the capability identifier
+ * @param boundProperties the list of BoundProperty instances.
+ * @param supportsPartialFulfillment whether or not this capability supports partial
+ * fulfillment.
+ */
+ fun createAppAction(
+ identifier: String,
+ boundProperties: List<BoundProperty<*>>,
+ supportsPartialFulfillment: Boolean
+ ): AppActionsContext.AppAction
/** Builds this action's arguments from an ArgumentsWrapper instance. */
@Throws(StructConversionException::class)
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecBuilder.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecBuilder.kt
index ad4b7b6..84f058a 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecBuilder.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecBuilder.kt
@@ -17,14 +17,10 @@
package androidx.appactions.interaction.capabilities.core.impl.spec
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
-import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
import androidx.appactions.interaction.capabilities.core.impl.converters.ParamValueConverter
import androidx.appactions.interaction.capabilities.core.impl.converters.SlotTypeConverter
import androidx.appactions.interaction.capabilities.core.impl.spec.ParamBinding.ArgumentSetter
-import androidx.appactions.interaction.capabilities.core.impl.spec.ParamBinding.Companion.create
import androidx.appactions.interaction.capabilities.core.impl.utils.ImmutableCollectors
-import androidx.appactions.interaction.capabilities.core.properties.Property
-import androidx.appactions.interaction.proto.AppActionsContext
import androidx.appactions.interaction.proto.ParamValue
import java.util.function.BiConsumer
import java.util.function.Function
@@ -42,7 +38,6 @@
ArrayList()
private val outputBindings: MutableMap<String, Function<OutputT, List<ParamValue>>> = HashMap()
- /** Sets the property type and returns a new `ActionSpecBuilder`. */
/** Sets the argument type and its builder and returns a new `ActionSpecBuilder`. */
@Suppress("UNUSED_PARAMETER")
fun <NewArgumentsT, NewArgumentsBuilderT : BuilderOf<NewArgumentsT>> setArguments(
@@ -69,41 +64,30 @@
*/
private fun bindParameterInternal(
paramName: String,
- paramGetter: Function<Map<String, Property<*>>, AppActionsContext.IntentParameter?>,
argumentSetter: ArgumentSetter<ArgumentsBuilderT>
): ActionSpecBuilder<ArgumentsT, ArgumentsBuilderT, OutputT> {
- paramBindingList.add(create(paramName, paramGetter, argumentSetter))
+ paramBindingList.add(ParamBinding(paramName, argumentSetter))
return this
}
/**
- * Binds the parameter name, getter, and setter for a [Property].
+ * Binds the parameter name, and corresponding method references for setting Argument value.
*
* If the Property getter returns a null value, this parameter will not exist in the parameter
* definition of the capability.
*
* @param paramName the name of this action' parameter.
- * @param propertyGetter a getter of the Property from the property, which must be able to
- * fetch a non-null `Property` from `PropertyT`.
* @param paramConsumer a setter to set the string value in the argument builder.
* @param paramValueConverter converter FROM assistant ParamValue proto
- * @param entityConverter converter TO assistant Entity proto
* @return the builder itself.
*/
- fun <T, PossibleValueT> bindParameter(
+ fun <T> bindParameter(
paramName: String,
- propertyGetter: Function<Map<String, Property<*>>, Property<PossibleValueT>?>,
paramConsumer: BiConsumer<in ArgumentsBuilderT, T>,
paramValueConverter: ParamValueConverter<T>,
- entityConverter: EntityConverter<PossibleValueT>
): ActionSpecBuilder<ArgumentsT, ArgumentsBuilderT, OutputT> {
return bindParameterInternal(
paramName,
- { propertyMap ->
- propertyGetter.apply(propertyMap)?.let {
- buildIntentParameter(paramName, it, entityConverter)
- }
- },
{ argBuilder: ArgumentsBuilderT, paramList: List<ParamValue> ->
if (paramList.isNotEmpty()) {
paramConsumer.accept(
@@ -122,20 +106,13 @@
* If the Property getter returns a null value, this parameter will not exist in the parameter
* definition of the capability.
*/
- fun <T, PossibleValueT> bindRepeatedParameter(
+ fun <T> bindRepeatedParameter(
paramName: String,
- propertyGetter: Function<Map<String, Property<*>>, Property<PossibleValueT>?>,
paramConsumer: BiConsumer<in ArgumentsBuilderT, List<T>>,
- paramValueConverter: ParamValueConverter<T>,
- entityConverter: EntityConverter<PossibleValueT>
+ paramValueConverter: ParamValueConverter<T>
): ActionSpecBuilder<ArgumentsT, ArgumentsBuilderT, OutputT> {
return bindParameterInternal(
paramName,
- { propertyMap ->
- propertyGetter.apply(propertyMap)?.let {
- buildIntentParameter(paramName, it, entityConverter)
- }
- },
{ argBuilder: ArgumentsBuilderT, paramList: List<ParamValue?>? ->
paramConsumer.accept(
argBuilder,
@@ -209,26 +186,5 @@
): ActionSpecBuilder<Any, BuilderOf<Any>, Any> {
return ActionSpecBuilder(capabilityName) { BuilderOf { Object() } }
}
-
- /** Create IntentParameter proto from a Property. */
- internal fun <T> buildIntentParameter(
- paramName: String,
- property: Property<T>,
- entityConverter: EntityConverter<T>
- ): AppActionsContext.IntentParameter {
- val builder = AppActionsContext.IntentParameter.newBuilder()
- .setName(paramName)
- .setIsRequired(property.isRequired)
- .setEntityMatchRequired(property.isValueMatchRequired)
- .setIsProhibited(property.isProhibited)
- property.possibleValues.stream()
- .map { possibleValue ->
- entityConverter.convert(possibleValue)
- }
- .forEach { entityProto ->
- builder.addPossibleEntities(entityProto)
- }
- return builder.build()
- }
}
}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecImpl.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecImpl.kt
index a05c8ed..1c59144 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecImpl.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecImpl.kt
@@ -18,11 +18,10 @@
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException
-import androidx.appactions.interaction.capabilities.core.impl.utils.ImmutableCollectors
-import androidx.appactions.interaction.capabilities.core.properties.Property
-import androidx.appactions.interaction.proto.AppActionsContext
+import androidx.appactions.interaction.proto.AppActionsContext.AppAction
import androidx.appactions.interaction.proto.FulfillmentResponse
import androidx.appactions.interaction.proto.ParamValue
+import androidx.appactions.interaction.proto.TaskInfo
import java.util.function.Function
import java.util.function.Supplier
@@ -33,20 +32,20 @@
private val paramBindingList: List<ParamBinding<ArgumentsT, ArgumentsBuilderT>>,
private val outputBindings: Map<String, Function<OutputT, List<ParamValue>>>
) : ActionSpec<ArgumentsT, OutputT> {
-
- override fun convertPropertyToProto(
- property: Map<String, Property<*>>
- ): AppActionsContext.AppAction {
- return AppActionsContext.AppAction.newBuilder()
+ override fun createAppAction(
+ identifier: String,
+ boundProperties: List<BoundProperty<*>>,
+ supportsPartialFulfillment: Boolean
+ ): AppAction = AppAction.newBuilder()
.setName(capabilityName)
+ .setIdentifier(identifier)
.addAllParams(
- paramBindingList.stream()
- .map { binding -> binding.propertyConverter.apply(property) }
- .filter { intentParam -> intentParam != null }
- .collect(ImmutableCollectors.toImmutableList())
+ boundProperties.map(BoundProperty<*>::convertToProto)
+ )
+ .setTaskInfo(
+ TaskInfo.newBuilder().setSupportsPartialFulfillment(supportsPartialFulfillment)
)
.build()
- }
@Throws(StructConversionException::class)
override fun buildArguments(args: Map<String, List<ParamValue>>): ArgumentsT {
@@ -81,4 +80,4 @@
}
return outputBuilder.build()
}
-}
\ No newline at end of file
+}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/BoundProperty.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/BoundProperty.kt
new file mode 100644
index 0000000..c0792f0
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/BoundProperty.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.appactions.interaction.capabilities.core.impl.spec
+
+import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
+import androidx.appactions.interaction.capabilities.core.impl.utils.invokeExternalBlock
+import androidx.appactions.interaction.capabilities.core.properties.Property
+import androidx.appactions.interaction.proto.AppActionsContext.IntentParameter
+
+/** Wrapper around [Property] and a type-specific EntityConverter. */
+data class BoundProperty<T> internal constructor(
+ val slotName: String,
+ val property: Property<T>,
+ val entityConverter: EntityConverter<T>
+) {
+ /** * Convert this wrapped Property into [IntentParameter] proto representation with
+ * current inventory.
+ */
+ fun convertToProto(): IntentParameter {
+ val builder = IntentParameter.newBuilder()
+ .setName(slotName)
+ .setIsRequired(property.isRequired)
+ .setEntityMatchRequired(property.isValueMatchRequired)
+ .setIsProhibited(property.isProhibited)
+ invokeExternalBlock("retrieving possibleValues for $slotName property") {
+ property.possibleValues
+ }.map {
+ entityConverter.convert(it)
+ }.forEach {
+ builder.addPossibleEntities(it)
+ }
+ return builder.build()
+ }
+}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ParamBinding.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ParamBinding.kt
index 7e57ead..c8cd221 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ParamBinding.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ParamBinding.kt
@@ -18,15 +18,11 @@
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException
-import androidx.appactions.interaction.capabilities.core.properties.Property
-import androidx.appactions.interaction.proto.AppActionsContext.IntentParameter
import androidx.appactions.interaction.proto.ParamValue
-import java.util.function.Function
data class ParamBinding<ArgumentsT, ArgumentsBuilderT : BuilderOf<ArgumentsT>>
internal constructor(
val name: String,
- val propertyConverter: Function<Map<String, Property<*>>, IntentParameter?>,
val argumentSetter: ArgumentSetter<ArgumentsBuilderT>
) {
/**
@@ -38,15 +34,4 @@
@Throws(StructConversionException::class)
fun setArguments(builder: ArgumentsBuilderT, paramValues: List<ParamValue>)
}
-
- companion object {
- @JvmStatic
- fun <ArgumentsT, ArgumentsBuilderT : BuilderOf<ArgumentsT>> create(
- name: String,
- paramGetter: Function<Map<String, Property<*>>, IntentParameter?>,
- argumentSetter: ArgumentSetter<ArgumentsBuilderT>
- ): ParamBinding<ArgumentsT, ArgumentsBuilderT> {
- return ParamBinding(name, paramGetter, argumentSetter)
- }
- }
}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImpl.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImpl.kt
index 4dee5fa..dc0dd7e 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImpl.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImpl.kt
@@ -21,9 +21,8 @@
import androidx.appactions.interaction.capabilities.core.HostProperties
import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
-import androidx.appactions.interaction.capabilities.core.properties.Property
+import androidx.appactions.interaction.capabilities.core.impl.spec.BoundProperty
import androidx.appactions.interaction.proto.AppActionsContext.AppAction
-import androidx.appactions.interaction.proto.TaskInfo
import java.util.function.Supplier
/**
@@ -44,25 +43,23 @@
constructor(
id: String,
private val actionSpec: ActionSpec<ArgumentsT, OutputT>,
- private val property: Map<String, Property<*>>,
- private val sessionFactory: (hostProperties: HostProperties?) -> ExecutionSessionT?,
+ private val boundProperties: List<BoundProperty<*>>,
+ private val sessionFactory: (hostProperties: HostProperties?) -> ExecutionSessionT,
private val sessionBridge: SessionBridge<ExecutionSessionT, ArgumentsT, ConfirmationT>,
private val sessionUpdaterSupplier: Supplier<SessionUpdaterT>
) : Capability(id) {
- override val appAction: AppAction get() =
- actionSpec
- .convertPropertyToProto(property)
- .toBuilder()
- .setTaskInfo(TaskInfo.newBuilder().setSupportsPartialFulfillment(true))
- .setIdentifier(id)
- .build()
+ override val appAction: AppAction get() = actionSpec.createAppAction(
+ id,
+ boundProperties,
+ supportsPartialFulfillment = true
+ )
override fun createSession(
sessionId: String,
hostProperties: HostProperties
): CapabilitySession {
- val externalSession = sessionFactory.invoke(hostProperties)!!
+ val externalSession = sessionFactory.invoke(hostProperties)
return TaskCapabilitySession(
sessionId,
actionSpec,
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilitySession.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilitySession.kt
index 6ef8d2b..f51e21b1 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilitySession.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilitySession.kt
@@ -105,7 +105,7 @@
*/
private fun enqueueAssistantRequest(request: AssistantUpdateRequest) {
synchronized(requestLock) {
- pendingAssistantRequest?.callbackInternal?.onError(ErrorStatusInternal.CANCELLED)
+ pendingAssistantRequest?.callbackInternal?.onError(ErrorStatusInternal.CANCELED)
pendingAssistantRequest = request
dispatchPendingRequestIfIdle()
}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskOrchestrator.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskOrchestrator.kt
index 44cb4e0..865d603 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskOrchestrator.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskOrchestrator.kt
@@ -154,10 +154,10 @@
try {
if (status == Status.DESTROYED) {
if (updateRequest.assistantRequest != null) {
- FulfillmentResult(ErrorStatusInternal.SESSION_ALREADY_DESTROYED)
+ FulfillmentResult(ErrorStatusInternal.SESSION_NOT_FOUND)
.applyToCallback(updateRequest.assistantRequest.callbackInternal)
} else if (updateRequest.touchEventRequest != null && touchEventCallback != null) {
- touchEventCallback!!.onError(ErrorStatusInternal.SESSION_ALREADY_DESTROYED)
+ touchEventCallback!!.onError(ErrorStatusInternal.SESSION_NOT_FOUND)
}
} else if (updateRequest.assistantRequest != null) {
processAssistantUpdateRequest(updateRequest.assistantRequest)
@@ -181,7 +181,6 @@
}
/** Processes an assistant update request. */
- @Suppress("DEPRECATION")
private suspend fun processAssistantUpdateRequest(
assistantUpdateRequest: AssistantUpdateRequest,
) = withUiHandleRegistered {
@@ -193,7 +192,6 @@
) {
FulfillmentRequest.Fulfillment.Type.SYNC ->
handleSyncStatus(argumentsWrapper)
- FulfillmentRequest.Fulfillment.Type.CONFIRM -> handleConfirm()
FulfillmentRequest.Fulfillment.Type.CANCEL -> {
terminate()
FulfillmentResult(FulfillmentResponse.getDefaultInstance())
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/utils/CallbackUtils.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/utils/CallbackUtils.kt
index 536472e..5393aa1 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/utils/CallbackUtils.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/utils/CallbackUtils.kt
@@ -23,6 +23,8 @@
import androidx.appactions.interaction.capabilities.core.impl.task.exceptions.DisambigStateException
import androidx.appactions.interaction.capabilities.core.impl.task.exceptions.InvalidResolverException
import kotlin.reflect.KClass
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.withTimeout
private const val LOG_TAG = "CallbackUtils"
@@ -71,19 +73,18 @@
this.isCausedBy(
ExternalException::class
) -> ErrorStatusInternal.EXTERNAL_EXCEPTION
- this.isCausedBy(
- StructConversionException::class
- ) -> ErrorStatusInternal.STRUCT_CONVERSION_FAILURE
- this.isCausedBy(
- InvalidResolverException::class
- ) -> ErrorStatusInternal.INVALID_RESOLVER
- this.isCausedBy(
- DisambigStateException::class
- ) -> ErrorStatusInternal.UNCHANGED_DISAMBIG_STATE
+ // Handle StructConversion first, because it's a subtype of InvalidRequestException below.
+ this.isCausedBy(StructConversionException::class) ||
+ this.isCausedBy(InvalidResolverException::class) ||
+ this.isCausedBy(DisambigStateException::class)
+ -> ErrorStatusInternal.INTERNAL
+
this.isCausedBy(
InvalidRequestException::class
) -> ErrorStatusInternal.INVALID_REQUEST
- else -> ErrorStatusInternal.CANCELLED
+
+ this is TimeoutCancellationException -> ErrorStatusInternal.TIMEOUT
+ else -> ErrorStatusInternal.UNKNOWN_ERROR_STATUS
}
}
@@ -102,13 +103,21 @@
t
)
errorCallback.invoke(t.toErrorStatusInternal())
- if (!t.isCausedBy(InvalidRequestException::class)) {
- LoggerInternal.log(
- CapabilityLogger.LogLevel.ERROR,
- LOG_TAG,
- "Rethrowing exception because it is not caused by InvalidRequestException.",
- t
- )
- throw t
+ when {
+ t.isCausedBy(
+ InvalidRequestException::class
+ ) || t.isCausedBy(
+ CancellationException::class
+ ) -> Unit
+ else -> {
+ LoggerInternal.log(
+ CapabilityLogger.LogLevel.ERROR,
+ LOG_TAG,
+ """Rethrowing exception because it was likely thrown from an app-implemented
+ callback.""",
+ t
+ )
+ throw t
+ }
}
}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/TextFilter.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/TextFilter.kt
new file mode 100644
index 0000000..f632cc8
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/TextFilter.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.appactions.interaction.capabilities.filters
+
+/** Filter class for text values, contains either some exact String, or a [TextMatcher] instance. */
+class TextFilter private constructor(
+ @get:JvmName("asMatcher")
+ val asMatcher: TextMatcher?,
+ @get:JvmName("asExactText")
+ val asExactText: String?
+) {
+ /** Creates a [TextFilter] instance with a [TextMatcher]. */
+ constructor(matcher: TextMatcher) : this(matcher, null)
+
+ /** Creates a [TextFilter] instance with some text to match exactly. */
+ constructor(exactText: String) : this(null, exactText)
+}
+
+/** Matches some text. */
+class TextMatcher(
+ /** The filtered text should start with this String. */
+ val startsWith: String?,
+
+ /** The filtered text should contain this String. */
+ val contains: String?
+) {
+ init {
+ require(startsWith != null || contains != null) {
+ "at least one of 'startsWith' and 'contains' must be non-null"
+ }
+ }
+}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/TimeFilter.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/TimeFilter.kt
new file mode 100644
index 0000000..169bdb4
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/TimeFilter.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.appactions.interaction.capabilities.filters
+
+import java.time.LocalTime
+
+/** Filter class for [LocalTime] values. */
+class TimeFilter(
+ @get:JvmName("asRangeFilter")
+ val asRangeFilter: TimeRangeFilter?,
+ @get:JvmName("asExactTime")
+ val asExactTime: LocalTime?
+) {
+ /** Creates a [TimeFilter] instance with a [TimeRangeFilter]. */
+ constructor(rangeFilter: TimeRangeFilter) : this(rangeFilter, null)
+ /** Creates a [TimeFilter] instance with a [LocalTime]. */
+ constructor(exactTime: LocalTime) : this(null, exactTime)
+}
+
+/** Matches [LocalTime] values within a range. * If only minTime is non-null, any [LocalTime] at or after minTime satisfies this filter.
+ * If only maxTime is non-null, any [LocalTime] at or before maxTime satisfies this filter.
+ */
+class TimeRangeFilter(
+ /** The minimum time to satisfy this filter. (inclusive) */
+ val minTime: LocalTime?,
+ /** The maximum time to satisfy this filter. (inclusive) */
+ val maxTime: LocalTime?
+) {
+ init {
+ require(minTime != null || maxTime != null) {
+ "at least one of 'minTime' and 'maxTime' must be non-null"
+ }
+ }
+}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/package-info.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/package-info.java
new file mode 100644
index 0000000..3d84cde
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+package androidx.appactions.interaction.capabilities.filters;
+
+import androidx.annotation.RestrictTo;
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/properties/NameFilter.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/properties/NameFilter.kt
new file mode 100644
index 0000000..02dbc12
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/properties/NameFilter.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.
+ */
+
+package androidx.appactions.interaction.capabilities.filters.properties
+
+import androidx.appactions.builtintypes.properties.Name
+import androidx.appactions.interaction.capabilities.filters.TextFilter
+
+/**
+ * Represents a filter for the [Name] property.
+ */
+class NameFilter(
+ /**
+ * Matches some text for [Name.asText].
+ */
+ @get:JvmName("whenText")
+ val whenText: TextFilter?
+)
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/types/ThingFilter.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/types/ThingFilter.kt
new file mode 100644
index 0000000..39b532e
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/filters/types/ThingFilter.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.appactions.interaction.capabilities.filters.types
+
+import androidx.appactions.interaction.capabilities.filters.properties.NameFilter
+
+/**
+ * Represents a filter for [androidx.appactions.builtintypes.types.Thing] objects.
+ * * All nested filters should be satisfied for an object to satisfy this filter.
+ */
+interface ThingFilter {
+ /**
+ * The exact id of the [Thing] being looked up. If non-null, other fields can be ignored.
+ */
+ val id: String?
+
+ /**
+ * The filter for the name property of [Thing].
+ */
+ val nameFilter: NameFilter?
+}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/BuiltInTypeSerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/BuiltInTypeSerializer.kt
new file mode 100644
index 0000000..7c783f8
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/BuiltInTypeSerializer.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers
+
+import androidx.appactions.builtintypes.types.Thing
+import androidx.appactions.interaction.protobuf.Struct
+
+/**
+ * Serializes some structured Built-in Type [T] to and from a [Struct] i.e. a JSON object.
+ *
+ * Structured Built-in Types refer to the top-level types under
+ * `androidx.appactions.builtintypes.types.*` that are [Thing] or its subtypes.
+ */
+interface BuiltInTypeSerializer<T : Thing> {
+ fun serialize(instance: T): Struct
+ fun deserialize(jsonObj: Struct): T
+
+ /**
+ * Returns the set of valid [CanonicalValue]s that can be used within the context of [T].
+ *
+ * For example,
+ *
+ * ```kt
+ * alarmSerializer.getCanonicalValues(DisambiguatingDescription.CanonicalValue::class.java)
+ * ```
+ *
+ * returns all the values for `Alarm.DisambiguatingDescriptionValue`.
+ */
+ fun <CanonicalValue> getCanonicalValues(cls: Class<CanonicalValue>): List<CanonicalValue>
+}
+
+inline fun <reified CanonicalValue, T : Thing> BuiltInTypeSerializer<T>.getCanonicalValues():
+ List<CanonicalValue> {
+ return getCanonicalValues(CanonicalValue::class.java)
+}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/package-info.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/package-info.java
new file mode 100644
index 0000000..f9b204c
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+package androidx.appactions.interaction.capabilities.serializers;
+
+import androidx.annotation.RestrictTo;
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/ByDaySerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/ByDaySerializer.kt
new file mode 100644
index 0000000..5145b17
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/ByDaySerializer.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.properties
+
+import androidx.appactions.builtintypes.properties.ByDay
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.UnionTypeSpec
+import androidx.appactions.interaction.capabilities.serializers.types.DAY_OF_WEEK_TYPE_SPEC
+
+val BY_DAY_TYPE_SPEC = UnionTypeSpec.Builder<ByDay>().bindMemberType(
+ memberGetter = ByDay::asDayOfWeek,
+ ctor = { ByDay(it) },
+ typeSpec = DAY_OF_WEEK_TYPE_SPEC,
+).bindMemberType(
+ memberGetter = ByDay::asText,
+ ctor = { ByDay(it) },
+ typeSpec = TypeSpec.STRING_TYPE_SPEC,
+).build()
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/DisambiguatingDescriptionSerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/DisambiguatingDescriptionSerializer.kt
new file mode 100644
index 0000000..f253638
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/DisambiguatingDescriptionSerializer.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.properties
+
+import androidx.appactions.builtintypes.properties.DisambiguatingDescription
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.UnionTypeSpec
+
+val TEXT_ONLY_DISAMBIGUATING_DESCRIPTION_TYPE_SPEC = UnionTypeSpec.Builder<
+ DisambiguatingDescription
+>().bindMemberType(
+ memberGetter = DisambiguatingDescription::asText,
+ ctor = { DisambiguatingDescription(it) },
+ typeSpec = TypeSpec.STRING_TYPE_SPEC,
+).build()
+
+/** Create a TypeSpec with a specific nested CanonicalValue type spec. */
+fun createDisambiguatingDescriptionTypeSpec(
+ canonicalValueTypeSpec: TypeSpec<DisambiguatingDescription.CanonicalValue>
+): TypeSpec<DisambiguatingDescription> = UnionTypeSpec.Builder<
+ DisambiguatingDescription
+>().bindMemberType(
+ memberGetter = { it.asCanonicalValue },
+ ctor = { DisambiguatingDescription(it) },
+ typeSpec = canonicalValueTypeSpec,
+).bindMemberType(
+ memberGetter = DisambiguatingDescription::asText,
+ ctor = { DisambiguatingDescription(it) },
+ typeSpec = TypeSpec.STRING_TYPE_SPEC,
+).build()
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/EndDateSerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/EndDateSerializer.kt
new file mode 100644
index 0000000..1c12fe3
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/EndDateSerializer.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.properties
+
+import androidx.appactions.builtintypes.properties.EndDate
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.UnionTypeSpec
+
+val END_DATE_TYPE_SPEC = UnionTypeSpec.Builder<EndDate>().bindMemberType(
+ memberGetter = EndDate::asDate,
+ ctor = { EndDate(it) },
+ typeSpec = TypeSpec.LOCAL_DATE_TYPE_SPEC
+).bindMemberType(
+ memberGetter = EndDate::asLocalDateTime,
+ ctor = { EndDate(it) },
+ typeSpec = TypeSpec.LOCAL_DATE_TIME_TYPE_SPEC
+).bindMemberType(
+ memberGetter = EndDate::asInstant,
+ ctor = { EndDate(it) },
+ typeSpec = TypeSpec.INSTANT_TYPE_SPEC
+).build()
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/EndTimeSerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/EndTimeSerializer.kt
new file mode 100644
index 0000000..4b2386f
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/EndTimeSerializer.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.properties
+
+import androidx.appactions.builtintypes.properties.EndTime
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.UnionTypeSpec
+
+val END_TIME_TYPE_SPEC = UnionTypeSpec.Builder<EndTime>().bindMemberType(
+ memberGetter = EndTime::asTime,
+ ctor = { EndTime(it) },
+ typeSpec = TypeSpec.LOCAL_TIME_TYPE_SPEC
+).bindMemberType(
+ memberGetter = EndTime::asLocalDateTime,
+ ctor = { EndTime(it) },
+ typeSpec = TypeSpec.LOCAL_DATE_TIME_TYPE_SPEC
+).bindMemberType(
+ memberGetter = EndTime::asInstant,
+ ctor = { EndTime(it) },
+ typeSpec = TypeSpec.INSTANT_TYPE_SPEC
+).build()
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/ExceptDate.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/ExceptDate.kt
new file mode 100644
index 0000000..868f941
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/ExceptDate.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.properties
+
+import androidx.appactions.builtintypes.properties.ExceptDate
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.UnionTypeSpec
+
+val EXCEPT_DATE_TYPE_SPEC = UnionTypeSpec.Builder<ExceptDate>().bindMemberType(
+ memberGetter = ExceptDate::asDate,
+ ctor = { ExceptDate(it) },
+ typeSpec = TypeSpec.LOCAL_DATE_TYPE_SPEC
+).bindMemberType(
+ memberGetter = ExceptDate::asLocalDateTime,
+ ctor = { ExceptDate(it) },
+ typeSpec = TypeSpec.LOCAL_DATE_TIME_TYPE_SPEC
+).bindMemberType(
+ memberGetter = ExceptDate::asInstant,
+ ctor = { ExceptDate(it) },
+ typeSpec = TypeSpec.INSTANT_TYPE_SPEC
+).build()
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/NameSerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/NameSerializer.kt
new file mode 100644
index 0000000..7fa89eb
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/NameSerializer.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.properties
+
+import androidx.appactions.builtintypes.properties.Name
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.UnionTypeSpec
+
+val NAME_TYPE_SPEC = UnionTypeSpec.Builder<Name>().bindMemberType(
+ memberGetter = Name::asText,
+ ctor = { Name(it) },
+ typeSpec = TypeSpec.STRING_TYPE_SPEC,
+).build()
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/RepeatFrequencySerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/RepeatFrequencySerializer.kt
new file mode 100644
index 0000000..60aaaa0
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/RepeatFrequencySerializer.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.properties
+
+import androidx.appactions.builtintypes.properties.RepeatFrequency
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.UnionTypeSpec
+
+/** Note: The order of [bindMemberType] calls matters here. */
+val REPEAT_FREQUENCY_TYPE_SPEC = UnionTypeSpec.Builder<RepeatFrequency>().bindMemberType(
+ memberGetter = RepeatFrequency::asDuration,
+ ctor = { RepeatFrequency(it) },
+ typeSpec = TypeSpec.DURATION_TYPE_SPEC
+).bindMemberType(
+ memberGetter = RepeatFrequency::asText,
+ ctor = { RepeatFrequency(it) },
+ typeSpec = TypeSpec.STRING_TYPE_SPEC
+).build()
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/StartDateSerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/StartDateSerializer.kt
new file mode 100644
index 0000000..fdd7042
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/StartDateSerializer.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.properties
+
+import androidx.appactions.builtintypes.properties.StartDate
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.UnionTypeSpec
+
+val START_DATE_TYPE_SPEC = UnionTypeSpec.Builder<StartDate>().bindMemberType(
+ memberGetter = StartDate::asDate,
+ ctor = { StartDate(it) },
+ typeSpec = TypeSpec.LOCAL_DATE_TYPE_SPEC
+).bindMemberType(
+ memberGetter = StartDate::asLocalDateTime,
+ ctor = { StartDate(it) },
+ typeSpec = TypeSpec.LOCAL_DATE_TIME_TYPE_SPEC
+).bindMemberType(
+ memberGetter = StartDate::asInstant,
+ ctor = { StartDate(it) },
+ typeSpec = TypeSpec.INSTANT_TYPE_SPEC
+).build()
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/StartTimeTypeSpec.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/StartTimeTypeSpec.kt
new file mode 100644
index 0000000..3d2fc6b
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/properties/StartTimeTypeSpec.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.properties
+
+import androidx.appactions.builtintypes.properties.StartTime
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.UnionTypeSpec
+
+val START_TIME_TYPE_SPEC = UnionTypeSpec.Builder<StartTime>().bindMemberType(
+ memberGetter = StartTime::asTime,
+ ctor = { StartTime(it) },
+ typeSpec = TypeSpec.LOCAL_TIME_TYPE_SPEC
+).bindMemberType(
+ memberGetter = StartTime::asLocalDateTime,
+ ctor = { StartTime(it) },
+ typeSpec = TypeSpec.LOCAL_DATE_TIME_TYPE_SPEC
+).bindMemberType(
+ memberGetter = StartTime::asInstant,
+ ctor = { StartTime(it) },
+ typeSpec = TypeSpec.INSTANT_TYPE_SPEC
+).build()
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/AlarmSerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/AlarmSerializer.kt
new file mode 100644
index 0000000..a794bbf
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/AlarmSerializer.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.appactions.interaction.capabilities.serializers.types
+
+import androidx.appactions.builtintypes.properties.DisambiguatingDescription
+import androidx.appactions.builtintypes.types.Alarm
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpecBuilder
+import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException
+import androidx.appactions.interaction.capabilities.serializers.properties.NAME_TYPE_SPEC
+import androidx.appactions.interaction.capabilities.serializers.properties.createDisambiguatingDescriptionTypeSpec
+
+private val supportedDisambiguatingDescriptionValues = listOf(
+ Alarm.DisambiguatingDescriptionValue.FAMILY_BELL
+)
+
+val ALARM_DISAMBIGUATING_DESCRIPTION_VALUE_TYPE_SPEC = TypeSpec.createStringBasedTypeSpec<
+ DisambiguatingDescription.CanonicalValue
+>(
+ toString = DisambiguatingDescription.CanonicalValue::textValue,
+ fromString = {
+ str ->
+ supportedDisambiguatingDescriptionValues.find {
+ it.textValue == str
+ } ?: throw StructConversionException(
+ "failed to deserialize Alarm.DisambiguatingDescriptionValue with textValue=$str"
+ )
+ }
+)
+
+val ALARM_TYPE_SPEC: TypeSpec<Alarm> = TypeSpecBuilder.newBuilder(
+ "Alarm",
+ Alarm::Builder,
+ Alarm.Builder<*>::build
+).bindStringField(
+ "namespace",
+ { it.namespace },
+ Alarm.Builder<*>::setNamespace
+).bindSpecField(
+ "alarmSchedule",
+ { it.alarmSchedule },
+ Alarm.Builder<*>::setAlarmSchedule,
+ SCHEDULE_TYPE_SPEC
+).bindSpecField(
+ "disambiguatingDescription",
+ { it.disambiguatingDescription },
+ Alarm.Builder<*>::setDisambiguatingDescription,
+ createDisambiguatingDescriptionTypeSpec(ALARM_DISAMBIGUATING_DESCRIPTION_VALUE_TYPE_SPEC)
+).bindSpecField(
+ "name",
+ { it.name },
+ Alarm.Builder<*>::setName,
+ NAME_TYPE_SPEC
+).bindStringField(
+ "identifier",
+ { it.identifier },
+ Alarm.Builder<*>::setIdentifier
+).bindIdentifier {
+ it.identifier
+}.build()
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/DayOfWeekSerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/DayOfWeekSerializer.kt
new file mode 100644
index 0000000..ad57f19
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/DayOfWeekSerializer.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.appactions.interaction.capabilities.serializers.types
+
+import androidx.appactions.builtintypes.types.DayOfWeek
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException
+
+private val supportedDayOfWeekValues = listOf(
+ DayOfWeek.FRIDAY, DayOfWeek.MONDAY,
+ DayOfWeek.PUBLIC_HOLIDAYS,
+ DayOfWeek.SATURDAY,
+ DayOfWeek.SUNDAY,
+ DayOfWeek.THURSDAY,
+ DayOfWeek.TUESDAY,
+ DayOfWeek.WEDNESDAY
+)
+
+val DAY_OF_WEEK_TYPE_SPEC = TypeSpec.createStringBasedTypeSpec<DayOfWeek>(
+ toString = DayOfWeek::canonicalUrl,
+ fromString = {
+ str ->
+ supportedDayOfWeekValues.find {
+ it.canonicalUrl == str
+ } ?: throw StructConversionException(
+ "failed to deserialize DayOfWeek with canonicalUrl=$str"
+ )
+ }
+)
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/ScheduleSerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/ScheduleSerializer.kt
new file mode 100644
index 0000000..e9ab3d9
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/ScheduleSerializer.kt
@@ -0,0 +1,111 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.types
+
+import androidx.appactions.builtintypes.types.Schedule
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpecBuilder
+import androidx.appactions.interaction.capabilities.serializers.properties.BY_DAY_TYPE_SPEC
+import androidx.appactions.interaction.capabilities.serializers.properties.END_DATE_TYPE_SPEC
+import androidx.appactions.interaction.capabilities.serializers.properties.END_TIME_TYPE_SPEC
+import androidx.appactions.interaction.capabilities.serializers.properties.EXCEPT_DATE_TYPE_SPEC
+import androidx.appactions.interaction.capabilities.serializers.properties.NAME_TYPE_SPEC
+import androidx.appactions.interaction.capabilities.serializers.properties.REPEAT_FREQUENCY_TYPE_SPEC
+import androidx.appactions.interaction.capabilities.serializers.properties.START_DATE_TYPE_SPEC
+import androidx.appactions.interaction.capabilities.serializers.properties.START_TIME_TYPE_SPEC
+import androidx.appactions.interaction.capabilities.serializers.properties.TEXT_ONLY_DISAMBIGUATING_DESCRIPTION_TYPE_SPEC
+
+val SCHEDULE_TYPE_SPEC: TypeSpec<Schedule> = TypeSpecBuilder.newBuilder(
+ "Schedule",
+ Schedule::Builder,
+ Schedule.Builder<*>::build
+).bindRepeatedSpecField(
+ "byDays",
+ { it.byDays },
+ Schedule.Builder<*>::addByDays,
+ BY_DAY_TYPE_SPEC
+).bindRepeatedSpecField(
+ "byMonths",
+ { it.byMonths },
+ Schedule.Builder<*>::addByMonths,
+ TypeSpec.LONG_TYPE_SPEC
+).bindRepeatedSpecField(
+ "byMonthDays",
+ { it.byMonthDays },
+ Schedule.Builder<*>::addByMonthDays,
+ TypeSpec.LONG_TYPE_SPEC
+).bindRepeatedSpecField(
+ "byMonthWeeks",
+ { it.byMonthWeeks },
+ Schedule.Builder<*>::addByMonthWeeks,
+ TypeSpec.LONG_TYPE_SPEC
+).bindSpecField(
+ "endDate",
+ { it.endDate },
+ Schedule.Builder<*>::setEndDate,
+ END_DATE_TYPE_SPEC
+).bindSpecField(
+ "endTime",
+ { it.endTime },
+ Schedule.Builder<*>::setEndTime,
+ END_TIME_TYPE_SPEC
+).bindSpecField(
+ "exceptDate",
+ { it.exceptDate },
+ Schedule.Builder<*>::setExceptDate,
+ EXCEPT_DATE_TYPE_SPEC
+).bindSpecField(
+ "repeatCount",
+ { it.repeatCount },
+ Schedule.Builder<*>::setRepeatCount,
+ TypeSpec.LONG_TYPE_SPEC
+).bindSpecField(
+ "repeatFrequency",
+ { it.repeatFrequency },
+ Schedule.Builder<*>::setRepeatFrequency,
+ REPEAT_FREQUENCY_TYPE_SPEC
+).bindStringField(
+ "scheduleTimeZone",
+ { it.scheduleTimezone },
+ Schedule.Builder<*>::setScheduleTimezone
+).bindSpecField(
+ "startDate",
+ { it.startDate },
+ Schedule.Builder<*>::setStartDate,
+ START_DATE_TYPE_SPEC
+).bindSpecField(
+ "startTime",
+ { it.startTime },
+ Schedule.Builder<*>::setStartTime,
+ START_TIME_TYPE_SPEC
+).bindSpecField(
+ "disambiguatingDescription",
+ { it.disambiguatingDescription },
+ Schedule.Builder<*>::setDisambiguatingDescription,
+ TEXT_ONLY_DISAMBIGUATING_DESCRIPTION_TYPE_SPEC
+).bindSpecField(
+ "name",
+ { it.name },
+ Schedule.Builder<*>::setName,
+ NAME_TYPE_SPEC
+).bindStringField(
+ "identifier",
+ { it.identifier },
+ Schedule.Builder<*>::setIdentifier
+).bindIdentifier {
+ it.identifier
+}.build()
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/TimerSerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/TimerSerializer.kt
new file mode 100644
index 0000000..c86674b
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/TimerSerializer.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.appactions.interaction.capabilities.serializers.types
+
+import androidx.appactions.builtintypes.types.Timer
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpecBuilder
+import androidx.appactions.interaction.capabilities.serializers.properties.NAME_TYPE_SPEC
+import androidx.appactions.interaction.capabilities.serializers.properties.TEXT_ONLY_DISAMBIGUATING_DESCRIPTION_TYPE_SPEC
+
+@JvmField
+val TIMER_TYPE_SPEC: TypeSpec<Timer> = TypeSpecBuilder.newBuilder(
+ "Timer",
+ Timer::Builder,
+ Timer.Builder<*>::build
+).bindStringField(
+ "namespace",
+ { it.namespace },
+ Timer.Builder<*>::setNamespace
+).bindSpecField(
+ "duration",
+ { it.duration },
+ Timer.Builder<*>::setDuration,
+ TypeSpec.DURATION_TYPE_SPEC
+).bindSpecField(
+ "disambiguatingDescription",
+ { it.disambiguatingDescription },
+ Timer.Builder<*>::setDisambiguatingDescription,
+ TEXT_ONLY_DISAMBIGUATING_DESCRIPTION_TYPE_SPEC
+).bindSpecField(
+ "name",
+ { it.name },
+ Timer.Builder<*>::setName,
+ NAME_TYPE_SPEC
+).bindStringField(
+ "identifier",
+ { it.identifier },
+ Timer.Builder<*>::setIdentifier
+).bindIdentifier {
+ it.identifier
+}.build()
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/AlarmProvider.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/AlarmProvider.kt
index 8e2af97..901bf40 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/AlarmProvider.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/AlarmProvider.kt
@@ -16,14 +16,14 @@
package androidx.appactions.interaction.capabilities.core.entity
-import androidx.appactions.builtintypes.experimental.types.Alarm
-import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
+import androidx.appactions.builtintypes.types.Alarm
+import androidx.appactions.interaction.capabilities.serializers.types.ALARM_TYPE_SPEC
/** Internal testing object for entity provider */
class AlarmProvider internal constructor(
override val id: String,
private var response: EntityLookupResponse<Alarm>,
-) : EntityProvider<Alarm>(TypeConverters.ALARM_TYPE_SPEC) {
+) : EntityProvider<Alarm>(ALARM_TYPE_SPEC) {
override suspend fun lookup(request: EntityLookupRequest<Alarm>):
EntityLookupResponse<Alarm> = response
}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/EntityProviderTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/EntityProviderTest.kt
index cb9f91e..fcd1086 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/EntityProviderTest.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/EntityProviderTest.kt
@@ -16,7 +16,7 @@
package androidx.appactions.interaction.capabilities.core.entity
-import androidx.appactions.builtintypes.experimental.types.Alarm
+import androidx.appactions.builtintypes.types.Alarm
import androidx.appactions.interaction.proto.Entity
import androidx.appactions.interaction.proto.GroundingRequest
import androidx.appactions.interaction.proto.GroundingResponse
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityTest.kt
index 322f1d7..44b5487 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityTest.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityTest.kt
@@ -25,6 +25,7 @@
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
+import androidx.appactions.interaction.capabilities.core.impl.spec.BoundProperty
import androidx.appactions.interaction.capabilities.core.properties.Property
import androidx.appactions.interaction.capabilities.core.properties.StringValue
import androidx.appactions.interaction.capabilities.core.testing.spec.Arguments
@@ -50,7 +51,6 @@
import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
-@Suppress("UNCHECKED_CAST")
class SingleTurnCapabilityTest {
private val hostProperties =
HostProperties.Builder().setMaxHostSizeDp(SizeF(300f, 500f)).build()
@@ -59,15 +59,19 @@
@Test
fun appAction_computedProperty() {
val mutableEntityList = mutableListOf<StringValue>()
+ val dynamicStringProperty = Property.Builder<StringValue>()
+ .setPossibleValueSupplier(
+ mutableEntityList::toList
+ ).build()
val capability = SingleTurnCapabilityImpl(
id = "capabilityId",
actionSpec = ACTION_SPEC,
- property = mutableMapOf(
- "requiredEntity" to Property
- .Builder<StringValue>()
- .setPossibleValueSupplier(
- mutableEntityList::toList
- ).build()
+ boundProperties = listOf(
+ BoundProperty(
+ "requiredString",
+ dynamicStringProperty,
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
),
executionCallback = ExecutionCallback<Arguments, Output> {
ExecutionResult.Builder<Output>().build()
@@ -126,17 +130,22 @@
)
.build()
}
- val property = mutableMapOf<String, Property<*>>()
- property.put(
- "requiredString",
- Property.Builder<StringValue>().build()
- )
- property.put("optionalString", Property.prohibited<StringValue>())
val capability =
SingleTurnCapabilityImpl(
id = "capabilityId",
actionSpec = ACTION_SPEC,
- property = property,
+ boundProperties = listOf(
+ BoundProperty(
+ "requiredString",
+ Property.Builder<StringValue>().build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ ),
+ BoundProperty(
+ "optionalString",
+ Property.prohibited<StringValue>(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
+ ),
executionCallback = executionCallback
)
@@ -184,17 +193,22 @@
fun oneShotCapability_exceptionInExecutionCallback() {
val executionCallback =
ExecutionCallback<Arguments, Output> { throw IllegalStateException("") }
- val property = mutableMapOf<String, Property<*>>()
- property.put(
- "requiredString",
- Property.Builder<StringValue>().build()
- )
- property.put("optionalString", Property.prohibited<StringValue>())
val capability =
SingleTurnCapabilityImpl(
id = "capabilityId",
actionSpec = ACTION_SPEC,
- property = property,
+ boundProperties = listOf(
+ BoundProperty(
+ "requiredString",
+ Property.Builder<StringValue>().build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ ),
+ BoundProperty(
+ "optionalString",
+ Property.prohibited<StringValue>(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
+ ),
executionCallback = executionCallback
)
@@ -219,16 +233,17 @@
fun oneShotSession_uiHandle_withExecutionCallback() {
val executionCallback =
ExecutionCallback<Arguments, Output> { ExecutionResult.Builder<Output>().build() }
- val property = mutableMapOf<String, Property<*>>()
- property.put(
- "requiredString",
- Property.Builder<StringValue>().build()
- )
val capability =
SingleTurnCapabilityImpl(
id = "capabilityId",
actionSpec = ACTION_SPEC,
- property = property,
+ boundProperties = listOf(
+ BoundProperty(
+ "requiredString",
+ Property.Builder<StringValue>().build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ ),
+ ),
executionCallback = executionCallback
)
val session = capability.createSession(fakeSessionId, hostProperties)
@@ -241,16 +256,17 @@
ExecutionCallbackAsync<Arguments, Output> {
Futures.immediateFuture(ExecutionResult.Builder<Output>().build())
}
- val property = mutableMapOf<String, Property<*>>()
- property.put(
- "requiredString",
- Property.Builder<StringValue>().build()
- )
val capability =
SingleTurnCapabilityImpl(
id = "capabilityId",
actionSpec = ACTION_SPEC,
- property = property,
+ boundProperties = listOf(
+ BoundProperty(
+ "requiredString",
+ Property.Builder<StringValue>().build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
+ ),
executionCallback = executionCallbackAsync.toExecutionCallback()
)
val session = capability.createSession(fakeSessionId, hostProperties)
@@ -266,15 +282,16 @@
argumentChannel.send(it)
executionResultChannel.receive()
}
- val property = mutableMapOf<String, Property<*>>()
- property.put(
- "requiredString",
- Property.Builder<StringValue>().build()
- )
val capability = SingleTurnCapabilityImpl(
id = "capabilityId",
actionSpec = ACTION_SPEC,
- property = property,
+ boundProperties = listOf(
+ BoundProperty(
+ "requiredString",
+ Property.Builder<StringValue>().build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
+ ),
executionCallback = executionCallback
)
val session1 = capability.createSession("session1", hostProperties)
@@ -331,19 +348,13 @@
.setOutput(Output::class.java)
.bindParameter(
"requiredString",
- { properties -> properties["requiredEntity"] as Property<StringValue> },
Arguments.Builder::setRequiredStringField,
TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
)
.bindParameter(
"optionalString",
- { properties ->
- properties["optionalString"] as? Property<StringValue>
- },
Arguments.Builder::setOptionalStringField,
TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
)
.bindOutput(
"optionalStringOutput",
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConvertersTest.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConvertersTest.java
index ea60add..18f6c6a 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConvertersTest.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConvertersTest.java
@@ -25,7 +25,7 @@
import static androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.PARTICIPANT_TYPE_SPEC;
import static androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.RECIPIENT_TYPE_SPEC;
import static androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.SAFETY_CHECK_TYPE_SPEC;
-import static androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.TIMER_TYPE_SPEC;
+import static androidx.appactions.interaction.capabilities.serializers.types.TimerSerializerKt.TIMER_TYPE_SPEC;
import static com.google.common.truth.Truth.assertThat;
@@ -41,7 +41,7 @@
import androidx.appactions.builtintypes.experimental.types.Message;
import androidx.appactions.builtintypes.experimental.types.Person;
import androidx.appactions.builtintypes.experimental.types.SafetyCheck;
-import androidx.appactions.builtintypes.experimental.types.Timer;
+import androidx.appactions.builtintypes.types.Timer;
import androidx.appactions.interaction.capabilities.core.SearchAction;
import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException;
import androidx.appactions.interaction.proto.Entity;
@@ -86,10 +86,7 @@
.addAttendee(new Attendee(PERSON_JAVA_THING_2))
.build();
private static final Call CALL_JAVA_THING =
- Call.Builder()
- .setIdentifier("id")
- .addParticipant(PERSON_JAVA_THING)
- .build();
+ Call.Builder().setIdentifier("id").addParticipant(PERSON_JAVA_THING).build();
private static final Message MESSAGE_JAVA_THING =
Message.Builder()
.setIdentifier("id")
@@ -107,8 +104,7 @@
Struct.newBuilder()
.putFields("@type", Value.newBuilder().setStringValue("Person").build())
.putFields("identifier", Value.newBuilder().setStringValue("id").build())
- .putFields("name",
- Value.newBuilder().setStringValue("name").build())
+ .putFields("name", Value.newBuilder().setStringValue("name").build())
.putFields("email", Value.newBuilder().setStringValue("email").build())
.putFields("telephone", Value.newBuilder().setStringValue("telephone").build())
.build();
@@ -209,8 +205,8 @@
ParamValue.newBuilder().setStringValue("hello world").build());
assertThat(
- SlotTypeConverter.ofSingular(TypeConverters.STRING_PARAM_VALUE_CONVERTER)
- .convert(input))
+ SlotTypeConverter.ofSingular(TypeConverters.STRING_PARAM_VALUE_CONVERTER)
+ .convert(input))
.isEqualTo("hello world");
}
@@ -238,8 +234,8 @@
assertThat(EntityConverter.Companion.of(LIST_ITEM_TYPE_SPEC).convert(listItem))
.isEqualTo(listItemProto);
assertThat(
- ParamValueConverter.Companion.of(LIST_ITEM_TYPE_SPEC)
- .fromParamValue(toParamValue(listItemStruct, "itemId")))
+ ParamValueConverter.Companion.of(LIST_ITEM_TYPE_SPEC)
+ .fromParamValue(toParamValue(listItemStruct, "itemId")))
.isEqualTo(listItem);
}
@@ -330,8 +326,10 @@
assertThat(EntityConverter.Companion.of(ITEM_LIST_TYPE_SPEC).convert(itemList))
.isEqualTo(itemListProto);
- assertThat(ParamValueConverter.Companion.of(ITEM_LIST_TYPE_SPEC)
- .fromParamValue(toParamValue(itemListStruct, "testList"))).isEqualTo(itemList);
+ assertThat(
+ ParamValueConverter.Companion.of(ITEM_LIST_TYPE_SPEC)
+ .fromParamValue(toParamValue(itemListStruct, "testList")))
+ .isEqualTo(itemList);
}
@Test
@@ -363,8 +361,10 @@
ParamValueConverter.Companion.of(RECIPIENT_TYPE_SPEC);
ParamValue paramValue =
ParamValue.newBuilder()
- .setIdentifier(PERSON_JAVA_THING.getIdentifier() == null ? "id" :
- PERSON_JAVA_THING.getIdentifier())
+ .setIdentifier(
+ PERSON_JAVA_THING.getIdentifier() == null
+ ? "id"
+ : PERSON_JAVA_THING.getIdentifier())
.setStructValue(PERSON_STRUCT)
.build();
Recipient recipient = new Recipient(PERSON_JAVA_THING);
@@ -452,9 +452,7 @@
() ->
SlotTypeConverter.ofSingular(BOOLEAN_PARAM_VALUE_CONVERTER)
.convert(input));
- assertThat(thrown)
- .hasMessageThat()
- .matches("cannot convert .+ into Value.");
+ assertThat(thrown).hasMessageThat().matches("cannot convert .+ into Value.");
}
@Test
@@ -467,9 +465,7 @@
() ->
SlotTypeConverter.ofSingular(INTEGER_PARAM_VALUE_CONVERTER)
.convert(input));
- assertThat(thrown)
- .hasMessageThat()
- .matches("cannot convert .+ into Value.");
+ assertThat(thrown).hasMessageThat().matches("cannot convert .+ into Value.");
}
@Test
@@ -511,9 +507,7 @@
SlotTypeConverter.ofSingular(
TypeConverters.LOCAL_DATE_PARAM_VALUE_CONVERTER)
.convert(input));
- assertThat(thrown)
- .hasMessageThat()
- .isEqualTo("Cannot parse date because string_value is missing from ParamValue.");
+ assertThat(thrown).hasMessageThat().matches("cannot convert .+ into Value.");
}
@Test
@@ -554,9 +548,7 @@
SlotTypeConverter.ofSingular(
TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER)
.convert(input));
- assertThat(thrown)
- .hasMessageThat()
- .isEqualTo("Cannot parse time because string_value is missing from ParamValue.");
+ assertThat(thrown).hasMessageThat().matches("cannot convert .+ into Value.");
}
@Test
@@ -604,7 +596,7 @@
@Test
public void zonedDateTime_success() throws Exception {
ParamValueConverter<ZonedDateTime> converter =
- TypeConverters.ZONED_DATETIME_PARAM_VALUE_CONVERTER;
+ TypeConverters.ZONED_DATE_TIME_PARAM_VALUE_CONVERTER;
ParamValue paramValue =
ParamValue.newBuilder().setStringValue("2018-06-17T15:10:05Z").build();
ZonedDateTime zonedDateTime = ZonedDateTime.of(2018, 6, 17, 15, 10, 5, 0, ZoneOffset.UTC);
@@ -626,7 +618,8 @@
StructConversionException.class,
() ->
SlotTypeConverter.ofSingular(
- TypeConverters.ZONED_DATETIME_PARAM_VALUE_CONVERTER)
+ TypeConverters
+ .ZONED_DATE_TIME_PARAM_VALUE_CONVERTER)
.convert(input));
assertThat(thrown)
.hasMessageThat()
@@ -643,19 +636,16 @@
StructConversionException.class,
() ->
SlotTypeConverter.ofSingular(
- TypeConverters.ZONED_DATETIME_PARAM_VALUE_CONVERTER)
+ TypeConverters
+ .ZONED_DATE_TIME_PARAM_VALUE_CONVERTER)
.convert(input));
- assertThat(thrown)
- .hasMessageThat()
- .isEqualTo(
- "Cannot parse datetime because string_value is missing from ParamValue.");
+ assertThat(thrown).hasMessageThat().contains("expected Value.stringValue to be present");
}
@Test
public void duration_success() throws Exception {
ParamValueConverter<Duration> converter = TypeConverters.DURATION_PARAM_VALUE_CONVERTER;
- ParamValue paramValue =
- ParamValue.newBuilder().setStringValue("PT5M").build();
+ ParamValue paramValue = ParamValue.newBuilder().setStringValue("PT5M").build();
Duration duration = Duration.ofMinutes(5);
assertThat(converter.fromParamValue(paramValue)).isEqualTo(duration);
@@ -676,8 +666,7 @@
.convert(input));
assertThat(thrown)
.hasMessageThat()
- .isEqualTo(
- "Cannot parse duration because string_value is missing from ParamValue.");
+ .contains("expected Value.stringValue to be present");
}
@Test
@@ -753,21 +742,21 @@
Timer timer = Timer.Builder().setIdentifier("abc").build();
assertThat(
- paramValueConverter.fromParamValue(
- ParamValue.newBuilder()
- .setStructValue(
- Struct.newBuilder()
- .putFields(
- "@type",
- Value.newBuilder()
- .setStringValue("Timer")
- .build())
- .putFields(
- "identifier",
- Value.newBuilder()
- .setStringValue("abc")
- .build()))
- .build()))
+ paramValueConverter.fromParamValue(
+ ParamValue.newBuilder()
+ .setStructValue(
+ Struct.newBuilder()
+ .putFields(
+ "@type",
+ Value.newBuilder()
+ .setStringValue("Timer")
+ .build())
+ .putFields(
+ "identifier",
+ Value.newBuilder()
+ .setStringValue("abc")
+ .build()))
+ .build()))
.isEqualTo(timer);
}
@@ -784,8 +773,8 @@
@Test
public void toParamValues_message_success() {
assertThat(
- ParamValueConverter.Companion.of(MESSAGE_TYPE_SPEC)
- .toParamValue(MESSAGE_JAVA_THING))
+ ParamValueConverter.Companion.of(MESSAGE_TYPE_SPEC)
+ .toParamValue(MESSAGE_JAVA_THING))
.isEqualTo(
ParamValue.newBuilder()
.setStructValue(MESSAGE_STRUCT)
@@ -796,8 +785,8 @@
@Test
public void toParamValues_safetyCheck_success() {
assertThat(
- ParamValueConverter.Companion.of(SAFETY_CHECK_TYPE_SPEC)
- .toParamValue(SAFETY_CHECK_JAVA_THING))
+ ParamValueConverter.Companion.of(SAFETY_CHECK_TYPE_SPEC)
+ .toParamValue(SAFETY_CHECK_JAVA_THING))
.isEqualTo(
ParamValue.newBuilder()
.setStructValue(SAFETY_CHECK_STRUCT)
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/UnionTypeSpecTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/UnionTypeSpecTest.kt
index 74057e2..1aaa4a3 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/UnionTypeSpecTest.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/UnionTypeSpecTest.kt
@@ -16,8 +16,10 @@
package androidx.appactions.interaction.capabilities.core.impl.converters
-import androidx.appactions.builtintypes.experimental.types.Alarm
-import androidx.appactions.builtintypes.experimental.types.Timer
+import androidx.appactions.builtintypes.types.Alarm
+import androidx.appactions.builtintypes.types.Timer
+import androidx.appactions.interaction.capabilities.serializers.types.ALARM_TYPE_SPEC
+import androidx.appactions.interaction.capabilities.serializers.types.TIMER_TYPE_SPEC
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@@ -36,12 +38,12 @@
.bindMemberType(
memberGetter = AlarmOrTimer::asAlarm,
ctor = { AlarmOrTimer(it) },
- typeSpec = TypeConverters.ALARM_TYPE_SPEC,
+ typeSpec = ALARM_TYPE_SPEC,
)
.bindMemberType(
memberGetter = AlarmOrTimer::asTimer,
ctor = { AlarmOrTimer(it) },
- typeSpec = TypeConverters.TIMER_TYPE_SPEC,
+ typeSpec = TIMER_TYPE_SPEC,
).build()
@RunWith(JUnit4::class)
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java
index 899825f..23efab9 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java
@@ -33,6 +33,7 @@
import androidx.appactions.interaction.proto.FulfillmentResponse.StructuredOutput;
import androidx.appactions.interaction.proto.FulfillmentResponse.StructuredOutput.OutputValue;
import androidx.appactions.interaction.proto.ParamValue;
+import androidx.appactions.interaction.proto.TaskInfo;
import androidx.appactions.interaction.protobuf.Struct;
import androidx.appactions.interaction.protobuf.Value;
@@ -40,10 +41,8 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.HashMap;
+import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
-
@RunWith(JUnit4.class)
@SuppressWarnings("unchecked")
@@ -54,34 +53,16 @@
.setOutput(Output.class)
.bindParameter(
"requiredString",
- properties ->
- {
- Property<?> property = properties.get("requiredString");
- return (property == null) ? null : (Property<StringValue>) property;
- },
Arguments.Builder::setRequiredStringField,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER)
.bindParameter(
"optionalString",
- properties ->
- {
- Property<?> property = properties.get("optionalString");
- return (property == null) ? null : (Property<StringValue>) property;
- },
Arguments.Builder::setOptionalStringField,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER)
.bindRepeatedParameter(
"repeatedString",
- properties ->
- {
- Property<?> property = properties.get("repeatedString");
- return (property == null) ? null : (Property<StringValue>) property;
- },
Arguments.Builder::setRepeatedStringField,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER)
.bindOutput(
"optionalStringOutput",
Output::getOptionalStringField,
@@ -128,62 +109,65 @@
.setOutput(Output.class)
.bindParameter(
"requiredEntity",
- properties -> {
- Property<?> property = properties.get("requiredEntity");
- return (property == null) ? null : (Property<TestEntity>) property;
- },
GenericEntityArguments.Builder::setSingularField,
- TEST_ENTITY_PARAM_VALUE_CONVERTER,
- TEST_ENTITY_CONVERTER)
+ TEST_ENTITY_PARAM_VALUE_CONVERTER)
.bindParameter(
"optionalEntity",
- properties -> {
- Property<?> property = properties.get("optionalEntity");
- return (property == null) ? null : (Property<TestEntity>) property;
- },
GenericEntityArguments.Builder::setOptionalField,
- TEST_ENTITY_PARAM_VALUE_CONVERTER,
- TEST_ENTITY_CONVERTER)
+ TEST_ENTITY_PARAM_VALUE_CONVERTER)
.bindRepeatedParameter(
"repeatedEntities",
- properties -> {
- Property<?> property = properties.get("repeatedEntities");
- return (property == null) ? null : (Property<TestEntity>) property;
- },
GenericEntityArguments.Builder::setRepeatedField,
- TEST_ENTITY_PARAM_VALUE_CONVERTER,
- TEST_ENTITY_CONVERTER)
+ TEST_ENTITY_PARAM_VALUE_CONVERTER)
.build();
@Test
public void getAppAction_genericParameters() {
- Map<String, Property<?>> property = new HashMap<>();
- property.put(
- "requiredEntity",
- new Property.Builder<TestEntity>()
- .setRequired(true)
- .setPossibleValues(
- new TestEntity.Builder().setId("one").setName("one").build())
- .build());
- property.put(
- "optionalEntity",
- new Property.Builder<TestEntity>()
- .setRequired(true)
- .setPossibleValues(
- new TestEntity.Builder().setId("two").setName("two").build())
- .build());
- property.put(
- "repeatedEntities",
- new Property.Builder<TestEntity>()
- .setRequired(true)
- .setPossibleValues(
- new TestEntity.Builder().setId("three").setName("three").build())
- .build());
+ List<BoundProperty<?>> boundProperties = new ArrayList<>();
+ boundProperties.add(
+ new BoundProperty<>(
+ "requiredEntity",
+ new Property.Builder<TestEntity>()
+ .setRequired(true)
+ .setPossibleValues(
+ new TestEntity.Builder()
+ .setId("one")
+ .setName("one")
+ .build())
+ .build(),
+ TEST_ENTITY_CONVERTER));
+ boundProperties.add(
+ new BoundProperty<>(
+ "optionalEntity",
+ new Property.Builder<TestEntity>()
+ .setRequired(true)
+ .setPossibleValues(
+ new TestEntity.Builder()
+ .setId("two")
+ .setName("two")
+ .build())
+ .build(),
+ TEST_ENTITY_CONVERTER));
+ boundProperties.add(
+ new BoundProperty(
+ "repeatedEntities",
+ new Property.Builder<TestEntity>()
+ .setRequired(true)
+ .setPossibleValues(
+ new TestEntity.Builder()
+ .setId("three")
+ .setName("three")
+ .build())
+ .build(),
+ TEST_ENTITY_CONVERTER));
- assertThat(GENERIC_TYPES_ACTION_SPEC.convertPropertyToProto(property))
+ assertThat(
+ GENERIC_TYPES_ACTION_SPEC.createAppAction(
+ "testIdentifier", boundProperties, false))
.isEqualTo(
AppAction.newBuilder()
.setName("actions.intent.TEST")
+ .setIdentifier("testIdentifier")
.addParams(
IntentParameter.newBuilder()
.setName("requiredEntity")
@@ -211,22 +195,28 @@
.newBuilder()
.setIdentifier("three")
.setName("three")))
+ .setTaskInfo(
+ TaskInfo.newBuilder().setSupportsPartialFulfillment(false))
.build());
}
@Test
public void getAppAction_onlyRequiredProperty() {
- Map<String, Property<?>> property = new HashMap<>();
- property.put("requiredString",
- new Property.Builder<StringValue>()
- .setPossibleValues(StringValue.of("Donald"))
- .setValueMatchRequired(true)
- .build());
+ List<BoundProperty<?>> boundProperties = new ArrayList<>();
+ boundProperties.add(
+ new BoundProperty<>(
+ "requiredString",
+ new Property.Builder<StringValue>()
+ .setPossibleValues(StringValue.of("Donald"))
+ .setValueMatchRequired(true)
+ .build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER));
- assertThat(ACTION_SPEC.convertPropertyToProto(property))
+ assertThat(ACTION_SPEC.createAppAction("testIdentifier", boundProperties, true))
.isEqualTo(
AppAction.newBuilder()
.setName("actions.intent.TEST")
+ .setIdentifier("testIdentifier")
.addParams(
IntentParameter.newBuilder()
.setName("requiredString")
@@ -236,26 +226,39 @@
.newBuilder()
.setIdentifier("Donald")
.setName("Donald")))
+ .setTaskInfo(
+ TaskInfo.newBuilder().setSupportsPartialFulfillment(true))
.build());
}
@Test
public void getAppAction_allProperties() {
- Map<String, Property<?>> property = new HashMap<>();
- property.put("requiredString",
- new Property.Builder<StringValue>().build());
- property.put("optionalString",
- new Property.Builder<StringValue>()
- .setPossibleValues(StringValue.of("value1"))
- .setValueMatchRequired(true)
- .setRequired(true)
- .build());
- property.put("repeatedString", Property.prohibited());
+ List<BoundProperty<?>> boundProperties = new ArrayList<>();
+ boundProperties.add(
+ new BoundProperty<>(
+ "requiredString",
+ new Property.Builder<StringValue>().build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER));
+ boundProperties.add(
+ new BoundProperty<>(
+ "optionalString",
+ new Property.Builder<StringValue>()
+ .setPossibleValues(StringValue.of("value1"))
+ .setValueMatchRequired(true)
+ .setRequired(true)
+ .build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER));
+ boundProperties.add(
+ new BoundProperty<>(
+ "repeatedString",
+ Property.prohibited(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER));
- assertThat(ACTION_SPEC.convertPropertyToProto(property))
+ assertThat(ACTION_SPEC.createAppAction("testIdentifier", boundProperties, false))
.isEqualTo(
AppAction.newBuilder()
.setName("actions.intent.TEST")
+ .setIdentifier("testIdentifier")
.addParams(IntentParameter.newBuilder().setName("requiredString"))
.addParams(
IntentParameter.newBuilder()
@@ -272,6 +275,8 @@
IntentParameter.newBuilder()
.setName("repeatedString")
.setIsProhibited(true))
+ .setTaskInfo(
+ TaskInfo.newBuilder().setSupportsPartialFulfillment(false))
.build());
}
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImplTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImplTest.kt
index 744863d..70eff44 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImplTest.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImplTest.kt
@@ -38,6 +38,7 @@
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeSpec
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
+import androidx.appactions.interaction.capabilities.core.impl.spec.BoundProperty
import androidx.appactions.interaction.capabilities.core.properties.Property
import androidx.appactions.interaction.capabilities.core.properties.StringValue
import androidx.appactions.interaction.capabilities.core.testing.spec.Arguments
@@ -74,17 +75,19 @@
import java.util.concurrent.atomic.AtomicReference
import java.util.function.Supplier
import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
-@Suppress("UNCHECKED_CAST")
class TaskCapabilityImplTest {
private val capability: Capability =
createCapability<EmptyTaskUpdater>(
- SINGLE_REQUIRED_FIELD_PROPERTY,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
sessionFactory =
{ _ ->
object : ExecutionSession {
@@ -124,12 +127,15 @@
fun appAction_computedProperty() {
val mutableEntityList = mutableListOf<StringValue>()
val capability = createCapability<EmptyTaskUpdater>(
- mutableMapOf(
- "required" to Property
- .Builder<StringValue>()
- .setPossibleValueSupplier(
- mutableEntityList::toList
- ).build()
+ listOf(
+ BoundProperty(
+ "required",
+ Property.Builder<StringValue>()
+ .setPossibleValueSupplier(
+ mutableEntityList::toList
+ ).build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
),
sessionFactory =
{
@@ -183,7 +189,7 @@
val externalSession = object : ExecutionSession {}
val capability =
createCapability(
- SINGLE_REQUIRED_FIELD_PROPERTY,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
{ externalSession },
{ TaskHandler.Builder<Arguments, Confirmation>().build() },
::EmptyTaskUpdater
@@ -198,7 +204,7 @@
val onCreateInvocationCount = AtomicInteger(0)
val capability: Capability =
createCapability(
- SINGLE_REQUIRED_FIELD_PROPERTY,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
sessionFactory =
{ _ ->
object : ExecutionSession {
@@ -289,7 +295,7 @@
}
}
val capability: Capability = createCapability(
- SINGLE_REQUIRED_FIELD_PROPERTY,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
sessionFactory = { _ -> externalSession },
sessionBridge = SessionBridge {
TaskHandler.Builder<Arguments, Confirmation>().build()
@@ -321,7 +327,7 @@
fun fulfillmentType_unknown_errorReported() {
val capability: Capability =
createCapability(
- SINGLE_REQUIRED_FIELD_PROPERTY,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
sessionFactory =
{ _ ->
object : ExecutionSession {
@@ -361,13 +367,21 @@
@Test
fun slotFilling_isActive_smokeTest() {
- val property = mapOf(
- "stringSlotA" to Property.Builder<StringValue>()
- .setRequired(true)
- .build(),
- "stringSlotB" to Property.Builder<StringValue>()
- .setRequired(true)
- .build()
+ val boundProperties = listOf(
+ BoundProperty(
+ "stringSlotA",
+ Property.Builder<StringValue>()
+ .setRequired(true)
+ .build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ ),
+ BoundProperty(
+ "stringSlotB",
+ Property.Builder<StringValue>()
+ .setRequired(true)
+ .build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
)
val sessionFactory:
(hostProperties: HostProperties?) -> CapabilityTwoStrings.ExecutionSession =
@@ -404,7 +418,7 @@
TaskCapabilityImpl(
"fakeId",
CapabilityTwoStrings.ACTION_SPEC,
- property,
+ boundProperties,
sessionFactory,
sessionBridge,
::EmptyTaskUpdater
@@ -454,13 +468,21 @@
@kotlin.Throws(Exception::class)
fun slotFilling_optionalButRejectedParam_onFinishNotInvoked() {
val onExecuteInvocationCount = AtomicInteger(0)
- val property = mapOf(
- "stringSlotA" to Property.Builder<StringValue>()
- .setRequired(true)
- .build(),
- "stringSlotB" to Property.Builder<StringValue>()
- .setRequired(false)
- .build()
+ val boundProperties = listOf(
+ BoundProperty(
+ "stringSlotA",
+ Property.Builder<StringValue>()
+ .setRequired(true)
+ .build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ ),
+ BoundProperty(
+ "stringSlotB",
+ Property.Builder<StringValue>()
+ .setRequired(false)
+ .build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
)
val sessionFactory:
(hostProperties: HostProperties?) -> CapabilityTwoStrings.ExecutionSession =
@@ -499,7 +521,7 @@
TaskCapabilityImpl(
"fakeId",
CapabilityTwoStrings.ACTION_SPEC,
- property,
+ boundProperties,
sessionFactory,
sessionBridge,
::EmptyTaskUpdater
@@ -543,19 +565,26 @@
@Test
@kotlin.Throws(Exception::class)
fun slotFilling_assistantRemovedParam_clearInSdkState() {
- val property = mapOf(
- "required" to
+ val boundProperties = listOf(
+ BoundProperty(
+ "required",
Property.Builder<StringValue>()
.setRequired(true)
.build(),
- "optionalEnum" to Property.Builder<TestEnum>()
- .setPossibleValues(TestEnum.VALUE_1, TestEnum.VALUE_2)
- .setRequired(true)
- .build()
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ ),
+ BoundProperty(
+ "optionalEnum",
+ Property.Builder<TestEnum>()
+ .setPossibleValues(TestEnum.VALUE_1, TestEnum.VALUE_2)
+ .setRequired(true)
+ .build(),
+ { Entity.newBuilder().setIdentifier(it.toString()).build() }
+ )
)
val capability: Capability =
createCapability(
- property,
+ boundProperties,
sessionFactory = { _ -> ExecutionSession.DEFAULT },
sessionBridge = SessionBridge {
TaskHandler.Builder<Arguments, Confirmation>().build()
@@ -605,11 +634,10 @@
@Test
@kotlin.Throws(Exception::class)
- @Suppress("DEPRECATION")
fun disambig_singleParam_disambigEntitiesInContext() {
val capability: Capability =
createCapability(
- SINGLE_REQUIRED_FIELD_PROPERTY,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
sessionFactory = {
object : ExecutionSession {
override suspend fun onExecute(arguments: Arguments) =
@@ -738,17 +766,22 @@
*/
@Test
@kotlin.Throws(Exception::class)
- @Suppress("DEPRECATION")
fun identifierOnly_refillsStruct() = runBlocking<Unit> {
- val property = mapOf(
- "listItem" to Property.Builder<
- ListItem
- >()
- .setRequired(true)
- .build(),
- "anyString" to Property.Builder<StringValue>()
- .setRequired(true)
- .build()
+ val boundProperties = listOf(
+ BoundProperty(
+ "listItem",
+ Property.Builder<ListItem>()
+ .setRequired(true)
+ .build(),
+ EntityConverter.of(TypeConverters.LIST_ITEM_TYPE_SPEC)
+ ),
+ BoundProperty(
+ "string",
+ Property.Builder<StringValue>()
+ .setRequired(true)
+ .build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
)
val item1: ListItem = ListItem.Builder().setName("red apple").setIdentifier("item1").build()
val item2: ListItem =
@@ -765,7 +798,7 @@
arguments: CapabilityStructFill.Arguments
): ExecutionResult<CapabilityStructFill.Output> {
arguments.listItem?.let { onExecuteListItemDeferred.complete(it) }
- arguments.anyString?.let { onExecuteStringDeferred.complete(it) }
+ arguments.string?.let { onExecuteStringDeferred.complete(it) }
return ExecutionResult.Builder<CapabilityStructFill.Output>().build()
}
@@ -813,7 +846,7 @@
TaskCapabilityImpl(
"selectListItem",
CapabilityStructFill.ACTION_SPEC,
- property,
+ boundProperties,
sessionFactory,
sessionBridge,
::EmptyTaskUpdater
@@ -996,12 +1029,9 @@
ExecutionResult.Builder<Output>().build()
}
}
- val property = mapOf(
- "required" to Property.Builder<StringValue>().setRequired(true).build()
- )
val capability: Capability =
createCapability(
- property,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
sessionFactory = sessionFactory,
sessionBridge = SessionBridge {
TaskHandler.Builder<Arguments, Confirmation>().build()
@@ -1056,12 +1086,9 @@
.build()
}
}
- val property = mapOf(
- "required" to Property.Builder<StringValue>().setRequired(true).build()
- )
val capability: Capability =
createCapability(
- property,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
sessionFactory = sessionFactory,
sessionBridge = SessionBridge {
TaskHandler.Builder<Arguments, Confirmation>()
@@ -1106,12 +1133,9 @@
ExecutionResult.Builder<Output>().build()
}
}
- val property = mapOf(
- "required" to Property.Builder<StringValue>().setRequired(true).build()
- )
val capability: Capability =
createCapability(
- property,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
sessionFactory = sessionFactory,
sessionBridge = SessionBridge {
TaskHandler.Builder<Arguments, Confirmation>().build()
@@ -1145,14 +1169,14 @@
)
assertThat(session.isActive).isEqualTo(false)
assertThat(callback2.receiveResponse().errorStatus)
- .isEqualTo(ErrorStatusInternal.SESSION_ALREADY_DESTROYED)
+ .isEqualTo(ErrorStatusInternal.SESSION_NOT_FOUND)
}
@Test
@kotlin.Throws(Exception::class)
fun syncStatus_unknown_errorReported() {
val capability: Capability =
createCapability(
- SINGLE_REQUIRED_FIELD_PROPERTY,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
sessionFactory =
{ _ ->
object : ExecutionSession {
@@ -1182,15 +1206,13 @@
// TURN 1 (UNKNOWN).
val errorCallback = FakeCallbackInternal()
- session.execute(buildRequestArgs(SYNC, SyncStatus.UNKNOWN_SYNC_STATUS),
- errorCallback)
+ session.execute(buildRequestArgs(SYNC, SyncStatus.UNKNOWN_SYNC_STATUS), errorCallback)
assertThat(errorCallback.receiveResponse().errorStatus)
.isEqualTo(ErrorStatusInternal.INVALID_REQUEST)
// TURN 2 (UNRECOGNIZED)
val errorCallback2 = FakeCallbackInternal()
- session.execute(buildRequestArgs(SYNC, SyncStatus.UNRECOGNIZED),
- errorCallback2)
+ session.execute(buildRequestArgs(SYNC, SyncStatus.UNRECOGNIZED), errorCallback2)
assertThat(errorCallback2.receiveResponse().errorStatus)
.isEqualTo(ErrorStatusInternal.INVALID_REQUEST)
}
@@ -1198,9 +1220,6 @@
@Test
@kotlin.Throws(Exception::class)
fun syncStatus_slotsIncomplete_taskNotExecuted() {
- val property = mapOf(
- "required" to Property.Builder<StringValue>().setRequired(true).build()
- )
val onExecuteInvocationCount = AtomicInteger(0)
val sessionFactory: (hostProperties: HostProperties?) -> ExecutionSession =
{ _ ->
@@ -1213,7 +1232,7 @@
}
val capability: Capability =
createCapability(
- property,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
sessionFactory = sessionFactory,
sessionBridge = SessionBridge { TaskHandler.Builder<Arguments, Confirmation>()
.build() },
@@ -1288,9 +1307,6 @@
.build()
}
}
- val property = mapOf(
- "required" to Property.Builder<StringValue>().setRequired(true).build()
- )
val onExecuteInvocationCount = AtomicInteger(0)
val sessionFactory: (hostProperties: HostProperties?) -> ExecutionSession =
{ _ ->
@@ -1309,7 +1325,7 @@
}
val capability: Capability =
createCapability(
- property,
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
sessionFactory = sessionFactory,
sessionBridge = {
TaskHandler.Builder<Arguments, Confirmation>()
@@ -1402,7 +1418,7 @@
}
@Test
- fun structConversionException_shouldReportStructConversionFailure() {
+ fun structConversionException_shouldReportInternalFailure() {
val sessionFactory: (hostProperties: HostProperties?) -> ExecutionSession =
{ _ ->
object : ExecutionSession {
@@ -1446,7 +1462,7 @@
assertThat(
callback.receiveResponse().errorStatus
- ).isEqualTo(ErrorStatusInternal.STRUCT_CONVERSION_FAILURE)
+ ).isEqualTo(ErrorStatusInternal.INTERNAL)
}
@Test
@@ -1494,6 +1510,62 @@
).isEqualTo(ErrorStatusInternal.EXTERNAL_EXCEPTION)
}
+ @kotlinx.coroutines.ExperimentalCoroutinesApi
+ @Test
+ fun slotListenerTimeout_returnsCorrectErrorStatus() = runTest {
+ val externalSession = object : ExecutionSession {
+ override val requiredStringListener = object : AppEntityListener<String> {
+ override suspend fun lookupAndRender(
+ searchAction: SearchAction<String>
+ ): EntitySearchResult<String> {
+ return EntitySearchResult.Builder<String>().build()
+ }
+
+ override suspend fun onReceived(
+ value: String
+ ): ValidationResult {
+ delay(4000) // will throw TimeoutCancellationException due to 3s timeout
+ return ValidationResult.newAccepted()
+ }
+ }
+ }
+ val session = TaskCapabilitySession(
+ "sessionId",
+ ACTION_SPEC,
+ ACTION_SPEC.createAppAction(
+ "fakeCapabilityId",
+ SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES,
+ supportsPartialFulfillment = true
+ ),
+ TaskHandler.Builder<Arguments, Confirmation>()
+ .registerAppEntityTaskParam(
+ "required",
+ externalSession.requiredStringListener,
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER,
+ EntityConverter.of(TypeSpec.STRING_TYPE_SPEC),
+ getTrivialSearchActionConverter()
+ ).build(),
+ externalSession,
+ scope = this,
+ )
+ val callback = FakeCallbackInternal(timeoutMs = 5000L)
+
+ session.execute(
+ buildRequestArgs(
+ SYNC, /* args...= */
+ "required",
+ ParamValue.newBuilder().setIdentifier("foo").setStringValue("foo").build()
+ ),
+ callback
+ )
+
+ advanceTimeBy(5000L)
+ val response = callback.receiveResponse()
+ assertThat(
+ response.errorStatus
+ ).isEqualTo(ErrorStatusInternal.EXTERNAL_EXCEPTION)
+ }
+
/**
* an implementation of Capability.Builder using Argument. Output, etc. defined under
* testing/spec
@@ -1508,9 +1580,19 @@
>(ACTION_SPEC) {
init {
- setProperty(SINGLE_REQUIRED_FIELD_PROPERTY)
+ setProperty(
+ "required",
+ Property.Builder<StringValue>()
+ .setRequired(true)
+ .build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
}
+ public override fun setExecutionSessionFactory(
+ sessionFactory: (hostProperties: HostProperties?) -> ExecutionSession
+ ) = super.setExecutionSessionFactory(sessionFactory)
+
override val sessionBridge: SessionBridge<
ExecutionSession,
Arguments,
@@ -1594,39 +1676,23 @@
.setOutput(Output::class.java)
.bindParameter(
"required",
- { properties ->
- properties["required"] as Property<StringValue>
- },
Arguments.Builder::setRequiredStringField,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.bindParameter(
"optional",
- { properties ->
- properties["optional"] as? Property<StringValue>
- },
Arguments.Builder::setOptionalStringField,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.bindParameter(
"optionalEnum",
- { properties ->
- properties["optionalEnum"] as? Property<TestEnum>
- },
Arguments.Builder::setEnumField,
- ENUM_CONVERTER,
- { Entity.newBuilder().setIdentifier(it.toString()).build() }
+ ENUM_CONVERTER
)
.bindRepeatedParameter(
"repeated",
- { properties ->
- properties["repeated"] as? Property<StringValue>
- },
Arguments.Builder::setRepeatedStringField,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.bindOutput(
"optionalStringOutput",
@@ -1640,10 +1706,13 @@
)
.build()
- private val SINGLE_REQUIRED_FIELD_PROPERTY = mapOf(
- "required" to Property.Builder<StringValue>()
- .setRequired(true)
- .build()
+ private val SINGLE_REQUIRED_FIELD_BOUND_PROPERTIES = listOf(
+ BoundProperty(
+ "required",
+ Property.Builder<StringValue>()
+ .setRequired(true)
+ .build(),
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
)
private fun getCurrentValues(
@@ -1664,7 +1733,7 @@
* etc., defined under ../../testing/spec
*/
private fun <SessionUpdaterT : AbstractTaskUpdater> createCapability(
- property: Map<String, Property<*>>,
+ boundProperties: List<BoundProperty<*>>,
sessionFactory: (hostProperties: HostProperties?) -> ExecutionSession,
sessionBridge: SessionBridge<ExecutionSession, Arguments, Confirmation>,
sessionUpdaterSupplier: Supplier<SessionUpdaterT>
@@ -1678,7 +1747,7 @@
return TaskCapabilityImpl(
"id",
ACTION_SPEC,
- property,
+ boundProperties,
sessionFactory,
sessionBridge,
sessionUpdaterSupplier
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityStructFill.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityStructFill.kt
index 40d0f99..878980f 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityStructFill.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityStructFill.kt
@@ -20,12 +20,9 @@
import androidx.appactions.interaction.capabilities.core.AppEntityListener
import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
-import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
import androidx.appactions.interaction.capabilities.core.impl.converters.ParamValueConverter
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.Property
-import androidx.appactions.interaction.capabilities.core.properties.StringValue
private const val CAPABILITY_NAME = "actions.intent.TEST"
@@ -34,11 +31,11 @@
class Arguments internal constructor(
val listItem: ListItem?,
- val anyString: String?
+ val string: String?
) {
override fun toString(): String {
return "Arguments(listItem=$listItem, " +
- "anyString=$anyString)"
+ "string=$string)"
}
override fun equals(other: Any?): Boolean {
@@ -48,27 +45,27 @@
other as Arguments
if (listItem != other.listItem) return false
- if (anyString != other.anyString) return false
+ if (string != other.string) return false
return true
}
override fun hashCode(): Int {
var result = listItem.hashCode()
- result += 31 * anyString.hashCode()
+ result += 31 * string.hashCode()
return result
}
class Builder : BuilderOf<Arguments> {
private var listItem: ListItem? = null
- private var anyString: String? = null
+ private var string: String? = null
fun setListItem(listItem: ListItem): Builder =
apply { this.listItem = listItem }
fun setAnyString(stringSlotB: String): Builder =
- apply { this.anyString = stringSlotB }
+ apply { this.string = stringSlotB }
- override fun build(): Arguments = Arguments(listItem, anyString)
+ override fun build(): Arguments = Arguments(listItem, string)
}
}
@@ -81,27 +78,18 @@
}
companion object {
- @Suppress("UNCHECKED_CAST")
val ACTION_SPEC = ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindParameter(
"listItem",
- { properties ->
- properties["listItem"] as? Property<ListItem>
- },
Arguments.Builder::setListItem,
- ParamValueConverter.of(TypeConverters.LIST_ITEM_TYPE_SPEC),
- EntityConverter.of(TypeConverters.LIST_ITEM_TYPE_SPEC)::convert
+ ParamValueConverter.of(TypeConverters.LIST_ITEM_TYPE_SPEC)
)
.bindParameter(
"string",
- { properties ->
- properties["anyString"] as? Property<StringValue>
- },
Arguments.Builder::setAnyString,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.build()
}
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoStrings.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoStrings.kt
index 612d3ca..3b1766f 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoStrings.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoStrings.kt
@@ -21,8 +21,6 @@
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.Property
-import androidx.appactions.interaction.capabilities.core.properties.StringValue
private const val CAPABILITY_NAME = "actions.intent.TEST"
@@ -76,27 +74,18 @@
interface ExecutionSession : BaseExecutionSession<Arguments, Output>
companion object {
- @Suppress("UNCHECKED_CAST")
val ACTION_SPEC = ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindParameter(
"stringSlotA",
- { properties ->
- properties["stringSlotA"] as? Property<StringValue>
- },
Arguments.Builder::setStringSlotA,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.bindParameter(
"stringSlotB",
- { properties ->
- properties["stringSlotB"] as? Property<StringValue>
- },
Arguments.Builder::setStringSlotB,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.build()
}
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/serializers/types/DayOfWeekSerializerTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/serializers/types/DayOfWeekSerializerTest.kt
new file mode 100644
index 0000000..195b70e
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/serializers/types/DayOfWeekSerializerTest.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.types
+
+import androidx.appactions.builtintypes.types.DayOfWeek
+import androidx.appactions.interaction.protobuf.Value
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class DayOfWeekSerializerTest {
+ @Test
+ fun DayOfWeek_conversion_success() {
+ val MONDAY_VALUE = Value.newBuilder().setStringValue(DayOfWeek.MONDAY.canonicalUrl).build()
+
+ assertThat(DAY_OF_WEEK_TYPE_SPEC.toValue(DayOfWeek.MONDAY)).isEqualTo(MONDAY_VALUE)
+ assertThat(DAY_OF_WEEK_TYPE_SPEC.fromValue(MONDAY_VALUE)).isSameInstanceAs(DayOfWeek.MONDAY)
+ }
+}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetExerciseObservation.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetExerciseObservation.kt
index 4fd5dc7..9334c2e 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetExerciseObservation.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetExerciseObservation.kt
@@ -30,7 +30,7 @@
/** A capability corresponding to actions.intent.GET_EXERCISE_OBSERVATION */
@CapabilityFactory(name = CAPABILITY_NAME)
class GetExerciseObservation private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
+ internal enum class SlotMetadata(val path: String) {
START_TIME("exerciseObservation.startTime"),
END_TIME("exerciseObservation.endTime")
}
@@ -39,18 +39,17 @@
Capability.Builder<
CapabilityBuilder, Arguments, Output, Confirmation, ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
+ fun setStartTimeProperty(startTime: Property<LocalTime>): CapabilityBuilder = setProperty(
+ SlotMetadata.START_TIME.path,
+ startTime,
+ TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
+ )
- fun setStartTime(startTime: Property<LocalTime>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.START_TIME.key] = startTime }
-
- fun setEndTime(endTime: Property<LocalTime>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.END_TIME.key] = endTime }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setEndTimeProperty(endTime: Property<LocalTime>): CapabilityBuilder = setProperty(
+ SlotMetadata.END_TIME.path,
+ endTime,
+ TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
+ )
}
class Arguments internal constructor(
@@ -101,7 +100,6 @@
companion object {
// TODO(b/273602015): Update to use Name property from builtintype library.
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(
@@ -110,22 +108,14 @@
)
.setOutput(Output::class.java)
.bindParameter(
- "exerciseObservation.startTime",
- { properties ->
- properties[PropertyMapStrings.START_TIME.key] as? Property<LocalTime>
- },
+ SlotMetadata.START_TIME.path,
Arguments.Builder::setStartTime,
- TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER,
- TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
+ TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER
)
.bindParameter(
- "exerciseObservation.endTime",
- { properties ->
- properties[PropertyMapStrings.END_TIME.key] as? Property<LocalTime>
- },
+ SlotMetadata.END_TIME.path,
Arguments.Builder::setEndTime,
- TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER,
- TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
+ TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER
)
.build()
}
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetHealthObservation.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetHealthObservation.kt
index 7d843ac..9f7ddd53 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetHealthObservation.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetHealthObservation.kt
@@ -31,7 +31,7 @@
@CapabilityFactory(name = CAPABILITY_NAME)
class GetHealthObservation private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
+ internal enum class SlotMetadata(val path: String) {
START_TIME("healthObservation.startTime"),
END_TIME("healthObservation.endTime")
}
@@ -44,18 +44,17 @@
Confirmation,
ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
+ fun setStartTimeProperty(startTime: Property<LocalTime>): CapabilityBuilder = setProperty(
+ SlotMetadata.START_TIME.path,
+ startTime,
+ TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
+ )
- fun setStartTime(startTime: Property<LocalTime>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.START_TIME.key] = startTime }
-
- fun setEndTime(endTime: Property<LocalTime>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.END_TIME.key] = endTime }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setEndTimeProperty(endTime: Property<LocalTime>): CapabilityBuilder = setProperty(
+ SlotMetadata.END_TIME.path,
+ endTime,
+ TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
+ )
}
class Arguments internal constructor(
@@ -106,7 +105,6 @@
companion object {
// TODO(b/273602015): Update to use Name property from builtintype library.
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(
@@ -115,22 +113,14 @@
)
.setOutput(Output::class.java)
.bindParameter(
- "healthObservation.startTime",
- { properties ->
- properties[PropertyMapStrings.START_TIME.key] as? Property<LocalTime>
- },
+ SlotMetadata.START_TIME.path,
Arguments.Builder::setStartTime,
- TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER,
- TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
+ TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER
)
.bindParameter(
- "healthObservation.endTime",
- { properties ->
- properties[PropertyMapStrings.END_TIME.key] as? Property<LocalTime>
- },
+ SlotMetadata.END_TIME.path,
Arguments.Builder::setEndTime,
- TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER,
- TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
+ TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER
)
.build()
}
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/PauseExercise.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/PauseExercise.kt
index 8a94643d..2d3143a 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/PauseExercise.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/PauseExercise.kt
@@ -30,7 +30,7 @@
/** A capability corresponding to actions.intent.PAUSE_EXERCISE */
@CapabilityFactory(name = CAPABILITY_NAME)
class PauseExercise private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
+ internal enum class SlotMetadata(val path: String) {
NAME("exercise.name")
}
@@ -42,14 +42,11 @@
Confirmation,
ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
- fun setName(name: Property<StringValue>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.NAME.key] = name }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setNameProperty(name: Property<StringValue>): CapabilityBuilder = setProperty(
+ SlotMetadata.NAME.path,
+ name,
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
}
class Arguments internal constructor(
@@ -92,19 +89,14 @@
companion object {
// TODO(b/273602015): Update to use Name property from builtintype library.
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindParameter(
- "exercise.name",
- { properties ->
- properties[PropertyMapStrings.NAME.key] as? Property<StringValue>
- },
+ SlotMetadata.NAME.path,
Arguments.Builder::setName,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.build()
}
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/ResumeExercise.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/ResumeExercise.kt
index 963f7ad..974fe21 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/ResumeExercise.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/ResumeExercise.kt
@@ -30,7 +30,7 @@
/** A capability corresponding to actions.intent.RESUME_EXERCISE */
@CapabilityFactory(name = CAPABILITY_NAME)
class ResumeExercise private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
+ internal enum class SlotMetadata(val path: String) {
NAME("exercise.name")
}
@@ -42,14 +42,11 @@
Confirmation,
ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
- fun setName(name: Property<StringValue>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.NAME.key] = name }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setNameProperty(name: Property<StringValue>): CapabilityBuilder = setProperty(
+ SlotMetadata.NAME.path,
+ name,
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
}
class Arguments internal constructor(
@@ -92,19 +89,14 @@
companion object {
// TODO(b/273602015): Update to use Name property from builtintype library.
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindParameter(
- "exercise.name",
- { properties ->
- properties[PropertyMapStrings.NAME.key] as? Property<StringValue>
- },
+ SlotMetadata.NAME.path,
Arguments.Builder::setName,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.build()
}
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StartExercise.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StartExercise.kt
index 3de87ec..92f8bbd 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StartExercise.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StartExercise.kt
@@ -31,7 +31,7 @@
/** A capability corresponding to actions.intent.START_EXERCISE */
@CapabilityFactory(name = CAPABILITY_NAME)
class StartExercise private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
+ internal enum class SlotMetadata(val path: String) {
NAME("exercise.name"),
DURATION("exercise.duration")
}
@@ -44,18 +44,17 @@
Confirmation,
ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
+ fun setNameProperty(name: Property<StringValue>): CapabilityBuilder = setProperty(
+ SlotMetadata.NAME.path,
+ name,
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
- fun setName(name: Property<StringValue>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.NAME.key] = name }
-
- fun setDuration(duration: Property<Duration>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.DURATION.key] = duration }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setDurationProperty(duration: Property<Duration>): CapabilityBuilder = setProperty(
+ SlotMetadata.DURATION.path,
+ duration,
+ TypeConverters.DURATION_ENTITY_CONVERTER
+ )
}
class Arguments internal constructor(
@@ -106,28 +105,19 @@
companion object {
// TODO(b/273602015): Update to use Name property from builtintype library.
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindParameter(
- "exercise.duration",
- { properties ->
- properties[PropertyMapStrings.DURATION.key] as? Property<Duration>
- },
+ SlotMetadata.DURATION.path,
Arguments.Builder::setDuration,
- TypeConverters.DURATION_PARAM_VALUE_CONVERTER,
- TypeConverters.DURATION_ENTITY_CONVERTER
+ TypeConverters.DURATION_PARAM_VALUE_CONVERTER
)
.bindParameter(
- "exercise.name",
- { properties ->
- properties[PropertyMapStrings.NAME.key] as? Property<StringValue>
- },
+ SlotMetadata.NAME.path,
Arguments.Builder::setName,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.build()
}
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StopExercise.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StopExercise.kt
index e257fac..0421d7d 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StopExercise.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StopExercise.kt
@@ -30,7 +30,7 @@
/** A capability corresponding to actions.intent.STOP_EXERCISE */
@CapabilityFactory(name = CAPABILITY_NAME)
class StopExercise private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
+ internal enum class SlotMetadata(val path: String) {
NAME("exercise.name")
}
@@ -42,15 +42,11 @@
Confirmation,
ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
-
- fun setName(name: Property<StringValue>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.NAME.key] = name }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setNameProperty(name: Property<StringValue>): CapabilityBuilder = setProperty(
+ SlotMetadata.NAME.path,
+ name,
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
}
class Arguments internal constructor(
@@ -93,19 +89,14 @@
companion object {
// TODO(b/273602015): Update to use Name property from builtintype library.
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindParameter(
- "exercise.name",
- { properties ->
- properties[PropertyMapStrings.NAME.key] as? Property<StringValue>
- },
+ SlotMetadata.NAME.path,
Arguments.Builder::setName,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.build()
}
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/PauseTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/PauseTimer.kt
index e2f8e01..a87a028 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/PauseTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/PauseTimer.kt
@@ -18,13 +18,16 @@
import androidx.appactions.builtintypes.experimental.types.GenericErrorStatus
import androidx.appactions.builtintypes.experimental.types.SuccessStatus
+import androidx.appactions.builtintypes.types.Timer
import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
import androidx.appactions.interaction.capabilities.core.Capability
import androidx.appactions.interaction.capabilities.core.CapabilityFactory
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
+import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
import androidx.appactions.interaction.capabilities.core.properties.Property
+import androidx.appactions.interaction.capabilities.serializers.types.TIMER_TYPE_SPEC
import androidx.appactions.interaction.proto.ParamValue
import androidx.appactions.interaction.protobuf.Struct
import androidx.appactions.interaction.protobuf.Value
@@ -34,8 +37,8 @@
/** A capability corresponding to actions.intent.PAUSE_TIMER */
@CapabilityFactory(name = CAPABILITY_NAME)
class PauseTimer private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
- TIMER_LIST("timer.timerList")
+ internal enum class SlotMetadata(val path: String) {
+ TIMER("timer")
}
class CapabilityBuilder :
@@ -46,15 +49,11 @@
Confirmation,
ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
-
- fun setTimerListProperty(timerList: Property<TimerValue>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.TIMER_LIST.key] = timerList }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setTimerProperty(timer: Property<Timer>): CapabilityBuilder = setProperty(
+ SlotMetadata.TIMER.path,
+ timer,
+ EntityConverter.of(TIMER_TYPE_SPEC)
+ )
}
class Arguments
@@ -156,19 +155,14 @@
sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
companion object {
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindRepeatedParameter(
- "timer",
- { properties ->
- properties[PropertyMapStrings.TIMER_LIST.key] as? Property<TimerValue>
- },
+ SlotMetadata.TIMER.path,
Arguments.Builder::setTimerList,
- TimerValue.PARAM_VALUE_CONVERTER,
- TimerValue.ENTITY_CONVERTER
+ TimerValue.PARAM_VALUE_CONVERTER
)
.bindOutput(
"executionStatus",
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt
index 5a3f115..c808cdb 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt
@@ -18,13 +18,16 @@
import androidx.appactions.builtintypes.experimental.types.GenericErrorStatus
import androidx.appactions.builtintypes.experimental.types.SuccessStatus
+import androidx.appactions.builtintypes.types.Timer
import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
import androidx.appactions.interaction.capabilities.core.Capability
import androidx.appactions.interaction.capabilities.core.CapabilityFactory
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
+import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
import androidx.appactions.interaction.capabilities.core.properties.Property
+import androidx.appactions.interaction.capabilities.serializers.types.TIMER_TYPE_SPEC
import androidx.appactions.interaction.proto.ParamValue
import androidx.appactions.interaction.protobuf.Struct
import androidx.appactions.interaction.protobuf.Value
@@ -34,8 +37,8 @@
/** A capability corresponding to actions.intent.RESET_TIMER */
@CapabilityFactory(name = CAPABILITY_NAME)
class ResetTimer private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
- TIMER_LIST("timer.timerList")
+ internal enum class SlotMetadata(val path: String) {
+ TIMER("timer")
}
class CapabilityBuilder :
@@ -46,15 +49,11 @@
Confirmation,
ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
-
- fun setTimerListProperty(timerList: Property<TimerValue>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.TIMER_LIST.key] = timerList }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setTimerProperty(timer: Property<Timer>): CapabilityBuilder = setProperty(
+ SlotMetadata.TIMER.path,
+ timer,
+ EntityConverter.of(TIMER_TYPE_SPEC)
+ )
}
class Arguments internal constructor(val timerList: List<TimerValue>?) {
@@ -153,19 +152,14 @@
sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
companion object {
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindRepeatedParameter(
- "timer",
- { properties ->
- properties[PropertyMapStrings.TIMER_LIST.key] as? Property<TimerValue>
- },
+ SlotMetadata.TIMER.path,
Arguments.Builder::setTimerList,
- TimerValue.PARAM_VALUE_CONVERTER,
- TimerValue.ENTITY_CONVERTER
+ TimerValue.PARAM_VALUE_CONVERTER
)
.bindOutput(
"executionStatus",
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt
index 505bdec..46b8712 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt
@@ -18,13 +18,16 @@
import androidx.appactions.builtintypes.experimental.types.GenericErrorStatus
import androidx.appactions.builtintypes.experimental.types.SuccessStatus
+import androidx.appactions.builtintypes.types.Timer
import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
import androidx.appactions.interaction.capabilities.core.Capability
import androidx.appactions.interaction.capabilities.core.CapabilityFactory
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
+import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
import androidx.appactions.interaction.capabilities.core.properties.Property
+import androidx.appactions.interaction.capabilities.serializers.types.TIMER_TYPE_SPEC
import androidx.appactions.interaction.proto.ParamValue
import androidx.appactions.interaction.protobuf.Struct
import androidx.appactions.interaction.protobuf.Value
@@ -34,8 +37,8 @@
/** A capability corresponding to actions.intent.RESUME_TIMER */
@CapabilityFactory(name = CAPABILITY_NAME)
class ResumeTimer private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
- TIMER_LIST("timer.timerList")
+ internal enum class SlotMetadata(val path: String) {
+ TIMER("timer")
}
class CapabilityBuilder :
@@ -46,15 +49,11 @@
Confirmation,
ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
-
- fun setTimerListProperty(timerList: Property<TimerValue>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.TIMER_LIST.key] = timerList }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setTimerProperty(timer: Property<Timer>): CapabilityBuilder = setProperty(
+ SlotMetadata.TIMER.path,
+ timer,
+ EntityConverter.of(TIMER_TYPE_SPEC)
+ )
}
class Arguments internal constructor(val timerList: List<TimerValue>?) {
@@ -153,19 +152,14 @@
sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
companion object {
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindRepeatedParameter(
- "timer",
- { properties ->
- properties[PropertyMapStrings.TIMER_LIST.key] as? Property<TimerValue>
- },
+ SlotMetadata.TIMER.path,
Arguments.Builder::setTimerList,
- TimerValue.PARAM_VALUE_CONVERTER,
- TimerValue.ENTITY_CONVERTER
+ TimerValue.PARAM_VALUE_CONVERTER
)
.bindOutput(
"executionStatus",
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StartTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StartTimer.kt
index 6d2bfa7..ed29c9c 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StartTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StartTimer.kt
@@ -21,13 +21,9 @@
import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
import androidx.appactions.interaction.capabilities.core.Capability
import androidx.appactions.interaction.capabilities.core.CapabilityFactory
-import androidx.appactions.interaction.capabilities.core.HostProperties
-import androidx.appactions.interaction.capabilities.core.ValueListener
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.impl.task.SessionBridge
-import androidx.appactions.interaction.capabilities.core.impl.task.TaskHandler
import androidx.appactions.interaction.capabilities.core.properties.Property
import androidx.appactions.interaction.capabilities.core.properties.StringValue
import androidx.appactions.interaction.proto.ParamValue
@@ -40,8 +36,7 @@
/** A capability corresponding to actions.intent.START_TIMER */
@CapabilityFactory(name = CAPABILITY_NAME)
class StartTimer private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
- TIMER_LIST("timer.timerList"),
+ internal enum class SlotMetadata(val path: String) {
IDENTIFIER("timer.identifier"),
NAME("timer.name"),
DURATION("timer.duration")
@@ -55,45 +50,25 @@
Confirmation,
ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
+ fun setIdentifierProperty(
+ identifier: Property<StringValue>
+ ): CapabilityBuilder = setProperty(
+ SlotMetadata.IDENTIFIER.path,
+ identifier,
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
- override val sessionBridge: SessionBridge<
- ExecutionSession,
- Arguments,
- Confirmation
- > = SESSION_BRIDGE
+ fun setNameProperty(name: Property<StringValue>): CapabilityBuilder = setProperty(
+ SlotMetadata.NAME.path,
+ name,
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
- override fun setExecutionSessionFactory(
- sessionFactory: (hostProperties: HostProperties?) -> ExecutionSession
- ): CapabilityBuilder = super.setExecutionSessionFactory(sessionFactory)
-
- fun setTimerListProperty(timerList: Property<TimerValue>): CapabilityBuilder = apply {
- properties[PropertyMapStrings.TIMER_LIST.key] = timerList
- }
-
- fun setIdentifierProperty(identifier: Property<StringValue>): CapabilityBuilder = apply {
- properties[PropertyMapStrings.IDENTIFIER.key] = identifier
- }
-
- fun setNameProperty(name: Property<StringValue>): CapabilityBuilder = apply {
- properties[PropertyMapStrings.NAME.key] = name
- }
-
- fun setDurationProperty(duration: Property<Duration>): CapabilityBuilder = apply {
- properties[PropertyMapStrings.DURATION.key] = duration
- }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
- }
-
- interface ExecutionSession : BaseExecutionSession<Arguments, Output> {
- val nameListener: ValueListener<String>?
- get() = null
- val durationListener: ValueListener<Duration>?
- get() = null
+ fun setDurationProperty(duration: Property<Duration>): CapabilityBuilder = setProperty(
+ SlotMetadata.DURATION.path,
+ duration,
+ TypeConverters.DURATION_ENTITY_CONVERTER
+ )
}
class Arguments internal constructor(
@@ -139,7 +114,6 @@
override fun build(): Arguments = Arguments(identifier, name, duration)
}
}
-
class Output internal constructor(val executionStatus: ExecutionStatus?) {
override fun toString(): String {
return "Output(executionStatus=$executionStatus)"
@@ -200,40 +174,28 @@
}
}
+ sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
class Confirmation internal constructor()
companion object {
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindParameter(
- "timer.identifier",
- { properties ->
- properties[PropertyMapStrings.IDENTIFIER.key] as? Property<StringValue>
- },
+ SlotMetadata.IDENTIFIER.path,
Arguments.Builder::setIdentifier,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.bindParameter(
- "timer.name",
- { properties ->
- properties[PropertyMapStrings.NAME.key] as? Property<StringValue>
- },
+ SlotMetadata.NAME.path,
Arguments.Builder::setName,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.bindParameter(
- "timer.duration",
- { properties ->
- properties[PropertyMapStrings.DURATION.key] as? Property<Duration>
- },
+ SlotMetadata.DURATION.path,
Arguments.Builder::setDuration,
- TypeConverters.DURATION_PARAM_VALUE_CONVERTER,
- TypeConverters.DURATION_ENTITY_CONVERTER
+ TypeConverters.DURATION_PARAM_VALUE_CONVERTER
)
.bindOutput(
"executionStatus",
@@ -241,25 +203,5 @@
ExecutionStatus::toParamValue
)
.build()
-
- private val SESSION_BRIDGE =
- SessionBridge<ExecutionSession, Arguments, Confirmation> { session ->
- val taskHandlerBuilder = TaskHandler.Builder<Arguments, Confirmation>()
- session.nameListener?.let {
- taskHandlerBuilder.registerValueTaskParam(
- "timer.name",
- it,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER
- )
- }
- session.durationListener?.let {
- taskHandlerBuilder.registerValueTaskParam(
- "timer.duration",
- it,
- TypeConverters.DURATION_PARAM_VALUE_CONVERTER
- )
- }
- taskHandlerBuilder.build()
- }
}
}
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt
index 5897c720..1ab0f53 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt
@@ -18,13 +18,16 @@
import androidx.appactions.builtintypes.experimental.types.GenericErrorStatus
import androidx.appactions.builtintypes.experimental.types.SuccessStatus
+import androidx.appactions.builtintypes.types.Timer
import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
import androidx.appactions.interaction.capabilities.core.Capability
import androidx.appactions.interaction.capabilities.core.CapabilityFactory
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
+import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
import androidx.appactions.interaction.capabilities.core.properties.Property
+import androidx.appactions.interaction.capabilities.serializers.types.TIMER_TYPE_SPEC
import androidx.appactions.interaction.proto.ParamValue
import androidx.appactions.interaction.protobuf.Struct
import androidx.appactions.interaction.protobuf.Value
@@ -34,8 +37,8 @@
/** A capability corresponding to actions.intent.STOP_TIMER */
@CapabilityFactory(name = CAPABILITY_NAME)
class StopTimer private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
- TIMER_LIST("timer.timerList")
+ internal enum class SlotMetadata(val path: String) {
+ TIMER("timer")
}
class CapabilityBuilder :
@@ -46,15 +49,11 @@
Confirmation,
ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
-
- fun setTimerListProperty(timerList: Property<TimerValue>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.TIMER_LIST.key] = timerList }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setTimerProperty(timer: Property<Timer>): CapabilityBuilder = setProperty(
+ SlotMetadata.TIMER.path,
+ timer,
+ EntityConverter.of(TIMER_TYPE_SPEC)
+ )
}
class Arguments internal constructor(val timerList: List<TimerValue>?) {
@@ -153,19 +152,14 @@
sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
companion object {
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindRepeatedParameter(
- "timer",
- { properties ->
- properties[PropertyMapStrings.TIMER_LIST.key] as? Property<TimerValue>
- },
+ SlotMetadata.TIMER.path,
Arguments.Builder::setTimerList,
- TimerValue.PARAM_VALUE_CONVERTER,
- TimerValue.ENTITY_CONVERTER
+ TimerValue.PARAM_VALUE_CONVERTER
)
.bindOutput(
"executionStatus",
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/TimerValue.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/TimerValue.kt
index b16d175..547623f 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/TimerValue.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/TimerValue.kt
@@ -16,12 +16,12 @@
package androidx.appactions.interaction.capabilities.productivity
-import androidx.appactions.builtintypes.experimental.types.Timer
+import androidx.appactions.builtintypes.types.Timer
import androidx.appactions.interaction.capabilities.core.SearchAction
-import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
import androidx.appactions.interaction.capabilities.core.impl.converters.ParamValueConverter
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.converters.UnionTypeSpec
+import androidx.appactions.interaction.capabilities.serializers.types.TIMER_TYPE_SPEC
import java.util.Objects
class TimerValue
@@ -53,20 +53,18 @@
.bindMemberType(
memberGetter = TimerValue::asTimer,
ctor = { TimerValue(it) },
- typeSpec = TypeConverters.TIMER_TYPE_SPEC,
+ typeSpec = TIMER_TYPE_SPEC,
)
.bindMemberType(
memberGetter = TimerValue::asTimerFilter,
ctor = { TimerValue(it) },
typeSpec =
TypeConverters.createSearchActionTypeSpec(
- TypeConverters.TIMER_TYPE_SPEC,
+ TIMER_TYPE_SPEC,
),
)
.build()
internal val PARAM_VALUE_CONVERTER = ParamValueConverter.of(TYPE_SPEC)
-
- internal val ENTITY_CONVERTER = EntityConverter.of(TYPE_SPEC)
}
}
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/PauseTimerTest.kt b/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/PauseTimerTest.kt
index 74a8f0e..5b79278 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/PauseTimerTest.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/PauseTimerTest.kt
@@ -17,7 +17,7 @@
package androidx.appactions.interaction.capabilities.productivity
import android.util.SizeF
-import androidx.appactions.builtintypes.experimental.types.Timer
+import androidx.appactions.builtintypes.types.Timer
import androidx.appactions.interaction.capabilities.core.ExecutionCallback
import androidx.appactions.interaction.capabilities.core.ExecutionResult
import androidx.appactions.interaction.capabilities.core.HostProperties
@@ -49,7 +49,7 @@
val argsDeferred = CompletableDeferred<Arguments>()
val capability = PauseTimer.CapabilityBuilder()
.setId("pause timer")
- .setTimerListProperty(Property.Builder<TimerValue>().setRequired(true).build())
+ .setTimerProperty(Property.Builder<Timer>().setRequired(true).build())
.setExecutionCallback(
ExecutionCallback {
argsDeferred.complete(it)
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/ResetTimerTest.kt b/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/ResetTimerTest.kt
index 163f560..d9ae096 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/ResetTimerTest.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/ResetTimerTest.kt
@@ -17,7 +17,7 @@
package androidx.appactions.interaction.capabilities.productivity
import android.util.SizeF
-import androidx.appactions.builtintypes.experimental.types.Timer
+import androidx.appactions.builtintypes.types.Timer
import androidx.appactions.interaction.capabilities.core.ExecutionCallback
import androidx.appactions.interaction.capabilities.core.ExecutionResult
import androidx.appactions.interaction.capabilities.core.HostProperties
@@ -49,7 +49,7 @@
val argsDeferred = CompletableDeferred<Arguments>()
val capability = ResetTimer.CapabilityBuilder()
.setId("reset timer")
- .setTimerListProperty(Property.Builder<TimerValue>().setRequired(true).build())
+ .setTimerProperty(Property.Builder<Timer>().setRequired(true).build())
.setExecutionCallback(
ExecutionCallback {
argsDeferred.complete(it)
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimerTest.kt b/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimerTest.kt
index 8e82cdf..ff6c9db 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimerTest.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimerTest.kt
@@ -17,7 +17,7 @@
package androidx.appactions.interaction.capabilities.productivity
import android.util.SizeF
-import androidx.appactions.builtintypes.experimental.types.Timer
+import androidx.appactions.builtintypes.types.Timer
import androidx.appactions.interaction.capabilities.core.ExecutionCallback
import androidx.appactions.interaction.capabilities.core.ExecutionResult
import androidx.appactions.interaction.capabilities.core.HostProperties
@@ -49,7 +49,7 @@
val argsDeferred = CompletableDeferred<Arguments>()
val capability = ResumeTimer.CapabilityBuilder()
.setId("resume timer")
- .setTimerListProperty(Property.Builder<TimerValue>().setRequired(true).build())
+ .setTimerProperty(Property.Builder<Timer>().setRequired(true).build())
.setExecutionCallback(
ExecutionCallback {
argsDeferred.complete(it)
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/StopTimerTest.kt b/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/StopTimerTest.kt
index 343ee54f..f5ffe34 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/StopTimerTest.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/test/java/androidx/appactions/interaction/capabilities/productivity/StopTimerTest.kt
@@ -17,7 +17,7 @@
package androidx.appactions.interaction.capabilities.productivity
import android.util.SizeF
-import androidx.appactions.builtintypes.experimental.types.Timer
+import androidx.appactions.builtintypes.types.Timer
import androidx.appactions.interaction.capabilities.core.ExecutionCallback
import androidx.appactions.interaction.capabilities.core.ExecutionResult
import androidx.appactions.interaction.capabilities.core.HostProperties
@@ -49,7 +49,7 @@
val argsDeferred = CompletableDeferred<Arguments>()
val capability = StopTimer.CapabilityBuilder()
.setId("stop timer")
- .setTimerListProperty(Property.Builder<TimerValue>().setRequired(true).build())
+ .setTimerProperty(Property.Builder<Timer>().setRequired(true).build())
.setExecutionCallback(
ExecutionCallback {
argsDeferred.complete(it)
diff --git a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartEmergencySharing.kt b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartEmergencySharing.kt
index 704cbf1..423715b 100644
--- a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartEmergencySharing.kt
+++ b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartEmergencySharing.kt
@@ -25,7 +25,6 @@
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.Property
import androidx.appactions.interaction.capabilities.safety.executionstatus.EmergencySharingInProgress
import androidx.appactions.interaction.capabilities.safety.executionstatus.SafetyAccountNotLoggedIn
import androidx.appactions.interaction.capabilities.safety.executionstatus.SafetyFeatureNotOnboarded
@@ -41,14 +40,7 @@
class CapabilityBuilder :
Capability.Builder<
CapabilityBuilder, Arguments, Output, Confirmation, ExecutionSession,
- >(ACTION_SPEC) {
-
- private var properties = mutableMapOf<String, Property<*>>()
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
- }
+ >(ACTION_SPEC)
class Arguments internal constructor() {
class Builder : BuilderOf<Arguments> {
diff --git a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartSafetyCheck.kt b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartSafetyCheck.kt
index 63737d9..6e9bec6 100644
--- a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartSafetyCheck.kt
+++ b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartSafetyCheck.kt
@@ -44,7 +44,7 @@
/** A capability corresponding to actions.intent.START_SAFETY_CHECK */
@CapabilityFactory(name = CAPABILITY_NAME)
class StartSafetyCheck private constructor() {
- internal enum class PropertyMapStrings(val key: String) {
+ internal enum class SlotMetadata(val path: String) {
DURATION("safetycheck.duration"),
CHECK_IN_TIME("safetycheck.checkInTime")
}
@@ -53,18 +53,19 @@
Capability.Builder<
CapabilityBuilder, Arguments, Output, Confirmation, ExecutionSession
>(ACTION_SPEC) {
- private var properties = mutableMapOf<String, Property<*>>()
+ fun setDurationProperty(duration: Property<Duration>): CapabilityBuilder = setProperty(
+ SlotMetadata.DURATION.path,
+ duration,
+ TypeConverters.DURATION_ENTITY_CONVERTER
+ )
- fun setDuration(duration: Property<Duration>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.DURATION.key] = duration }
-
- fun setCheckInTime(checkInTime: Property<ZonedDateTime>): CapabilityBuilder =
- apply { properties[PropertyMapStrings.CHECK_IN_TIME.key] = checkInTime }
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
+ fun setCheckInTimeProperty(
+ checkInTime: Property<ZonedDateTime>
+ ): CapabilityBuilder = setProperty(
+ SlotMetadata.CHECK_IN_TIME.path,
+ checkInTime,
+ TypeConverters.ZONED_DATE_TIME_ENTITY_CONVERTER
+ )
}
class Arguments internal constructor(
@@ -225,28 +226,19 @@
sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
companion object {
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC =
ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindParameter(
- "safetyCheck.duration",
- { properties ->
- properties[PropertyMapStrings.DURATION.key] as? Property<Duration>
- },
+ SlotMetadata.DURATION.path,
Arguments.Builder::setDuration,
- TypeConverters.DURATION_PARAM_VALUE_CONVERTER,
- TypeConverters.DURATION_ENTITY_CONVERTER
+ TypeConverters.DURATION_PARAM_VALUE_CONVERTER
)
.bindParameter(
- "safetyCheck.checkInTime",
- { properties ->
- properties[PropertyMapStrings.CHECK_IN_TIME.key] as? Property<ZonedDateTime>
- },
+ SlotMetadata.CHECK_IN_TIME.path,
Arguments.Builder::setCheckInTime,
- TypeConverters.ZONED_DATETIME_PARAM_VALUE_CONVERTER,
- TypeConverters.ZONED_DATETIME_ENTITY_CONVERTER
+ TypeConverters.ZONED_DATE_TIME_PARAM_VALUE_CONVERTER
)
.bindOutput(
"safetyCheck",
diff --git a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopEmergencySharing.kt b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopEmergencySharing.kt
index e35c3b5..90b7827 100644
--- a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopEmergencySharing.kt
+++ b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopEmergencySharing.kt
@@ -26,7 +26,6 @@
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.Property
import androidx.appactions.interaction.capabilities.safety.executionstatus.SafetyAccountNotLoggedIn
import androidx.appactions.interaction.capabilities.safety.executionstatus.SafetyFeatureNotOnboarded
import androidx.appactions.interaction.proto.ParamValue
@@ -41,15 +40,7 @@
class CapabilityBuilder :
Capability.Builder<
CapabilityBuilder, Arguments, Output, Confirmation, ExecutionSession,
- >(ACTION_SPEC) {
-
- private var properties = mutableMapOf<String, Property<*>>()
-
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
- }
+ >(ACTION_SPEC)
class Arguments internal constructor() {
class Builder : BuilderOf<Arguments> {
diff --git a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopSafetyCheck.kt b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopSafetyCheck.kt
index 7734f23..e8bb0a9 100644
--- a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopSafetyCheck.kt
+++ b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopSafetyCheck.kt
@@ -26,7 +26,6 @@
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.Property
import androidx.appactions.interaction.capabilities.safety.executionstatus.SafetyAccountNotLoggedIn
import androidx.appactions.interaction.capabilities.safety.executionstatus.SafetyFeatureNotOnboarded
import androidx.appactions.interaction.proto.ParamValue
@@ -41,14 +40,7 @@
class CapabilityBuilder :
Capability.Builder<
CapabilityBuilder, Arguments, Output, Confirmation, ExecutionSession
- >(ACTION_SPEC) {
-
- private var properties = mutableMapOf<String, Property<*>>()
- override fun build(): Capability {
- super.setProperty(properties)
- return super.build()
- }
- }
+ >(ACTION_SPEC)
class Arguments internal constructor() {
class Builder : BuilderOf<Arguments> {
diff --git a/appactions/interaction/interaction-proto/src/main/proto/app_actions_data.proto b/appactions/interaction/interaction-proto/src/main/proto/app_actions_data.proto
index 4ae871a..dfae0d4 100644
--- a/appactions/interaction/interaction-proto/src/main/proto/app_actions_data.proto
+++ b/appactions/interaction/interaction-proto/src/main/proto/app_actions_data.proto
@@ -420,4 +420,40 @@
// start dictation.
bool text_input = 1;
}
-}
\ No newline at end of file
+}
+
+// Represents the result of sending an execution request to a capability.
+// NEXT_ID: 2
+message AppInteractionMetadata {
+
+ // The error status of capability execution.
+ // NEXT_ID: 10
+ enum ErrorStatus {
+ // Unexpected error occurred.
+ UNKNOWN_ERROR_STATUS = 0;
+ // The current capability session was cancelled, likely because a new request was sent to the
+ // capability before the first had time to complete.
+ CANCELED = 1;
+ // Developer provided callback has timed out. Note, there might be a transport level timeout in
+ // addition to the capability specific one, which may be less than the capability timeout. In
+ // such cases, the capability should receive a fulfillment request with CANCEL status.
+ TIMEOUT = 2;
+ // Invalid data was sent to the capability. This could be a nonsensical request Type or
+ // malformed arguments (e.g. wrong data format for a BII argument).
+ INVALID_REQUEST = 3;
+ // An exception was thrown from a developer-provided callback.
+ EXTERNAL_EXCEPTION = 7;
+ // Tried to send request to a particular capability session, but that session has not been
+ // started or has already ended.
+ SESSION_NOT_FOUND = 8;
+ // Tried to start up a session for a particular capability ID but the capability was not found.
+ CAPABILITY_NOT_FOUND = 9;
+ // UI was requested but there is no UI currently set.
+ NO_UI_ELEMENTS = 10;
+ // Internal error occurred.
+ INTERNAL = 11;
+ }
+
+ // ErrorStatus of capability execution. Can be logged to a dashboard to
+ ErrorStatus error_status = 1;
+}
diff --git a/appactions/interaction/interaction-service-proto/build.gradle b/appactions/interaction/interaction-service-proto/build.gradle
index 89a9271..9e627e8 100644
--- a/appactions/interaction/interaction-service-proto/build.gradle
+++ b/appactions/interaction/interaction-service-proto/build.gradle
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import androidx.build.LibraryType
import androidx.build.Publish
import androidx.build.RunApiTasks
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionGrpcMetadata.kt b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionGrpcMetadata.kt
new file mode 100644
index 0000000..9b81b60
--- /dev/null
+++ b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionGrpcMetadata.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.appactions.interaction.service
+
+import androidx.appactions.interaction.capabilities.core.impl.ErrorStatusInternal
+import androidx.appactions.interaction.proto.AppInteractionMetadata
+import androidx.appactions.interaction.proto.AppInteractionMetadata.ErrorStatus
+import androidx.appactions.interaction.protobuf.InvalidProtocolBufferException
+import io.grpc.Metadata
+
+/**
+ * Utilities to attach App Interaction specific metadata to any gRPC response
+ * (via StatusRuntimeException).
+ */
+internal object AppInteractionGrpcMetadata {
+
+ /** [Metadata.Key] used on gRPC trailers to pass [AppInteractionMetadata]. */
+ val INTERACTION_SERVICE_STATUS_KEY: Metadata.Key<AppInteractionMetadata> = Metadata.Key.of(
+ "interaction-service-metadata-bin",
+ object : Metadata.BinaryMarshaller<AppInteractionMetadata> {
+
+ override fun toBytes(value: AppInteractionMetadata): ByteArray {
+ return value.toByteArray()
+ }
+
+ override fun parseBytes(serialized: ByteArray): AppInteractionMetadata {
+ return try {
+ AppInteractionMetadata.parseFrom(serialized)
+ } catch (e: InvalidProtocolBufferException) {
+ throw IllegalArgumentException(e)
+ }
+ }
+ })
+
+ private fun buildAppInteractionMetadata(
+ errorStatusInternal: ErrorStatusInternal
+ ): AppInteractionMetadata {
+ val errorStatus = when (errorStatusInternal) {
+ ErrorStatusInternal.UNKNOWN_ERROR_STATUS,
+ -> ErrorStatus.UNKNOWN_ERROR_STATUS
+ ErrorStatusInternal.INTERNAL -> ErrorStatus.INTERNAL
+ ErrorStatusInternal.CANCELED -> ErrorStatus.CANCELED
+ ErrorStatusInternal.TIMEOUT -> ErrorStatus.TIMEOUT
+ ErrorStatusInternal.INVALID_REQUEST -> ErrorStatus.INVALID_REQUEST
+ ErrorStatusInternal.SESSION_NOT_FOUND,
+ -> ErrorStatus.SESSION_NOT_FOUND
+ ErrorStatusInternal.EXTERNAL_EXCEPTION -> ErrorStatus.EXTERNAL_EXCEPTION
+ }
+ return AppInteractionMetadata.newBuilder()
+ .setErrorStatus(errorStatus)
+ .build()
+ }
+
+ /**
+ * Supply errors directly from the service library. For example, sometimes we need to return an
+ * error before we invoked any capability.
+ */
+ fun metadataOf(errorStatus: ErrorStatus): Metadata {
+ val metadata = Metadata()
+ metadata.put(
+ INTERACTION_SERVICE_STATUS_KEY,
+ AppInteractionMetadata.newBuilder()
+ .setErrorStatus(errorStatus)
+ .build()
+ )
+ return metadata
+ }
+
+ /** Supply errors by converting from errors in the Capability library. */
+ fun metadataOf(errorStatusInternal: ErrorStatusInternal): Metadata {
+ val metadata = Metadata()
+ metadata.put(
+ INTERACTION_SERVICE_STATUS_KEY,
+ buildAppInteractionMetadata(errorStatusInternal)
+ )
+ return metadata
+ }
+}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionService.kt b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionService.kt
index 623fc0f..34a1b37 100644
--- a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionService.kt
+++ b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionService.kt
@@ -52,7 +52,7 @@
*
* @return the list of EntityProvider that this service supports.
*/
- abstract val registeredEntityProviders: List<EntityProvider<*>>
+ open val registeredEntityProviders: List<EntityProvider<*>> = listOf()
/**
* A list of [AppVerificationInfo] which define who is allowed to interact with the app's bound
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceFactory.kt b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceFactory.kt
index d95524a..f35c045 100644
--- a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceFactory.kt
+++ b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceFactory.kt
@@ -20,12 +20,12 @@
import io.grpc.BindableService
/**
- * Factory for returning a [BindableService] from an []AppInteractionService].
+ * Factory for returning a [BindableService] from an [AppInteractionService].
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
object AppInteractionServiceFactory {
/**
- * Creates a new instance of the gRPC service from the developer's []AppInteractionService]
+ * Creates a new instance of the gRPC service from the developer's [AppInteractionService]
* (android service).
*/
fun create(appInteractionService: AppInteractionService): BindableService {
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImpl.kt b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImpl.kt
index c3b7557..7365f3e 100644
--- a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImpl.kt
+++ b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImpl.kt
@@ -31,6 +31,7 @@
import androidx.appactions.interaction.capabilities.core.impl.utils.CapabilityLogger.LogLevel
import androidx.appactions.interaction.capabilities.core.impl.utils.LoggerInternal
import androidx.appactions.interaction.proto.AppActionsContext
+import androidx.appactions.interaction.proto.AppInteractionMetadata.ErrorStatus
import androidx.appactions.interaction.proto.FulfillmentRequest
import androidx.appactions.interaction.proto.FulfillmentResponse
import androidx.appactions.interaction.proto.GroundingRequest
@@ -143,15 +144,15 @@
if (registeredCapabilities.isEmpty()) {
registeredCapabilities = appInteractionService.registeredCapabilities
}
- val targetCapability = registeredCapabilities
- .filter { request.identifier == it.id }
- .firstOrNull()
+ val targetCapability =
+ registeredCapabilities.firstOrNull { request.identifier == it.id }
if (targetCapability == null) {
return respondWithError(
StatusRuntimeException(
Status.FAILED_PRECONDITION.withDescription(
ERROR_NO_ACTION_CAPABILITY,
),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.CAPABILITY_NOT_FOUND)
),
startSessionResponseObserver,
)
@@ -200,6 +201,7 @@
Status.FAILED_PRECONDITION.withDescription(
ERROR_NO_FULFILLMENT_REQUEST,
),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.INVALID_REQUEST)
),
responseObserver,
)
@@ -213,6 +215,7 @@
Status.FAILED_PRECONDITION.withDescription(
ERROR_NO_ACTION_CAPABILITY,
),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.CAPABILITY_NOT_FOUND)
),
responseObserver,
)
@@ -223,6 +226,7 @@
return respondWithError(
StatusRuntimeException(
Status.FAILED_PRECONDITION.withDescription(ERROR_NO_SESSION),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.SESSION_NOT_FOUND)
),
responseObserver,
)
@@ -231,6 +235,7 @@
return respondWithError(
StatusRuntimeException(
Status.FAILED_PRECONDITION.withDescription(ERROR_SESSION_ENDED),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.SESSION_NOT_FOUND)
),
responseObserver,
)
@@ -267,9 +272,9 @@
is CapabilityExecutionException -> convertToGrpcException(t)
is StatusRuntimeException, is StatusException -> t
else -> StatusRuntimeException(
- Status.INTERNAL.withDescription(
- t.message,
- ).withCause(t),
+ Status.INTERNAL.withDescription(t.message).withCause(t),
+ AppInteractionGrpcMetadata.metadataOf(
+ ErrorStatus.UNKNOWN_ERROR_STATUS)
)
},
responseObserver,
@@ -291,6 +296,7 @@
return respondWithError(
StatusRuntimeException(
Status.FAILED_PRECONDITION.withDescription(ERROR_NO_SESSION),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.SESSION_NOT_FOUND)
),
responseObserver,
)
@@ -298,7 +304,8 @@
val uiCache = UiSessions.getUiCacheOrNull(sessionId)
if (uiCache == null) {
return respondWithError(
- StatusRuntimeException(Status.INTERNAL.withDescription(ERROR_NO_UI)),
+ StatusRuntimeException(Status.INTERNAL.withDescription(ERROR_NO_UI),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.NO_UI_ELEMENTS)),
responseObserver,
)
}
@@ -308,7 +315,8 @@
if (tileLayoutInternal == null && remoteViewsInternal == null) {
UiSessions.removeUiCache(sessionId)
return respondWithError(
- StatusRuntimeException(Status.INTERNAL.withDescription(ERROR_NO_UI)),
+ StatusRuntimeException(Status.INTERNAL.withDescription(ERROR_NO_UI),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.NO_UI_ELEMENTS)),
responseObserver
)
}
@@ -331,11 +339,12 @@
req: CollectionRequest,
responseObserver: StreamObserver<CollectionResponse>,
) {
- val sessionId = req.getSessionIdentifier()!!
+ val sessionId = req.sessionIdentifier!!
if (SessionManager.getSession(sessionId) == null) {
return respondWithError(
StatusRuntimeException(
Status.FAILED_PRECONDITION.withDescription(ERROR_NO_SESSION),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.SESSION_NOT_FOUND)
),
responseObserver,
)
@@ -343,7 +352,10 @@
val uiCache = UiSessions.getUiCacheOrNull(sessionId)
if (uiCache == null) {
return respondWithError(
- StatusRuntimeException(Status.INTERNAL.withDescription(ERROR_NO_UI)),
+ StatusRuntimeException(
+ Status.INTERNAL.withDescription(ERROR_NO_UI),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.NO_UI_ELEMENTS)
+ ),
responseObserver,
)
}
@@ -351,7 +363,8 @@
if (factory == null) {
return respondWithError(
StatusRuntimeException(
- Status.UNIMPLEMENTED.withDescription(ERROR_NO_COLLECTION_SUPPORT),
+ Status.INTERNAL.withDescription(ERROR_NO_COLLECTION_SUPPORT),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.UNKNOWN_ERROR_STATUS),
),
responseObserver,
)
@@ -423,9 +436,8 @@
when (t) {
is StatusRuntimeException, is StatusException -> t
else -> StatusRuntimeException(
- Status.INTERNAL.withDescription(
- t.message,
- ).withCause(t),
+ Status.INTERNAL.withDescription(t.message,).withCause(t),
+ AppInteractionGrpcMetadata.metadataOf(ErrorStatus.UNKNOWN_ERROR_STATUS)
)
},
responseObserver,
@@ -541,14 +553,20 @@
}
internal fun convertToGrpcException(e: CapabilityExecutionException): StatusRuntimeException {
- return when (e.errorStatus) {
- ErrorStatusInternal.TIMEOUT -> StatusRuntimeException(
- Status.DEADLINE_EXCEEDED.withDescription(e.message).withCause(e),
- )
- else -> StatusRuntimeException(
- Status.INTERNAL.withDescription(e.message).withCause(e),
- )
+ val rpcStatus = when (e.errorStatus) {
+ ErrorStatusInternal.UNKNOWN_ERROR_STATUS -> Status.UNKNOWN
+ ErrorStatusInternal.CANCELED -> Status.CANCELLED
+ ErrorStatusInternal.TIMEOUT -> Status.DEADLINE_EXCEEDED
+ ErrorStatusInternal.INVALID_REQUEST -> Status.INVALID_ARGUMENT
+ ErrorStatusInternal.SESSION_NOT_FOUND -> Status.FAILED_PRECONDITION
+ ErrorStatusInternal.INTERNAL,
+ ErrorStatusInternal.EXTERNAL_EXCEPTION,
+ -> Status.INTERNAL
}
+ return StatusRuntimeException(
+ rpcStatus.withDescription(e.message).withCause(e),
+ AppInteractionGrpcMetadata.metadataOf(e.errorStatus)
+ )
}
internal fun convertFulfillmentResponse(
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppVerificationInfo.kt b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppVerificationInfo.kt
index 90af3ce..92503ef 100644
--- a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppVerificationInfo.kt
+++ b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppVerificationInfo.kt
@@ -39,13 +39,13 @@
/** Builder for constructing an AppVerificationInfo instance. */
class Builder {
private var packageName: String? = null
- private var signatures: List<ByteArray> = emptyList()
+ private var signatures: List<ByteArray> = mutableListOf()
/** Set the packageName that will be part of the [AppVerificationInfo] */
fun setPackageName(packageName: String) = apply { this.packageName = packageName }
/** Set the packageName that will be part of the [AppVerificationInfo] */
- fun addSignature(signatures: List<ByteArray>) = apply { this.signatures = signatures }
+ fun addSignature(signatures: ByteArray) = apply { this.signatures = listOf(signatures) }
/**
* Creates a new instance of [AppVerificationInfo]
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/CapabilityExecutionException.java b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/CapabilityExecutionException.java
deleted file mode 100644
index ffc4686..0000000
--- a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/CapabilityExecutionException.java
+++ /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.appactions.interaction.service;
-
-import androidx.appactions.interaction.capabilities.core.impl.ErrorStatusInternal;
-
-/** Exception that occurs from failure to execute capability when sending fulfillment request. */
-final class CapabilityExecutionException extends RuntimeException {
-
- private final ErrorStatusInternal mErrorStatus;
-
- CapabilityExecutionException(ErrorStatusInternal mErrorStatus, String message) {
- super(message);
- this.mErrorStatus = mErrorStatus;
- }
-
- ErrorStatusInternal getErrorStatus() {
- return this.mErrorStatus;
- }
-}
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/CapabilityExecutionException.kt b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/CapabilityExecutionException.kt
new file mode 100644
index 0000000..243c469
--- /dev/null
+++ b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/CapabilityExecutionException.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.appactions.interaction.service
+
+import androidx.appactions.interaction.capabilities.core.impl.ErrorStatusInternal
+
+/** Exception that occurs from failure to execute capability when sending fulfillment request. */
+internal class CapabilityExecutionException(
+ val errorStatus: ErrorStatusInternal,
+ message: String?
+) : RuntimeException(message)
\ No newline at end of file
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceEntityProviderTest.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceEntityProviderTest.kt
index d2794ec..c955f86 100644
--- a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceEntityProviderTest.kt
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceEntityProviderTest.kt
@@ -16,9 +16,9 @@
package androidx.appactions.interaction.service
-import androidx.appactions.builtintypes.experimental.types.Alarm
+import androidx.appactions.builtintypes.types.Alarm
import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
-import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
+import androidx.appactions.interaction.capabilities.serializers.types.ALARM_TYPE_SPEC
import androidx.appactions.interaction.capabilities.testing.internal.ArgumentUtils.buildSearchActionParamValue
import androidx.appactions.interaction.capabilities.testing.internal.TestingUtils.awaitSync
import androidx.appactions.interaction.proto.GroundingRequest
@@ -144,7 +144,7 @@
.setStatus(Status.SUCCESS)
.addCandidates(
Candidate.newBuilder().setGroundedEntity(
- EntityConverter.of(TypeConverters.ALARM_TYPE_SPEC).convert(morningAlarm)
+ EntityConverter.of(ALARM_TYPE_SPEC).convert(morningAlarm)
)
)
).build()
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImplTest.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImplTest.kt
index 66c8427..5f3826d 100644
--- a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImplTest.kt
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImplTest.kt
@@ -16,15 +16,24 @@
package androidx.appactions.interaction.service
+import android.content.Context
+import android.util.SizeF
+import android.widget.RemoteViews
+import android.widget.RemoteViewsService.RemoteViewsFactory
import androidx.appactions.interaction.capabilities.core.Capability
+import androidx.appactions.interaction.capabilities.core.ExecutionResult
import androidx.appactions.interaction.capabilities.core.impl.CallbackInternal
import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession
+import androidx.appactions.interaction.capabilities.core.impl.ErrorStatusInternal
import androidx.appactions.interaction.proto.AppActionsContext
import androidx.appactions.interaction.proto.AppActionsContext.AppAction
import androidx.appactions.interaction.proto.AppActionsContext.AppDialogState
+import androidx.appactions.interaction.proto.AppInteractionMetadata.ErrorStatus
import androidx.appactions.interaction.proto.CurrentValue
import androidx.appactions.interaction.proto.FulfillmentRequest
import androidx.appactions.interaction.proto.FulfillmentRequest.Fulfillment
+import androidx.appactions.interaction.proto.FulfillmentRequest.Fulfillment.FulfillmentParam
+import androidx.appactions.interaction.proto.FulfillmentRequest.Fulfillment.FulfillmentValue
import androidx.appactions.interaction.proto.FulfillmentResponse
import androidx.appactions.interaction.proto.FulfillmentResponse.StructuredOutput
import androidx.appactions.interaction.proto.FulfillmentResponse.StructuredOutput.OutputValue
@@ -35,11 +44,22 @@
import androidx.appactions.interaction.service.AppInteractionServiceGrpcImpl.Companion.ERROR_SESSION_ENDED
import androidx.appactions.interaction.service.proto.AppInteractionServiceGrpc
import androidx.appactions.interaction.service.proto.AppInteractionServiceGrpc.AppInteractionServiceStub
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionRequest.GetCount
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionRequest.GetItemId
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionRequest.GetLoadingView
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionRequest.GetViewAt
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionRequest.GetViewTypeCount
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionRequest.HasStableIds
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionRequest.OnDestroy
import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.Request
import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.StartSessionRequest
import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.StartSessionResponse
+import androidx.appactions.interaction.service.test.R
import androidx.appactions.interaction.service.testing.internal.FakeAppInteractionService
+import androidx.appactions.interaction.service.testing.internal.FakeCapability
import androidx.concurrent.futures.await
+import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import io.grpc.BindableService
@@ -57,6 +77,7 @@
import kotlin.test.assertFailsWith
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.runBlocking
+import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -64,6 +85,7 @@
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.times
@@ -101,6 +123,26 @@
.addOutputValues(OutputValue.newBuilder().setName("bio_arg1")),
)
.build()
+ private val testFulfillmentRequestUi =
+ FulfillmentRequest.newBuilder()
+ .addFulfillments(
+ Fulfillment.newBuilder()
+ .setName(testBiiName)
+ .setIdentifier(capabilityId)
+ .addParams(
+ FulfillmentParam.newBuilder()
+ .setName("fieldOne")
+ .addFulfillmentValues(
+ FulfillmentValue.newBuilder()
+ .setValue(
+ ParamValue.newBuilder().setStringValue("hello").build())
+ .build())
+ .build())
+ .setType(Fulfillment.Type.SYNC)
+ .setSyncStatus(Fulfillment.SyncStatus.SLOTS_COMPLETE)
+ .build()
+ )
+ .build()
private val testAppDialogState = AppDialogState.newBuilder().setFulfillmentIdentifier("id")
.addParams(
AppActionsContext.DialogParameter.newBuilder()
@@ -114,8 +156,31 @@
private lateinit var capability1: Capability
private lateinit var appInteractionService: FakeAppInteractionService
+ private val context: Context = ApplicationProvider.getApplicationContext()
+ private val remoteViewsFactoryId = 123
+ private val remoteViews = RemoteViews(context.packageName, R.layout.remote_view)
+
+ private fun createFakeCapability(vararg uiResponses: UiResponse):
+ Capability {
+ return FakeCapability.CapabilityBuilder()
+ .setId(capabilityId)
+ .setExecutionSessionFactory { _ ->
+ object : FakeCapability.ExecutionSession {
+ override suspend fun onExecute(
+ arguments: FakeCapability.Arguments,
+ ): ExecutionResult<FakeCapability.Output> {
+ for (uiResponse in uiResponses) {
+ this.updateUi(uiResponse)
+ }
+ return ExecutionResult.Builder<FakeCapability.Output>().build()
+ }
+ }
+ }
+ .build()
+ }
+
@Before
- fun before() {
+ fun setup() {
capability1 = mock()
whenever(capability1.id).thenReturn(capabilityId)
whenever(capability1.appAction).thenReturn(AppAction.getDefaultInstance())
@@ -127,6 +192,11 @@
appInteractionService.registeredCapabilities = listOf(capability1)
}
+ @After
+ fun cleanup() {
+ UiSessions.removeUiCache(sessionId)
+ }
+
@Test
fun startUpSession_validRequest_success(): Unit = runBlocking {
val server =
@@ -168,6 +238,496 @@
}
@Test
+ fun requestUi_respondWithRemoteViewsInMetadata(): Unit = runBlocking {
+
+ val remoteViewsUiResponse =
+ UiResponse.RemoteViewsUiBuilder()
+ .setRemoteViews(remoteViews, SizeF(10f, 15f))
+ .addRemoteViewsFactory(remoteViewsFactoryId, FakeRemoteViewsFactory())
+ .build()
+
+ appInteractionService.registeredCapabilities = listOf(
+ createFakeCapability(remoteViewsUiResponse)
+ )
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+
+ assertStartupSession(stub)
+
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequestUi)
+ .build()
+
+ val responseFuture = futureStub.sendRequestFulfillment(request)
+ responseFuture.await()
+
+ val responseObserver = mock<StreamObserver<AppInteractionServiceProto.UiResponse>>()
+ stub.requestUi(
+ AppInteractionServiceProto.UiRequest.newBuilder()
+ .setSessionIdentifier(sessionId).build(),
+ responseObserver
+ )
+ val responseCaptor = argumentCaptor<AppInteractionServiceProto.UiResponse>()
+ verify(responseObserver).onNext(responseCaptor.capture())
+ assertThat(responseCaptor.firstValue).isEqualTo(
+ AppInteractionServiceProto.UiResponse.newBuilder().setRemoteViewsInfo(
+ AppInteractionServiceProto.RemoteViewsInfo.newBuilder()
+ .setWidthDp(10f)
+ .setHeightDp(15f)
+ .build()
+ ).build()
+ )
+
+ server.shutdownNow()
+ }
+
+ @Test
+ @Suppress("deprecation")
+ fun requestUi_respondWithTileLayout(): Unit = runBlocking {
+
+ val layout = androidx.wear.tiles.LayoutElementBuilders.Layout.Builder()
+ .setRoot(androidx.wear.tiles.LayoutElementBuilders.Row.Builder().build())
+ .build()
+ val resource = androidx.wear.tiles.ResourceBuilders.Resources.Builder()
+ .setVersion("123").build()
+ val tileLayout = UiResponse.TileLayoutBuilder().setTileLayout(layout, resource).build()
+
+ appInteractionService.registeredCapabilities = listOf(
+ createFakeCapability(tileLayout)
+ )
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+
+ assertStartupSession(stub)
+
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequestUi)
+ .build()
+
+ val responseFuture = futureStub.sendRequestFulfillment(request)
+ responseFuture.await()
+
+ val uiResponse = futureStub.requestUi(AppInteractionServiceProto.UiRequest.newBuilder()
+ .setSessionIdentifier(sessionId).build()).await()
+
+ assertThat(uiResponse.uiTypeCase).isEqualTo(AppInteractionServiceProto
+ .UiResponse.UiTypeCase.TILE_LAYOUT)
+ assertThat(uiResponse.tileLayout.layout).isNotEmpty()
+ assertThat(uiResponse.tileLayout.resources).isNotEmpty()
+
+ server.shutdownNow()
+ }
+
+ @Test
+ fun requestUi_noUi_failWithStatusRuntimeException(): Unit = runBlocking {
+
+ appInteractionService.registeredCapabilities = listOf(
+ createFakeCapability() // Not setting any Ui response
+ )
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+
+ assertStartupSession(stub)
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequestUi)
+ .build()
+
+ val responseFuture = futureStub.sendRequestFulfillment(request)
+ responseFuture.await()
+
+ val responseObserver = mock<StreamObserver<AppInteractionServiceProto.UiResponse>>()
+ stub.requestUi(
+ AppInteractionServiceProto.UiRequest.newBuilder()
+ .setSessionIdentifier(sessionId).build(),
+ responseObserver
+ )
+
+ val errorCaptor = argumentCaptor<StatusRuntimeException>()
+ verify(responseObserver).onError(errorCaptor.capture())
+ assertThat(errorCaptor.firstValue.status.code).isEqualTo(
+ Status.INTERNAL.code
+ )
+ assertThat(errorCaptor.firstValue.status.description).isEqualTo("No UI set")
+
+ server.shutdownNow()
+ }
+
+ @Test
+ fun collectionRequestTriggersRemoteViewFactory(): Unit = runBlocking {
+
+ val mockedRemoteViewFactory = mock<RemoteViewsFactory>()
+ val remoteViewsUiResponse = UiResponse.RemoteViewsUiBuilder()
+ .setRemoteViews(remoteViews, SizeF(10f, 15f))
+ .addRemoteViewsFactory(remoteViewsFactoryId, mockedRemoteViewFactory)
+ .build()
+
+ appInteractionService.registeredCapabilities = listOf(
+ createFakeCapability(remoteViewsUiResponse)
+ )
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+
+ assertStartupSession(stub)
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequestUi)
+ .build()
+
+ val responseFuture = futureStub.sendRequestFulfillment(request)
+ responseFuture.await()
+
+ val collectionRequest = AppInteractionServiceProto.CollectionRequest.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setViewId(123)
+ .setGetViewTypeCount(GetViewTypeCount.newBuilder().build()).build()
+ futureStub.requestCollection(collectionRequest)
+ verify(mockedRemoteViewFactory, times(1)).viewTypeCount
+
+ server.shutdownNow()
+ }
+
+ @Test
+ fun collectionRequestTriggersGetCount(): Unit = runBlocking {
+
+ val mockedRemoteViewFactory = mock<RemoteViewsFactory>()
+ whenever(mockedRemoteViewFactory.count) doReturn (3)
+ val remoteViewsUiResponse = UiResponse.RemoteViewsUiBuilder()
+ .setRemoteViews(remoteViews, SizeF(10f, 15f))
+ .addRemoteViewsFactory(remoteViewsFactoryId, mockedRemoteViewFactory)
+ .build()
+
+ appInteractionService.registeredCapabilities = listOf(
+ createFakeCapability(remoteViewsUiResponse)
+ )
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+
+ assertStartupSession(stub)
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequestUi)
+ .build()
+
+ val responseFuture = futureStub.sendRequestFulfillment(request)
+ responseFuture.await()
+
+ val collectionRequest = AppInteractionServiceProto.CollectionRequest.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setViewId(123)
+ .setGetCount(GetCount.newBuilder().build())
+ .build()
+ val collectionResponse = futureStub.requestCollection(collectionRequest).await()
+ verify(mockedRemoteViewFactory).count
+ assertThat(collectionResponse.getCount.count).isEqualTo(3)
+
+ server.shutdownNow()
+ }
+
+ @Test
+ fun collectionRequestTriggersOnDestroy(): Unit = runBlocking {
+
+ val mockedRemoteViewFactory = mock<RemoteViewsFactory>()
+ val remoteViewsUiResponse = UiResponse.RemoteViewsUiBuilder()
+ .setRemoteViews(remoteViews, SizeF(10f, 15f))
+ .addRemoteViewsFactory(remoteViewsFactoryId, mockedRemoteViewFactory)
+ .build()
+
+ appInteractionService.registeredCapabilities = listOf(
+ createFakeCapability(remoteViewsUiResponse)
+ )
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+
+ assertStartupSession(stub)
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequestUi)
+ .build()
+
+ val responseFuture = futureStub.sendRequestFulfillment(request)
+ responseFuture.await()
+
+ val collectionRequest = AppInteractionServiceProto.CollectionRequest.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setViewId(123)
+ .setOnDestroy(OnDestroy.newBuilder().build()).build()
+ futureStub.requestCollection(collectionRequest).await()
+ verify(mockedRemoteViewFactory, times(1)).onDestroy()
+
+ server.shutdownNow()
+ }
+
+ @Test
+ fun collectionRequestTriggersGetViewAt(): Unit = runBlocking {
+
+ val mockedRemoteViewFactory = mock<RemoteViewsFactory>()
+ val remoteViewsUiResponse = UiResponse.RemoteViewsUiBuilder()
+ .setRemoteViews(remoteViews, SizeF(10f, 15f))
+ .addRemoteViewsFactory(remoteViewsFactoryId, mockedRemoteViewFactory)
+ .build()
+
+ appInteractionService.registeredCapabilities = listOf(
+ createFakeCapability(remoteViewsUiResponse)
+ )
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+
+ assertStartupSession(stub)
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequestUi)
+ .build()
+
+ val responseFuture = futureStub.sendRequestFulfillment(request)
+ responseFuture.await()
+
+ val collectionRequest = AppInteractionServiceProto.CollectionRequest.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setViewId(123)
+ .setGetViewAt(GetViewAt.newBuilder().setPosition(1).build()).build()
+ futureStub.requestCollection(collectionRequest).await()
+ verify(mockedRemoteViewFactory, times(1)).getViewAt(1)
+
+ server.shutdownNow()
+ }
+
+ @Test
+ fun collectionRequestTriggersGetLoadingView(): Unit = runBlocking {
+
+ val mockedRemoteViewFactory = mock<RemoteViewsFactory>()
+ val remoteViewsUiResponse = UiResponse.RemoteViewsUiBuilder()
+ .setRemoteViews(remoteViews, SizeF(10f, 15f))
+ .addRemoteViewsFactory(remoteViewsFactoryId, mockedRemoteViewFactory)
+ .build()
+
+ appInteractionService.registeredCapabilities = listOf(
+ createFakeCapability(remoteViewsUiResponse)
+ )
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+
+ assertStartupSession(stub)
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequestUi)
+ .build()
+
+ val responseFuture = futureStub.sendRequestFulfillment(request)
+ responseFuture.await()
+
+ val collectionRequest = AppInteractionServiceProto.CollectionRequest.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setViewId(123)
+ .setGetLoadingView(GetLoadingView.newBuilder().build()).build()
+ futureStub.requestCollection(collectionRequest).await()
+ verify(mockedRemoteViewFactory, times(1)).loadingView
+
+ server.shutdownNow()
+ }
+
+ @Test
+ fun collectionRequestTriggersGetViewTypeCount(): Unit = runBlocking {
+
+ val mockedRemoteViewFactory = mock<RemoteViewsFactory>()
+ whenever(mockedRemoteViewFactory.viewTypeCount) doReturn (1)
+ val remoteViewsUiResponse = UiResponse.RemoteViewsUiBuilder()
+ .setRemoteViews(remoteViews, SizeF(10f, 15f))
+ .addRemoteViewsFactory(remoteViewsFactoryId, mockedRemoteViewFactory)
+ .build()
+
+ appInteractionService.registeredCapabilities = listOf(
+ createFakeCapability(remoteViewsUiResponse)
+ )
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+
+ assertStartupSession(stub)
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequestUi)
+ .build()
+
+ val responseFuture = futureStub.sendRequestFulfillment(request)
+ responseFuture.await()
+
+ val collectionRequest = AppInteractionServiceProto.CollectionRequest.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setViewId(123)
+ .setGetViewTypeCount(GetViewTypeCount.newBuilder().build())
+ .build()
+ val collectionResponse = futureStub.requestCollection(collectionRequest).await()
+ verify(mockedRemoteViewFactory).viewTypeCount
+ assertThat(collectionResponse.getViewTypeCount.viewTypeCount).isEqualTo(1)
+
+ server.shutdownNow()
+ }
+
+ @Test
+ fun collectionRequestTriggersGetItemId(): Unit = runBlocking {
+
+ val mockedRemoteViewFactory = mock<RemoteViewsFactory>()
+ whenever(mockedRemoteViewFactory.getItemId(any())) doReturn (2)
+ val remoteViewsUiResponse = UiResponse.RemoteViewsUiBuilder()
+ .setRemoteViews(remoteViews, SizeF(10f, 15f))
+ .addRemoteViewsFactory(remoteViewsFactoryId, mockedRemoteViewFactory)
+ .build()
+
+ appInteractionService.registeredCapabilities = listOf(
+ createFakeCapability(remoteViewsUiResponse)
+ )
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+
+ assertStartupSession(stub)
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequestUi)
+ .build()
+
+ val responseFuture = futureStub.sendRequestFulfillment(request)
+ responseFuture.await()
+
+ val collectionRequest = AppInteractionServiceProto.CollectionRequest.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setViewId(123)
+ .setGetItemId(GetItemId.newBuilder().setPosition(2).build())
+ .build()
+ val collectionResponse = futureStub.requestCollection(collectionRequest).await()
+ verify(mockedRemoteViewFactory).getItemId(2)
+ assertThat(collectionResponse.getItemId.itemId).isEqualTo(2)
+
+ server.shutdownNow()
+ }
+
+ @Test
+ fun collectionRequestTriggersHasStableIds(): Unit = runBlocking {
+
+ val mockedRemoteViewFactory = mock<RemoteViewsFactory>()
+ whenever(mockedRemoteViewFactory.hasStableIds()) doReturn (true)
+ val remoteViewsUiResponse = UiResponse.RemoteViewsUiBuilder()
+ .setRemoteViews(remoteViews, SizeF(10f, 15f))
+ .addRemoteViewsFactory(remoteViewsFactoryId, mockedRemoteViewFactory)
+ .build()
+
+ appInteractionService.registeredCapabilities = listOf(
+ createFakeCapability(remoteViewsUiResponse)
+ )
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+
+ assertStartupSession(stub)
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequestUi)
+ .build()
+
+ val responseFuture = futureStub.sendRequestFulfillment(request)
+ responseFuture.await()
+
+ val collectionRequest = AppInteractionServiceProto.CollectionRequest.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setViewId(123)
+ .setHasStableIds(HasStableIds.newBuilder().build())
+ .build()
+ val collectionResponse = futureStub.requestCollection(collectionRequest).await()
+ verify(mockedRemoteViewFactory).hasStableIds()
+ assertThat(collectionResponse.hasStableIds.hasStableIds).isEqualTo(true)
+
+ server.shutdownNow()
+ }
+
+ @Test
fun startUpSession_shouldFailWhenNoStaticCapability(): Unit = runBlocking {
val server =
createInProcessServer(
@@ -196,6 +756,8 @@
.isEqualTo(Status.Code.FAILED_PRECONDITION)
assertThat(Status.fromThrowable(exceptionCaptor.firstValue).description)
.isEqualTo(ERROR_NO_ACTION_CAPABILITY)
+ val metadataErrorStatus = assertAndGetErrorStatus(exceptionCaptor.firstValue)
+ assertThat(metadataErrorStatus).isEqualTo(ErrorStatus.CAPABILITY_NOT_FOUND)
verify(capability1, never()).createSession(any(), any())
server.shutdownNow()
@@ -231,6 +793,45 @@
}
@Test
+ fun sendRequestFulfillment_errorFromCallback_errorPassedInGrpcMetadata(): Unit = runBlocking {
+ val mockCapabilitySession = createMockSession()
+ whenever(mockCapabilitySession.execute(any(), any())).thenAnswer { invocation ->
+ (invocation.arguments[1] as CallbackInternal)
+ .onError(ErrorStatusInternal.EXTERNAL_EXCEPTION)
+ }
+ whenever(capability1.createSession(any(), any())).thenReturn(mockCapabilitySession)
+
+ val server =
+ createInProcessServer(
+ AppInteractionServiceGrpcImpl(appInteractionService),
+ remoteViewsInterceptor,
+ )
+ val channel = createInProcessChannel()
+ val stub = AppInteractionServiceGrpc.newStub(channel)
+ val futureStub = AppInteractionServiceGrpc.newFutureStub(channel)
+ assertStartupSession(stub)
+ verify(capability1, times(1)).createSession(any(), any())
+
+ // Send fulfillment request
+ val request =
+ Request.newBuilder()
+ .setSessionIdentifier(sessionId)
+ .setFulfillmentRequest(testFulfillmentRequest)
+ .build()
+ val exception =
+ assertFailsWith<StatusRuntimeException> {
+ futureStub.sendRequestFulfillment(request).await()
+ }
+ assertThat(Status.fromThrowable(exception).code).isEqualTo(Status.Code.INTERNAL)
+ assertThat(Status.fromThrowable(exception).description)
+ .isEqualTo("Error executing action capability")
+ val metadataErrorStatus = assertAndGetErrorStatus(exception)
+ assertThat(metadataErrorStatus).isEqualTo(ErrorStatus.EXTERNAL_EXCEPTION)
+
+ server.shutdownNow()
+ }
+
+ @Test
fun sendRequestFulfillment_shouldFailWhenNoFulfillment(): Unit = runBlocking {
val server =
createInProcessServer(
@@ -256,6 +857,8 @@
assertThat(Status.fromThrowable(exception).code).isEqualTo(Status.Code.FAILED_PRECONDITION)
assertThat(Status.fromThrowable(exception).description)
.isEqualTo(ERROR_NO_FULFILLMENT_REQUEST)
+ val metadataErrorStatus = assertAndGetErrorStatus(exception)
+ assertThat(metadataErrorStatus).isEqualTo(ErrorStatus.INVALID_REQUEST)
server.shutdownNow()
}
@@ -291,6 +894,8 @@
assertThat(Status.fromThrowable(exception).code).isEqualTo(Status.Code.FAILED_PRECONDITION)
assertThat(Status.fromThrowable(exception).description)
.isEqualTo(ERROR_NO_ACTION_CAPABILITY)
+ val metadataErrorStatus = assertAndGetErrorStatus(exception)
+ assertThat(metadataErrorStatus).isEqualTo(ErrorStatus.CAPABILITY_NOT_FOUND)
server.shutdownNow()
}
@@ -323,6 +928,8 @@
}
assertThat(Status.fromThrowable(exception).code).isEqualTo(Status.Code.FAILED_PRECONDITION)
assertThat(Status.fromThrowable(exception).description).isEqualTo(ERROR_NO_SESSION)
+ val metadataErrorStatus = assertAndGetErrorStatus(exception)
+ assertThat(metadataErrorStatus).isEqualTo(ErrorStatus.SESSION_NOT_FOUND)
server.shutdownNow()
}
@@ -358,6 +965,8 @@
}
assertThat(Status.fromThrowable(exception).code).isEqualTo(Status.Code.FAILED_PRECONDITION)
assertThat(Status.fromThrowable(exception).description).isEqualTo(ERROR_SESSION_ENDED)
+ val metadataErrorStatus = assertAndGetErrorStatus(exception)
+ assertThat(metadataErrorStatus).isEqualTo(ErrorStatus.SESSION_NOT_FOUND)
server.shutdownNow()
}
@@ -416,4 +1025,11 @@
whenever(mockSession.uiHandle).thenReturn(Any())
return mockSession
}
+
+ private fun assertAndGetErrorStatus(ex: StatusRuntimeException): ErrorStatus {
+ val appInteractionMetadata =
+ ex.trailers?.get(AppInteractionGrpcMetadata.INTERACTION_SERVICE_STATUS_KEY)
+ assertThat(appInteractionMetadata).isNotNull()
+ return appInteractionMetadata!!.errorStatus
+ }
}
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppVerificationInfoTest.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppVerificationInfoTest.kt
index 20c792f..6a97a1d 100644
--- a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppVerificationInfoTest.kt
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppVerificationInfoTest.kt
@@ -29,7 +29,7 @@
val verificationInfo: AppVerificationInfo =
AppVerificationInfo.Builder()
.setPackageName("packageName")
- .addSignature(listOf(ByteArray(5)))
+ .addSignature(ByteArray(5))
.build()
assertThat(verificationInfo.packageName).isEqualTo("packageName")
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/CapabilityCallbackTest.java b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/CapabilityCallbackTest.java
index 507f38d..cb7155a 100644
--- a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/CapabilityCallbackTest.java
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/CapabilityCallbackTest.java
@@ -70,7 +70,7 @@
CallbackToFutureAdapter.getFuture(
completer -> {
CapabilityCallback cb = new CapabilityCallback(completer);
- cb.onError(ErrorStatusInternal.CANCELLED);
+ cb.onError(ErrorStatusInternal.CANCELED);
return "test future";
});
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeAlarmEntityProvider.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeAlarmEntityProvider.kt
index e0151be..27d4b5a 100644
--- a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeAlarmEntityProvider.kt
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeAlarmEntityProvider.kt
@@ -16,18 +16,18 @@
package androidx.appactions.interaction.service.testing.internal
-import androidx.appactions.builtintypes.experimental.types.Alarm
+import androidx.appactions.builtintypes.types.Alarm
import androidx.appactions.interaction.capabilities.core.entity.EntityLookupCandidate
import androidx.appactions.interaction.capabilities.core.entity.EntityLookupRequest
import androidx.appactions.interaction.capabilities.core.entity.EntityLookupResponse
import androidx.appactions.interaction.capabilities.core.entity.EntityProvider
-import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
+import androidx.appactions.interaction.capabilities.serializers.types.ALARM_TYPE_SPEC
class FakeAlarmEntityProvider(
override val id: String,
private val alarms: List<Alarm> = listOf()
) : EntityProvider<Alarm>(
- TypeConverters.ALARM_TYPE_SPEC
+ ALARM_TYPE_SPEC
) {
override suspend fun lookup(
request: EntityLookupRequest<Alarm>
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeCapability.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeCapability.kt
index 1105d83..29fc252c 100644
--- a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeCapability.kt
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeCapability.kt
@@ -18,6 +18,7 @@
import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
import androidx.appactions.interaction.capabilities.core.Capability
+import androidx.appactions.interaction.capabilities.core.HostProperties
import androidx.appactions.interaction.capabilities.core.ValueListener
import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
@@ -30,10 +31,6 @@
private const val CAPABILITY_NAME = "actions.intent.FAKE_CAPABILITY"
class FakeCapability private constructor() {
- class Properties(
- val fieldOne: Property<StringValue>? = null,
- )
-
class Arguments internal constructor(
val fieldOne: String?,
) {
@@ -75,35 +72,25 @@
builder.build()
}
- private var fieldOne: Property<StringValue>? = null
+ public override fun setExecutionSessionFactory(
+ sessionFactory: (hostProperties: HostProperties?) -> ExecutionSession
+ ) = super.setExecutionSessionFactory(sessionFactory)
- fun setFieldOne(fieldOne: Property<StringValue>) = apply {
- this.fieldOne = fieldOne
- }
-
- override fun build(): Capability {
- super.setProperty(
- mutableMapOf(
- "fieldOne" to (
- fieldOne ?: Property.Builder<StringValue>().build()
- )
- )
- )
- return super.build()
- }
+ fun setFieldOne(fieldOne: Property<StringValue>) = setProperty(
+ "fieldOne",
+ fieldOne,
+ TypeConverters.STRING_VALUE_ENTITY_CONVERTER
+ )
}
companion object {
- @Suppress("UNCHECKED_CAST")
private val ACTION_SPEC = ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
.setArguments(Arguments::class.java, Arguments::Builder)
.setOutput(Output::class.java)
.bindParameter(
"fieldOne",
- { properties -> properties["fieldOne"] as? Property<StringValue> },
Arguments.Builder::setFieldOne,
- TypeConverters.STRING_PARAM_VALUE_CONVERTER,
- TypeConverters.STRING_VALUE_ENTITY_CONVERTER,
+ TypeConverters.STRING_PARAM_VALUE_CONVERTER
)
.build()
}
diff --git a/appcompat/appcompat/src/androidTest/AndroidManifest.xml b/appcompat/appcompat/src/androidTest/AndroidManifest.xml
index fb17a4b..e8780ab 100644
--- a/appcompat/appcompat/src/androidTest/AndroidManifest.xml
+++ b/appcompat/appcompat/src/androidTest/AndroidManifest.xml
@@ -357,7 +357,8 @@
<activity
android:name="androidx.appcompat.widget.TooltipCompatTestActivity" />
- <activity android:name="androidx.appcompat.app.LocalesUpdateActivity"/>
+ <activity android:name="androidx.appcompat.app.LocalesUpdateActivity"
+ android:label="@string/locale_test_title"/>
<activity
android:name="androidx.appcompat.app.LocalesConfigChangesActivity"
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesUpdateTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesUpdateTestCase.kt
index d07329e..bca120b 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesUpdateTestCase.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesUpdateTestCase.kt
@@ -16,9 +16,12 @@
package androidx.appcompat.app
+import android.app.Activity
+import android.content.res.Configuration
import android.os.Build
import android.util.LayoutDirection.RTL
import android.webkit.WebView
+import androidx.appcompat.test.R
import androidx.appcompat.testutils.LocalesActivityTestRule
import androidx.appcompat.testutils.LocalesUtils
import androidx.appcompat.testutils.LocalesUtils.CUSTOM_LOCALE_LIST
@@ -26,11 +29,13 @@
import androidx.appcompat.testutils.LocalesUtils.getRTLLocaleList
import androidx.appcompat.testutils.LocalesUtils.setLocalesAndWait
import androidx.appcompat.testutils.LocalesUtils.setLocalesAndWaitForRecreate
+import androidx.core.os.ConfigurationCompat
import androidx.core.os.LocaleListCompat
import androidx.test.filters.FlakyTest
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
import androidx.testutils.waitForExecution
+import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Before
@@ -55,6 +60,17 @@
expectedLocales = LocalesUpdateActivity.overlayCustomAndSystemLocales(CUSTOM_LOCALE_LIST,
systemLocales)
}
+
+ @After
+ fun teardown() {
+ rule.runOnUiThread {
+ // clean-up
+ AppCompatDelegate.setApplicationLocales(LocaleListCompat.getEmptyLocaleList())
+ // setting auto storage opt-in to false
+ AppCompatDelegate.setIsAutoStoreLocalesOptedIn(false)
+ }
+ }
+
@Test
fun testDialogDoesNotOverrideActivityConfiguration() {
setLocalesAndWaitForRecreate(rule, CUSTOM_LOCALE_LIST)
@@ -133,4 +149,20 @@
// Now assert that the layoutDirection of decorView is RTL
assertEquals(rule.activity.window.decorView.layoutDirection, RTL)
}
-}
+
+ @SdkSuppress(minSdkVersion = 17)
+ @Test
+ fun testTitleRespectPerAppLocale() {
+ // Set activity language as AR
+ setLocalesAndWaitForRecreate(rule, getRTLLocaleList())
+
+ // Verify the title string come from AR resource
+ val testActivity = rule.activity as Activity
+ val newConfig = Configuration(testActivity.resources.configuration)
+ ConfigurationCompat.setLocales(newConfig, getRTLLocaleList())
+ val newContext = testActivity.createConfigurationContext(newConfig)
+ assertEquals(
+ newContext.resources.getString(R.string.locale_test_title),
+ testActivity.title)
+ }
+}
\ No newline at end of file
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatMultiAutoCompleteTextViewTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatMultiAutoCompleteTextViewTest.java
index 86cfcb1..c634b6d 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatMultiAutoCompleteTextViewTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatMultiAutoCompleteTextViewTest.java
@@ -39,6 +39,7 @@
import androidx.test.filters.LargeTest;
import androidx.test.filters.SdkSuppress;
+import org.junit.Ignore;
import org.junit.Test;
/**
@@ -136,6 +137,7 @@
TextViewCompat.getCompoundDrawableTintList(textView));
}
+ @Ignore("b/268534721")
@Test
public void testCompoundDrawablesTintList() {
// Given an ACTV with a white drawableLeftCompat and a ColorStateList drawableTint set
diff --git a/appcompat/appcompat/src/androidTest/res/values-ar/donottranslate-strings.xml b/appcompat/appcompat/src/androidTest/res/values-ar/donottranslate-strings.xml
new file mode 100644
index 0000000..ca02dfe
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/res/values-ar/donottranslate-strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <string name="locale_test_title">AR title</string>
+</resources>
diff --git a/appcompat/appcompat/src/androidTest/res/values/donottranslate-strings.xml b/appcompat/appcompat/src/androidTest/res/values/donottranslate-strings.xml
index 151400a..9b9df7c 100644
--- a/appcompat/appcompat/src/androidTest/res/values/donottranslate-strings.xml
+++ b/appcompat/appcompat/src/androidTest/res/values/donottranslate-strings.xml
@@ -166,4 +166,6 @@
<string name="font_serif">serif</string>
<string name="toolbar_collapse">Toolbar collapse</string>
+
+ <string name="locale_test_title">title</string>
</resources>
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
index 4976f99..6630ad9 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
@@ -550,6 +550,12 @@
// until after the Activity is created
applyApplicationSpecificConfig(false);
+ // The default activity title is based on the label resource defined in the manifest, but it
+ // loads the resource string before we apply the per-app locale into the configuration on
+ // devices running Android 12 or earlier. To fix this, reload the label string after calling
+ // applyApplicationSpecificConfig(), which updates the configuration.
+ overrideTitleWithNewConfiguration();
+
// We lazily fetch the Window for Activities, to allow DayNight to apply in
// attachBaseContext
ensureWindow();
@@ -3009,6 +3015,21 @@
return mActivityHandlesConfigFlags;
}
+ private void overrideTitleWithNewConfiguration() {
+ if (mHost instanceof Activity && Build.VERSION.SDK_INT < 33) {
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ final ActivityInfo info = pm.getActivityInfo(
+ new ComponentName(mContext, mHost.getClass()), 0);
+ if (info.labelRes != 0) {
+ ((Activity) mHost).setTitle(info.labelRes);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.d(TAG, "Exception while getting ActivityInfo", e);
+ }
+ }
+ }
+
/**
* Clears out internal reference when the action mode is destroyed.
*/
diff --git a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Person.java b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Person.java
index bbd50e29..700b734 100644
--- a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Person.java
+++ b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Person.java
@@ -222,11 +222,11 @@
/**
* Returns an external uri for this {@link Person}. Or {@code null} if no {@link Uri} is
* provided. A {@link Uri} can be any of the following:
- *
+ * <ul>
* <li>A {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}.
* <li>A {@code mailto:} schema*
* <li>A {@code tel:} schema*
- *
+ * </ul>
* <p>For mailto: and tel: URI schemes, it is recommended that the path portion
* refers to a valid contact in the Contacts Provider.
*/
@@ -416,11 +416,11 @@
/**
* Sets an external {@link Uri} for this {@link Person}. Or {@code null} if no
* {@link Uri} is provided. A {@link Uri} can be any of the following:
- *
+ * <ul>
* <li>A {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}.
* <li>A {@code mailto:} schema*
* <li>A {@code tel:} schema*
- *
+ * </ul>
* <p>For mailto: and tel: URI schemes, it is recommended that the path
* portion refers to a valid contact in the Contacts Provider.
*/
diff --git a/benchmark/baseline-profile-gradle-plugin/build.gradle b/benchmark/baseline-profile-gradle-plugin/build.gradle
index e4884b6..0fe910f 100644
--- a/benchmark/baseline-profile-gradle-plugin/build.gradle
+++ b/benchmark/baseline-profile-gradle-plugin/build.gradle
@@ -32,10 +32,10 @@
}
dependencies {
+ compileOnly(libs.androidGradlePluginz)
+ compileOnly(libs.kotlinGradlePluginz)
+
implementation(gradleApi())
- implementation(libs.androidGradlePluginz)
- implementation(libs.kotlinGradlePluginz)
- implementation(libs.kotlinStdlib)
implementation(libs.protobuf)
implementation(libs.agpTestingPlatformCoreProto)
@@ -46,6 +46,8 @@
testImplementation(libs.truth)
neededForGradleTestKit(libs.androidGradlePluginz)
+ neededForGradleTestKit(libs.kotlinGradlePluginz)
+ neededForGradleTestKit(libs.kotlinStdlib)
}
SdkResourceGenerator.generateForHostTest(project)
@@ -86,4 +88,7 @@
}
}
+tasks.withType(Test).configureEach { test ->
+ test.maxParallelForks(2)
+}
afterEvaluate { tasks.named("test") { it.dependsOn(tasks.named("publish")) } }
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerExtension.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerExtension.kt
index 00934a5..858ae55 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerExtension.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerExtension.kt
@@ -141,7 +141,7 @@
* }
* ```
*/
- override fun from(project: Project, variantName: String?) = main.from(project, variantName)
+ override fun from(project: Project) = main.from(project)
fun variants(
action: Action<NamedDomainObjectContainer<BaselineProfileVariantConfigurationImpl>>
@@ -160,7 +160,7 @@
BaselineProfileVariantConfiguration {
internal val filters = FilterRules()
- internal val dependencies = mutableListOf<Pair<Project, String?>>()
+ internal val dependencies = mutableListOf<Project>()
/**
* @inheritDoc
@@ -175,8 +175,8 @@
/**
* @inheritDoc
*/
- override fun from(project: Project, variantName: String?) {
- dependencies.add(Pair(project, variantName))
+ override fun from(project: Project) {
+ dependencies.add(project)
}
}
@@ -321,24 +321,7 @@
* }
* ```
*/
- fun from(project: Project) = from(project, null)
-
- /**
- * Allows to specify a target `com.android.test` module that has the `androidx.baselineprofile`
- * plugin, and that can provide a baseline profile for this module. The [variantName] can
- * directly map to a test variant, to fetch a baseline profile for a different variant.
- * For example it's possible to use a `paidRelease` baseline profile for `freeRelease` variant.
- * ```
- * baselineProfile {
- * variants {
- * freeRelease {
- * from(project(":baseline-profile"), "paidRelease")
- * }
- * }
- * }
- * ```
- */
- fun from(project: Project, variantName: String?)
+ fun from(project: Project)
}
class FilterRules {
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
index a57d752..4103bf2 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
@@ -29,6 +29,8 @@
import androidx.baselineprofile.gradle.utils.BUILD_TYPE_BENCHMARK_PREFIX
import androidx.baselineprofile.gradle.utils.CONFIGURATION_NAME_BASELINE_PROFILES
import androidx.baselineprofile.gradle.utils.INTERMEDIATES_BASE_FOLDER
+import androidx.baselineprofile.gradle.utils.KOTLIN_MULTIPLATFORM_PLUGIN_ID
+import androidx.baselineprofile.gradle.utils.KotlinMultiPlatformUtils
import androidx.baselineprofile.gradle.utils.MAX_AGP_VERSION_REQUIRED
import androidx.baselineprofile.gradle.utils.MIN_AGP_VERSION_REQUIRED
import androidx.baselineprofile.gradle.utils.R8Utils
@@ -191,29 +193,13 @@
// Creates the configuration to carry the specific variant artifact
val baselineProfileConfiguration = createConfigurationForVariant(
variant = variant,
- mainConfiguration = mainBaselineProfileConfiguration,
- hasDirectConfiguration = variantDependencies.any { it.second != null }
+ mainConfiguration = mainBaselineProfileConfiguration
)
// Adds the custom dependencies for baseline profiles. Note that dependencies
// for global, build type, flavor and variant specific are all merged.
variantDependencies.forEach {
- val targetProject = it.first
- val variantName = it.second
- val targetProjectDependency = if (variantName != null) {
- val configurationName = camelCase(
- variantName,
- CONFIGURATION_NAME_BASELINE_PROFILES
- )
- project.dependencies.project(
- mutableMapOf(
- "path" to targetProject.path,
- "configuration" to configurationName
- )
- )
- } else {
- project.dependencyFactory.create(targetProject)
- }
+ val targetProjectDependency = project.dependencyFactory.create(it)
baselineProfileConfiguration.dependencies.add(targetProjectDependency)
}
@@ -228,6 +214,16 @@
// for apps.
val mergeIntoMain = variantConfiguration.mergeIntoMain ?: isLibraryModule()
+ // Determines the target name for the Android target in kotlin multiplatform projects.
+ // Note that KotlinMultiPlatformUtils references the kmp extension that exists only if the
+ // multiplatform plugin has been applied.
+ val androidTargetName =
+ if (project.plugins.hasPlugin(KOTLIN_MULTIPLATFORM_PLUGIN_ID)) {
+ KotlinMultiPlatformUtils.androidTargetName(project)
+ } else {
+ ""
+ }
+
// This part changes according to the AGP version of the module. `mergeIntoMain` merges
// the profile of the generated profile for this variant into the main one. This can be
// applied to the `main` configuration or to single variants. On Agp 8.0, since it's not
@@ -237,14 +233,27 @@
// calling `generateReleaseBaselineProfiles`. On Agp 8.1 instead, it works as intended and
// we can merge all the variants with `mergeIntoMain` true, independently from the build
// type.
+ data class TaskAndFolderName(val taskVariantName: String, val folderVariantName: String)
val (mergeAwareVariantName, mergeAwareVariantOutput) = if (mergeIntoMain) {
if (supportsFeature(AgpFeature.TEST_MODULE_SUPPORTS_MULTIPLE_BUILD_TYPES)) {
- listOf("", "main")
+ TaskAndFolderName(
+ taskVariantName = "",
+ folderVariantName = camelCase(androidTargetName, "main")
+ )
} else {
- listOf(variant.buildType ?: "", "main")
+ // Note that the exception here cannot happen because all the variants have a build
+ // type in Android.
+ TaskAndFolderName(
+ taskVariantName = variant.buildType
+ ?: throw IllegalStateException("Found variant without build type."),
+ folderVariantName = camelCase(androidTargetName, "main")
+ )
}
} else {
- listOf(variant.name, variant.name)
+ TaskAndFolderName(
+ taskVariantName = variant.name,
+ folderVariantName = camelCase(androidTargetName, variant.name)
+ )
}
// Creates the task to merge the baseline profile artifacts coming from
@@ -436,16 +445,26 @@
if (supportsFeature(AgpFeature.TEST_MODULE_SUPPORTS_MULTIPLE_BUILD_TYPES)) {
- // Generate a flavor task, such as `generateFreeBaselineProfile`
- if (!mergeIntoMain &&
- !variant.flavorName.isNullOrBlank() &&
- variant.flavorName != variant.name
- ) {
- maybeCreateGenerateTask<Task>(
- project = project,
- variantName = variant.flavorName!!,
- lastTaskProvider = lastTaskProvider
+ // Generate a flavor task for the assembled flavor name and each flavor dimension.
+ // For example for variant `freeRelease` (build type `release`, flavor `free`):
+ // `generateFreeBaselineProfile`.
+ // For example for variant `freeRedRelease` (build type `release`, flavor dimensions
+ // `free` and `red`): `generateFreeBaselineProfile`, `generateRedBaselineProfile` and
+ // `generateFreeRedBaselineProfile`.
+ if (!mergeIntoMain) {
+ listOfNotNull(
+ variant.flavorName,
+ *variant.productFlavors.map { it.second }.toTypedArray()
)
+ .filter { it != variant.name && it.isNotBlank() }
+ .toSet()
+ .forEach {
+ maybeCreateGenerateTask<Task>(
+ project = project,
+ variantName = it,
+ lastTaskProvider = lastTaskProvider
+ )
+ }
}
// Generate the main global tasks `generateBaselineProfile
@@ -474,69 +493,13 @@
private fun createConfigurationForVariant(
variant: Variant,
- mainConfiguration: Configuration?,
- hasDirectConfiguration: Boolean
- ): Configuration {
-
- val variantName = variant.name
- val productFlavors = variant.productFlavors
- val flavorName = variant.flavorName ?: ""
- val buildTypeName = variant.buildType ?: ""
-
- val buildTypeConfiguration =
- if (buildTypeName.isNotBlank() && buildTypeName != variantName) {
- configurationManager.maybeCreate(
- nameParts = listOf(buildTypeName, CONFIGURATION_NAME_BASELINE_PROFILES),
- canBeResolved = true,
- canBeConsumed = false,
- buildType = null,
- productFlavors = null,
- extendFromConfigurations = listOfNotNull(mainConfiguration)
- )
- } else null
-
- val flavorConfiguration =
- if (flavorName.isNotBlank() && flavorName != variantName) {
- configurationManager.maybeCreate(
- nameParts = listOf(flavorName, CONFIGURATION_NAME_BASELINE_PROFILES),
- canBeResolved = true,
- canBeConsumed = false,
- buildType = null,
- productFlavors = null,
- extendFromConfigurations = listOfNotNull(mainConfiguration)
- )
- } else null
-
- // When there is direct configuration for the dependency the matching through attributes
- // is bypassed, because most likely the user meant to match a configuration that does not
- // have the same tags (for example to a different flavor or build type).
-
- return if (hasDirectConfiguration) {
- configurationManager.maybeCreate(
- nameParts = listOf(variantName, CONFIGURATION_NAME_BASELINE_PROFILES),
- canBeResolved = true,
- canBeConsumed = false,
- extendFromConfigurations = listOfNotNull(
- mainConfiguration,
- flavorConfiguration,
- buildTypeConfiguration
- ),
- buildType = null,
- productFlavors = null
- )
- } else {
- configurationManager.maybeCreate(
- nameParts = listOf(variantName, CONFIGURATION_NAME_BASELINE_PROFILES),
- canBeResolved = true,
- canBeConsumed = false,
- extendFromConfigurations = listOfNotNull(
- mainConfiguration,
- flavorConfiguration,
- buildTypeConfiguration
- ),
- buildType = buildTypeName,
- productFlavors = productFlavors
- )
- }
- }
+ mainConfiguration: Configuration
+ ) = configurationManager.maybeCreate(
+ nameParts = listOf(variant.name, CONFIGURATION_NAME_BASELINE_PROFILES),
+ canBeResolved = true,
+ canBeConsumed = false,
+ extendFromConfigurations = listOf(mainConfiguration),
+ buildType = variant.buildType ?: "",
+ productFlavors = variant.productFlavors
+ )
}
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/PerVariantConsumerExtensionManager.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/PerVariantConsumerExtensionManager.kt
index eb7b035..73434be 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/PerVariantConsumerExtensionManager.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/PerVariantConsumerExtensionManager.kt
@@ -49,7 +49,7 @@
val filterRules: List<Pair<RuleType, String>>
get() = getMergedListForVariant(variant) { filters.rules }
- val dependencies: List<Pair<Project, String?>>
+ val dependencies: List<Project>
get() = getMergedListForVariant(variant) { dependencies }
val baselineProfileRulesRewrite: Boolean?
@@ -74,7 +74,13 @@
variant: Variant,
getter: BaselineProfileVariantConfigurationImpl.() -> List<T>
): List<T> {
- return listOfNotNull("main", variant.flavorName, variant.buildType, variant.name)
+ return listOfNotNull(
+ "main",
+ variant.flavorName,
+ *variant.productFlavors.map { it.second }.toTypedArray(),
+ variant.buildType,
+ variant.name
+ )
.mapNotNull { ext.variants.findByName(it) }
.map { getter.invoke(it) }
.flatten()
@@ -91,6 +97,7 @@
val definedProperties = listOfNotNull(
variant.name,
+ *variant.productFlavors.map { it.second }.toTypedArray(),
variant.flavorName,
variant.buildType,
"main"
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 cb5582f..c5b75e2 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
@@ -151,10 +151,10 @@
throw GradleException(
"""
The baseline profile consumer plugin is applied to this module but no dependency
- has been set. Please review the configuration of build.gradle for the module
- `${project.path}` making sure that a `baselineProfile` dependency exists and
- points to a valid `com.android.test` module that has the `androidx.baselineprofile`
- or `androidx.baselineprofile.producer` plugin applied.
+ has been set. Please review the configuration of build.gradle for this module
+ making sure that a `baselineProfile` dependency exists and points to a valid
+ `com.android.test` module that has the `androidx.baselineprofile` or
+ `androidx.baselineprofile.producer` plugin applied.
""".trimIndent()
)
}
@@ -311,7 +311,13 @@
}
private fun Iterable<File>.readLines(filterBlock: (File) -> (Boolean)): List<String> = this
- .flatMap { if (it.isFile) listOf(it) else listOf(*it.listFiles()!!) }
+ .flatMap {
+ if (it.isFile) {
+ listOf(it)
+ } else {
+ listOf(*(it.listFiles() ?: arrayOf()))
+ }
+ }
.filter(filterBlock)
.flatMap { it.readLines() }
}
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPlugin.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPlugin.kt
index e3acffd..408c9fc 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPlugin.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPlugin.kt
@@ -62,6 +62,9 @@
private val baselineProfileExtension = BaselineProfileProducerExtension.register(project)
private val configurationManager = ConfigurationManager(project)
+ private val shouldSkipGeneration by lazy {
+ project.properties.containsKey(PROP_SKIP_GENERATION)
+ }
// This maps all the extended build types to the original ones. Note that release does not
// exist by default so we need to create nonMinifiedRelease and map it manually to `release`.
@@ -183,6 +186,14 @@
configureBlock = configureBlock
)
}
+
+ if (shouldSkipGeneration) {
+ logger.info(
+ """
+ Property `$PROP_SKIP_GENERATION` set. Baseline profile generation will be skipped.
+ """.trimIndent()
+ )
+ }
}
override fun onTestBeforeVariants(variantBuilder: TestVariantBuilder) {
@@ -276,13 +287,17 @@
}
task
- }.onEach { it.setEnableEmulatorDisplay(baselineProfileExtension.enableEmulatorDisplay) }
+ }.onEach {
+ it.setEnableEmulatorDisplay(baselineProfileExtension.enableEmulatorDisplay)
+ if (shouldSkipGeneration) it.setTaskEnabled(false)
+ }
// The collect task collects the baseline profile files from the ui test results
val collectTaskProvider = CollectBaselineProfileTask.registerForVariant(
project = project,
variant = variant,
- testTaskDependencies = testTasks
+ testTaskDependencies = testTasks,
+ shouldSkipGeneration = shouldSkipGeneration
)
// The artifacts are added to the configuration that exposes the generated baseline profile
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerProperties.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerProperties.kt
new file mode 100644
index 0000000..1efc5e8
--- /dev/null
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerProperties.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.
+ */
+
+package androidx.baselineprofile.gradle.producer
+
+/**
+ * This property determines whether the test task should actually run to generate the baseline
+ * profile artifacts. When this property is set, the test tasks will be disabled and baseline
+ * profile won't be generated. This property is useful for Github CI, as default ubuntu runners
+ * cannot run android emulators.
+ *
+ * An example of how to configure baseline profile generation on Github CI is in the project
+ * NowInAndroid:
+ * https://github.com/android/nowinandroid/blob/main/.github/workflows/AndroidCIWithGmd.yaml#L42
+ * It's necessary to set `runs-on: macos-12` and properties -Dorg.gradle.workers.max=1
+ * -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect.
+ */
+internal const val PROP_SKIP_GENERATION = "androidx.baselineprofile.skipgeneration"
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/tasks/CollectBaselineProfileTask.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/tasks/CollectBaselineProfileTask.kt
index 20b47cd..aff2944 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/tasks/CollectBaselineProfileTask.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/tasks/CollectBaselineProfileTask.kt
@@ -54,7 +54,8 @@
internal fun registerForVariant(
project: Project,
variant: TestVariant,
- testTaskDependencies: List<InstrumentationTestTaskWrapper>
+ testTaskDependencies: List<InstrumentationTestTaskWrapper>,
+ shouldSkipGeneration: Boolean
): TaskProvider<CollectBaselineProfileTask> {
val flavorName = variant.flavorName
@@ -87,6 +88,9 @@
.properties
.filterKeys { k -> k.startsWith(PROP_KEY_PREFIX_INSTRUMENTATION_RUNNER_ARG) }
)
+
+ // Disables the task if requested
+ if (shouldSkipGeneration) it.enabled = false
}
}
}
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/tasks/InstrumentationTestTaskWrapper.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/tasks/InstrumentationTestTaskWrapper.kt
index e4f9650..cf7dabc 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/tasks/InstrumentationTestTaskWrapper.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/producer/tasks/InstrumentationTestTaskWrapper.kt
@@ -59,4 +59,8 @@
}
}
}
+
+ fun setTaskEnabled(enabled: Boolean) {
+ testTask.configure { t -> t.enabled = enabled }
+ }
}
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Constants.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Constants.kt
index 9323a0f..1afa832 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Constants.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Constants.kt
@@ -47,3 +47,6 @@
// Other constants
internal const val RELEASE = "release"
+
+// Kotlin Multiplatform Plugin ID
+internal const val KOTLIN_MULTIPLATFORM_PLUGIN_ID = "org.jetbrains.kotlin.multiplatform"
\ No newline at end of file
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/KotlinMultiPlatformUtils.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/KotlinMultiPlatformUtils.kt
new file mode 100644
index 0000000..f80edf0
--- /dev/null
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/KotlinMultiPlatformUtils.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.baselineprofile.gradle.utils
+
+import org.gradle.api.Project
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
+
+/**
+ * Utility methods for kotlin multiplatform projects. Note that this class references symbols
+ * existing only if the KMP plugin has been applied.
+ */
+internal object KotlinMultiPlatformUtils {
+
+ fun androidTargetName(project: Project) = project
+ .extensions
+ .findByType(KotlinMultiplatformExtension::class.java)
+ ?.targets
+ ?.firstOrNull { it.platformType == KotlinPlatformType.androidJvm }
+ ?.name
+ ?: ""
+}
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 985e914..a6d70de 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
@@ -28,6 +28,7 @@
import androidx.baselineprofile.gradle.utils.build
import androidx.baselineprofile.gradle.utils.buildAndAssertThatOutput
import androidx.baselineprofile.gradle.utils.buildAndFailAndAssertThatOutput
+import androidx.baselineprofile.gradle.utils.camelCase
import androidx.baselineprofile.gradle.utils.require
import androidx.baselineprofile.gradle.utils.requireInOrder
import com.google.common.truth.Truth.assertThat
@@ -41,7 +42,7 @@
private const val EXPECTED_PROFILE_FOLDER = "generated/baselineProfiles"
@RunWith(Parameterized::class)
-class BaselineProfileConsumerPluginTest(agpVersion: String?) {
+class BaselineProfileConsumerPluginTest(private val agpVersion: String?) {
companion object {
@Parameterized.Parameters(name = "agpVersion={0}")
@@ -242,48 +243,112 @@
}
@Test
- fun testSrcSetAreAddedToVariants() {
- projectSetup.producer.setupWithFreeAndPaidFlavors(
- freeReleaseProfileLines = listOf(Fixtures.CLASS_1_METHOD_1, Fixtures.CLASS_1),
- paidReleaseProfileLines = listOf(Fixtures.CLASS_2_METHOD_1, Fixtures.CLASS_2)
- )
+ fun testSrcSetAreAddedToVariantsForApplications() {
+ projectSetup.producer.setupWithFreeAndPaidFlavors()
projectSetup.consumer.setup(
androidPlugin = ANDROID_APPLICATION_PLUGIN,
flavors = true,
- dependencyOnProducerProject = true,
additionalGradleCodeBlock = """
androidComponents {
onVariants(selector()) { variant ->
- tasks.register(variant.name + "Print", PrintTask) { t ->
- t.text.set(variant.sources.baselineProfiles?.all?.get().toString())
+ tasks.register(variant.name + "Sources", DisplaySourceSets) { t ->
+ t.srcs.set(variant.sources.baselineProfiles.all)
}
}
}
""".trimIndent()
)
- arrayOf("freeRelease", "paidRelease")
+ data class VariantExpectedSrcSets(val variantName: String, val expectedDirs: List<String>)
+
+ arrayOf(
+ VariantExpectedSrcSets(
+ variantName = "freeRelease",
+ expectedDirs = listOf(
+ "src/main/baselineProfiles",
+ "src/free/baselineProfiles",
+ "src/release/baselineProfiles",
+ "src/freeRelease/generated/baselineProfiles",
+
+ // In AGP 8.0 there seems to be a bug where the default baselineProfiles folder
+ // is instead `src/freeRelease/resources`. This is fixed in AGP 8.1.
+ *(if (agpVersion == TEST_AGP_VERSION_8_1_0) {
+ listOf("src/freeRelease/baselineProfiles")
+ } else {
+ listOf()
+ }).toTypedArray()
+ )
+ ),
+ VariantExpectedSrcSets(
+ variantName = "paidRelease",
+ expectedDirs = listOf(
+ "src/main/baselineProfiles",
+ "src/paid/baselineProfiles",
+ "src/release/baselineProfiles",
+ "src/paidRelease/generated/baselineProfiles",
+
+ // In AGP 8.0 there seems to be a bug where the default baselineProfiles folder
+ // is instead `src/paidRelease/resources`. This is fixed in AGP 8.1.
+ *(if (agpVersion == TEST_AGP_VERSION_8_1_0) {
+ listOf("src/paidRelease/baselineProfiles")
+ } else {
+ listOf()
+ }).toTypedArray()
+ )
+ )
+ )
.forEach {
- // Expected src set location. Note that src sets are not added if the folder does
- // not exist so we need to create it.
- val expected =
- File(
- projectSetup.consumer.rootDir,
- "src/$it/$EXPECTED_PROFILE_FOLDER"
- )
- .apply {
- mkdirs()
- deleteOnExit()
- }
+ val expected = it.expectedDirs
+ .map { dir -> File(projectSetup.consumer.rootDir, dir) }
+ .onEach { f ->
+ // Expected src set location. Note that src sets are not added if the folder does
+ // not exist so we need to create it.
+ f.mkdirs()
+ f.deleteOnExit()
+ }
- gradleRunner.buildAndAssertThatOutput("${it}Print") {
- contains(expected.absolutePath)
+ gradleRunner.buildAndAssertThatOutput("${it.variantName}Sources") {
+ expected.forEach { e -> contains(e.absolutePath) }
}
}
}
@Test
+ fun testSrcSetAreAddedToVariantsForLibraries() {
+ projectSetup.producer.setupWithoutFlavors()
+ projectSetup.consumer.setup(
+ androidPlugin = ANDROID_LIBRARY_PLUGIN,
+ additionalGradleCodeBlock = """
+ androidComponents {
+ onVariants(selector()) { variant ->
+ tasks.register(variant.name + "Sources", DisplaySourceSets) { t ->
+ t.srcs.set(variant.sources.baselineProfiles.all)
+ }
+ }
+ }
+ """.trimIndent()
+ )
+
+ val expected = listOf(
+ "src/main/baselineProfiles",
+ "src/main/generated/baselineProfiles",
+ "src/release/baselineProfiles",
+ )
+ .map { dir -> File(projectSetup.consumer.rootDir, dir) }
+ .onEach { f ->
+ // Expected src set location. Note that src sets are not added if the folder does
+ // not exist so we need to create it.
+ f.mkdirs()
+ f.deleteOnExit()
+ }
+
+ gradleRunner.buildAndAssertThatOutput("releaseSources") {
+ expected.forEach { e -> contains(e.absolutePath) }
+ }
+ }
+
+ @Test
fun testWhenPluginIsAppliedAndNoDependencyIsSetShouldFailWithErrorMsg() {
projectSetup.consumer.setup(
androidPlugin = ANDROID_APPLICATION_PLUGIN,
@@ -794,49 +859,6 @@
}
@Test
- fun testVariantDependenciesWithVariantsAndDirectConfiguration() {
- projectSetup.producer.setupWithFreeAndPaidFlavors(
- freeReleaseProfileLines = listOf(Fixtures.CLASS_1_METHOD_1, Fixtures.CLASS_1),
- paidReleaseProfileLines = listOf(Fixtures.CLASS_2_METHOD_1, Fixtures.CLASS_2),
- )
-
- // In this setup no dependency is being added through the dependency block.
- // Instead dependencies are being added through per-variant configuration block.
- projectSetup.consumer.setup(
- androidPlugin = ANDROID_APPLICATION_PLUGIN,
- flavors = true,
- dependencyOnProducerProject = false,
- baselineProfileBlock = """
- variants {
- freeRelease {
- from(project(":${projectSetup.producer.name}"))
- }
- paidRelease {
- from(project(":${projectSetup.producer.name}"), "freeRelease")
- }
- }
-
- """.trimIndent()
- )
- gradleRunner
- .withArguments("generateReleaseBaselineProfile", "--stacktrace")
- .build()
-
- assertThat(readBaselineProfileFileContent("freeRelease"))
- .containsExactly(
- Fixtures.CLASS_1,
- Fixtures.CLASS_1_METHOD_1,
- )
-
- // This output should be the same of free release
- assertThat(readBaselineProfileFileContent("paidRelease"))
- .containsExactly(
- Fixtures.CLASS_1,
- Fixtures.CLASS_1_METHOD_1,
- )
- }
-
- @Test
fun testPartialResults() {
projectSetup.consumer.setup(
androidPlugin = ANDROID_APPLICATION_PLUGIN
@@ -978,6 +1000,135 @@
assertThat(notFound).isEmpty()
}
}
+
+ @Test
+ fun testMultidimensionalFlavorsAndMatchingFallbacks() {
+ projectSetup.consumer.setupWithBlocks(
+ androidPlugin = ANDROID_APPLICATION_PLUGIN,
+ flavorsBlock = """
+ flavorDimensions = ["tier", "color"]
+ free { dimension "tier" }
+ red { dimension "color" }
+ paid {
+ dimension "tier"
+ matchingFallbacks += "free"
+ }
+ blue {
+ dimension "color"
+ matchingFallbacks += "red"
+ }
+ """.trimIndent(),
+ buildTypesBlock = "",
+ dependencyOnProducerProject = false,
+ baselineProfileBlock = """
+ variants {
+ free { from(project(":${projectSetup.producer.name}")) }
+ red { from(project(":${projectSetup.producer.name}")) }
+ paid { from(project(":${projectSetup.producer.name}")) }
+ // blue is already covered by the intersection of the other dimensions so no
+ // need to specify it.
+ }
+
+ """.trimIndent()
+ )
+ projectSetup.producer.setup(
+ variantProfiles = listOf(
+ VariantProfile(
+ flavorDimensions = mapOf(
+ "tier" to "free",
+ "color" to "red",
+ ),
+ buildType = "release",
+ profileFileLines = mapOf(
+ "some-test-output" to listOf(
+ Fixtures.CLASS_1_METHOD_1,
+ Fixtures.CLASS_1
+ )
+ ),
+ startupFileLines = mapOf(
+ "some-startup-test-output" to listOf(
+ Fixtures.CLASS_1_METHOD_1,
+ Fixtures.CLASS_1
+ )
+ ),
+ )
+ )
+ )
+
+ arrayOf(
+ "freeRedRelease",
+ "freeBlueRelease",
+ "paidRedRelease",
+ "paidBlueRelease"
+ ).forEach { variantName ->
+ gradleRunner.build(camelCase("generate", variantName, "baselineProfile")) {
+ assertThat(readBaselineProfileFileContent(variantName))
+ .containsExactly(
+ Fixtures.CLASS_1_METHOD_1,
+ Fixtures.CLASS_1
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testSkipGeneration() {
+ projectSetup.consumer.setup(ANDROID_APPLICATION_PLUGIN)
+ projectSetup.producer.setupWithoutFlavors(
+ releaseProfileLines = listOf(
+ Fixtures.CLASS_1_METHOD_1,
+ Fixtures.CLASS_1
+ )
+ )
+
+ gradleRunner.build(
+ "generateBaselineProfile",
+ "-Pandroidx.baselineprofile.skipgeneration"
+ ) {
+ assertThat(baselineProfileFile("release").exists()).isFalse()
+ }
+ }
+
+ @Test
+ fun testSkipGenerationWithPreviousResults() {
+ projectSetup.consumer.setup(ANDROID_APPLICATION_PLUGIN)
+ projectSetup.producer.setupWithoutFlavors(
+ releaseProfileLines = listOf(
+ Fixtures.CLASS_1_METHOD_1,
+ Fixtures.CLASS_1
+ )
+ )
+
+ gradleRunner.build("generateBaselineProfile") {
+ assertThat(readBaselineProfileFileContent("release"))
+ .containsExactly(
+ Fixtures.CLASS_1_METHOD_1,
+ Fixtures.CLASS_1
+ )
+ }
+
+ projectSetup.producer.setupWithoutFlavors(
+ releaseProfileLines = listOf(
+ Fixtures.CLASS_2_METHOD_1,
+ Fixtures.CLASS_2
+ )
+ )
+
+ gradleRunner.build(
+ "generateBaselineProfile",
+ "-Pandroidx.baselineprofile.skipgeneration"
+ ) {
+
+ // Note that the baseline profile should still contain the previous profile rules
+ // and not the updated ones, as running with `skipgeneration` will disable the
+ // generation tasks.
+ assertThat(readBaselineProfileFileContent("release"))
+ .containsExactly(
+ Fixtures.CLASS_1_METHOD_1,
+ Fixtures.CLASS_1
+ )
+ }
+ }
}
@RunWith(JUnit4::class)
@@ -1358,3 +1509,108 @@
)
}
}
+
+@RunWith(Parameterized::class)
+class BaselineProfileConsumerPluginTestWithKmp(agpVersion: String?) {
+
+ companion object {
+ @Parameterized.Parameters(name = "agpVersion={0}")
+ @JvmStatic
+ fun parameters() = TEST_AGP_VERSION_ALL
+ }
+
+ @get:Rule
+ val projectSetup = BaselineProfileProjectSetupRule(
+ forceAgpVersion = agpVersion,
+ addKotlinGradlePluginToClasspath = true
+ )
+
+ private val gradleRunner by lazy { projectSetup.consumer.gradleRunner }
+
+ @Test
+ fun testSrcSetAreAddedToVariantsForApplicationsWithKmp() {
+ projectSetup.producer.setupWithoutFlavors(releaseProfileLines = listOf())
+ projectSetup.consumer.setupWithBlocks(
+ androidPlugin = ANDROID_APPLICATION_PLUGIN,
+ otherPluginsBlock = """
+ id("org.jetbrains.kotlin.multiplatform")
+ """.trimIndent(),
+ additionalGradleCodeBlock = """
+ kotlin {
+ jvm { }
+ android { }
+ sourceSets {
+ androidMain { }
+ }
+ }
+
+ androidComponents {
+ onVariants(selector()) { variant ->
+ tasks.register(variant.name + "Sources", DisplaySourceSets) { t ->
+ t.srcs.set(variant.sources.baselineProfiles.all)
+ }
+ }
+ }
+ """.trimIndent()
+ )
+
+ val expected = listOf(
+ "src/main/baselineProfiles",
+ "src/release/baselineProfiles",
+ "src/androidRelease/generated/baselineProfiles",
+ )
+ .map { dir -> File(projectSetup.consumer.rootDir, dir) }
+ .onEach { f ->
+ // Expected src set location. Note that src sets are not added if the folder does
+ // not exist so we need to create it.
+ f.mkdirs()
+ f.deleteOnExit()
+ }
+
+ gradleRunner.buildAndAssertThatOutput("releaseSources") {
+ expected.forEach { e -> contains(e.absolutePath) }
+ }
+ }
+
+ @Test
+ fun testSrcSetAreAddedToVariantsForLibrariesWithKmp() {
+ projectSetup.producer.setupWithoutFlavors(releaseProfileLines = listOf())
+ projectSetup.consumer.setupWithBlocks(
+ androidPlugin = ANDROID_LIBRARY_PLUGIN,
+ otherPluginsBlock = """
+ id("org.jetbrains.kotlin.multiplatform")
+ """.trimIndent(),
+ additionalGradleCodeBlock = """
+ kotlin {
+ jvm { }
+ android("androidTarget") { }
+ }
+
+ androidComponents {
+ onVariants(selector()) { variant ->
+ tasks.register(variant.name + "Sources", DisplaySourceSets) { t ->
+ t.srcs.set(variant.sources.baselineProfiles.all)
+ }
+ }
+ }
+ """.trimIndent()
+ )
+
+ val expected = listOf(
+ "src/main/baselineProfiles",
+ "src/release/baselineProfiles",
+ "src/androidTargetMain/generated/baselineProfiles",
+ )
+ .map { dir -> File(projectSetup.consumer.rootDir, dir) }
+ .onEach { f ->
+ // Expected src set location. Note that src sets are not added if the folder does
+ // not exist so we need to create it.
+ f.mkdirs()
+ f.deleteOnExit()
+ }
+
+ gradleRunner.buildAndAssertThatOutput("releaseSources") {
+ expected.forEach { e -> contains(e.absolutePath) }
+ }
+ }
+}
diff --git a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPluginTest.kt b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPluginTest.kt
index e3abee6..c411a3d 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPluginTest.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPluginTest.kt
@@ -161,4 +161,43 @@
assertThat(notFound).isEmpty()
}
}
+
+ @Test
+ fun skipGenerationPropertyShouldDisableTestTasks() {
+ projectSetup.appTarget.setup()
+ projectSetup.producer.setup(
+ variantProfiles = listOf(emptyReleaseVariantProfile),
+ targetProject = projectSetup.appTarget,
+ managedDevices = listOf("somePixelDevice"),
+ baselineProfileBlock = """
+ managedDevices = ["somePixelDevice"]
+ """.trimIndent(),
+ additionalGradleCodeBlock = """
+ afterEvaluate {
+ for (String taskName : [
+ "somePixelDeviceNonMinifiedReleaseAndroidTest",
+ "collectNonMinifiedReleaseBaselineProfile"]) {
+ def task = tasks.getByName(taskName)
+ println(taskName + "=" + task.enabled)
+ }
+ }
+ """.trimIndent()
+ )
+
+ // Execute any task and check the expected output.
+ // Note that executing `somePixelDeviceSetup` will fail for `LicenseNotAcceptedException`.
+ projectSetup
+ .producer
+ .gradleRunner
+ .build(
+ "tasks",
+ "-Pandroidx.baselineprofile.skipgeneration"
+ ) {
+ val notFound = it.lines().require(
+ "somePixelDeviceNonMinifiedReleaseAndroidTest=false",
+ "collectNonMinifiedReleaseBaselineProfile=false"
+ )
+ assertThat(notFound).isEmpty()
+ }
+ }
}
diff --git a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/BaselineProfileProjectSetupRule.kt b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/BaselineProfileProjectSetupRule.kt
index c4385c0..2994b57 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/BaselineProfileProjectSetupRule.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/BaselineProfileProjectSetupRule.kt
@@ -38,7 +38,8 @@
internal const val ANDROID_TEST_PLUGIN = "com.android.test"
class BaselineProfileProjectSetupRule(
- private val forceAgpVersion: String? = null
+ private val forceAgpVersion: String? = null,
+ private val addKotlinGradlePluginToClasspath: Boolean = false
) : ExternalResource() {
/**
@@ -146,6 +147,15 @@
("com.android.tools.build:gradle") { version { strictly "$forceAgpVersion" } }
""".trimIndent()
}
+
+ val kotlinGradlePluginDependency = if (addKotlinGradlePluginToClasspath) {
+ """
+ "org.jetbrains.kotlin:kotlin-gradle-plugin:${appTargetSetupRule.props.kotlinVersion}"
+ """.trimIndent()
+ } else {
+ null
+ }
+
rootFolder.newFile("build.gradle").writeText(
"""
buildscript {
@@ -153,7 +163,12 @@
dependencies {
// Specifies agp dependency
- classpath $agpDependency
+ ${
+ listOfNotNull(
+ agpDependency,
+ kotlinGradlePluginDependency
+ ).joinToString("\n") { "classpath $it" }
+ }
// Specifies plugin dependency
classpath "androidx.baselineprofile.consumer:androidx.baselineprofile.consumer.gradle.plugin:+"
@@ -186,12 +201,29 @@
}
data class VariantProfile(
- val flavor: String?,
- val buildType: String = "release",
- val profileFileLines: Map<String, List<String>> = mapOf(),
- val startupFileLines: Map<String, List<String>> = mapOf()
+ val flavorDimensions: Map<String, String>,
+ val buildType: String,
+ val profileFileLines: Map<String, List<String>>,
+ val startupFileLines: Map<String, List<String>>
) {
- val nonMinifiedVariant = "${flavor ?: ""}NonMinified${buildType.capitalized()}"
+
+ val nonMinifiedVariant = camelCase(
+ *flavorDimensions.map { it.value }.toTypedArray(),
+ "nonMinified",
+ buildType
+ )
+
+ constructor(
+ flavor: String?,
+ buildType: String = "release",
+ profileFileLines: Map<String, List<String>> = mapOf(),
+ startupFileLines: Map<String, List<String>> = mapOf()
+ ) : this(
+ flavorDimensions = if (flavor != null) mapOf("version" to flavor) else mapOf(),
+ buildType = buildType,
+ profileFileLines = profileFileLines,
+ startupFileLines = startupFileLines
+ )
}
interface Module {
@@ -302,7 +334,7 @@
}
fun setupWithoutFlavors(
- releaseProfileLines: List<String>,
+ releaseProfileLines: List<String> = listOf(),
releaseStartupProfileLines: List<String> = listOf(),
) {
setup(
@@ -362,14 +394,21 @@
}
""".trimIndent()
+ val flavors = variantProfiles.flatMap { it.flavorDimensions.toList() }
+ val flavorDimensionNames = flavors
+ .map { it.first }
+ .toSet()
+ .joinToString { """ "$it"""" }
+ val flavorBlocks = flavors
+ .groupBy { it.second }
+ .toList()
+ .map { it.second }
+ .flatten()
+ .joinToString("\n") { """ ${it.second} { dimension "${it.first}" } """ }
val flavorsBlock = """
productFlavors {
- flavorDimensions = ["version"]
- ${
- variantProfiles
- .filter { !it.flavor.isNullOrBlank() }
- .joinToString("\n") { " ${it.flavor} { dimension \"version\" } " }
- }
+ flavorDimensions = [$flavorDimensionNames]
+ $flavorBlocks
}
""".trimIndent()
@@ -511,23 +550,33 @@
addAppTargetPlugin: Boolean = androidPlugin == ANDROID_APPLICATION_PLUGIN,
baselineProfileBlock: String = "",
additionalGradleCodeBlock: String = "",
- ) {
- val flavorsBlock = """
- productFlavors {
+ ) = setupWithBlocks(
+ androidPlugin = androidPlugin,
+ otherPluginsBlock = "",
+ flavorsBlock = if (flavors) """
flavorDimensions = ["version"]
free { dimension "version" }
paid { dimension "version" }
- }
-
- """.trimIndent()
-
- val buildTypeAnotherReleaseBlock = """
- buildTypes {
+ """.trimIndent() else "",
+ dependencyOnProducerProject = dependencyOnProducerProject,
+ buildTypesBlock = if (buildTypeAnotherRelease) """
anotherRelease { initWith(release) }
- }
+ """.trimIndent() else "",
+ addAppTargetPlugin = addAppTargetPlugin,
+ baselineProfileBlock = baselineProfileBlock,
+ additionalGradleCodeBlock = additionalGradleCodeBlock
+ )
- """.trimIndent()
-
+ fun setupWithBlocks(
+ androidPlugin: String,
+ otherPluginsBlock: String = "",
+ flavorsBlock: String = "",
+ buildTypesBlock: String = "",
+ dependencyOnProducerProject: Boolean = true,
+ addAppTargetPlugin: Boolean = androidPlugin == ANDROID_APPLICATION_PLUGIN,
+ baselineProfileBlock: String = "",
+ additionalGradleCodeBlock: String = "",
+ ) {
val dependencyOnProducerProjectBlock = """
dependencies {
baselineProfile(project(":$producerName"))
@@ -541,11 +590,24 @@
id("$androidPlugin")
id("androidx.baselineprofile.consumer")
${if (addAppTargetPlugin) "id(\"androidx.baselineprofile.apptarget\")" else ""}
+ $otherPluginsBlock
}
android {
namespace 'com.example.namespace'
- ${if (flavors) flavorsBlock else ""}
- ${if (buildTypeAnotherRelease) buildTypeAnotherReleaseBlock else ""}
+ ${
+ """
+ productFlavors {
+ $flavorsBlock
+ }
+ """.trimIndent()
+ }
+ ${
+ """
+ buildTypes {
+ $buildTypesBlock
+ }
+ """.trimIndent()
+ }
}
${if (dependencyOnProducerProject) dependencyOnProducerProjectBlock else ""}
diff --git a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/TestUtils.kt b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/TestUtils.kt
index 50c69a9..4e1cfb0 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/TestUtils.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/TestUtils.kt
@@ -18,9 +18,17 @@
import com.google.common.truth.StringSubject
import com.google.common.truth.Truth.assertThat
+import org.gradle.configurationcache.extensions.capitalized
import org.gradle.testkit.runner.GradleRunner
internal val GRADLE_CODE_PRINT_TASK = """
+ abstract class DisplaySourceSets extends DefaultTask {
+ @Input abstract ListProperty<Directory> getSrcs()
+ @TaskAction void exec() {
+ srcs.get().forEach { directory -> println(directory) }
+ }
+ }
+
abstract class PrintTask extends DefaultTask {
@Input abstract Property<String> getText()
@TaskAction void exec() { println(getText().get()) }
@@ -36,21 +44,17 @@
""".trimIndent()
-internal fun GradleRunner.build(vararg arguments: String, block: (String) -> (Unit)) {
- this
- .withArguments(*arguments, "--stacktrace")
- .build()
- .output
- .let(block)
-}
+internal fun GradleRunner.build(vararg arguments: String, block: (String) -> (Unit)) = this
+ .withArguments(*arguments, "--stacktrace")
+ .build()
+ .output
+ .also(block)
-internal fun GradleRunner.buildAndFail(vararg arguments: String, block: (String) -> (Unit)) {
- this
- .withArguments(*arguments, "--stacktrace")
- .buildAndFail()
- .output
- .let(block)
-}
+internal fun GradleRunner.buildAndFail(vararg arguments: String, block: (String) -> (Unit)) = this
+ .withArguments(*arguments, "--stacktrace")
+ .buildAndFail()
+ .output
+ .also(block)
internal fun GradleRunner.buildAndAssertThatOutput(
vararg arguments: String,
@@ -95,3 +99,14 @@
}
return remaining
}
+
+fun camelCase(vararg strings: String): String {
+ if (strings.isEmpty()) return ""
+ return StringBuilder().apply {
+ var shouldCapitalize = false
+ for (str in strings.filter { it.isNotBlank() }) {
+ append(if (shouldCapitalize) str.capitalized() else str)
+ shouldCapitalize = true
+ }
+ }.toString()
+}
diff --git a/benchmark/benchmark-common/build.gradle b/benchmark/benchmark-common/build.gradle
index b66a11b..3c5a408 100644
--- a/benchmark/benchmark-common/build.gradle
+++ b/benchmark/benchmark-common/build.gradle
@@ -84,10 +84,7 @@
// https://github.com/square/wire/issues/1947
// Remove when we upgrade to fixed wire library
afterEvaluate {
- tasks.named("compileReleaseKotlin").configure {
- it.dependsOn("generateDebugProtos")
- }
- tasks.named("compileDebugKotlin").configure {
- it.dependsOn("generateReleaseProtos")
- }
+ tasks.named("compileReleaseKotlin").configure {it.dependsOn("generateDebugProtos")}
+ tasks.named("compileDebugKotlin").configure {it.dependsOn("generateReleaseProtos")}
+ tasks.named("generateKmpDocs").configure {it.dependsOn("generateDebugProtos", "generateReleaseProtos")}
}
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/vmtrace/ArtTraceTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/vmtrace/ArtTraceTest.kt
new file mode 100644
index 0000000..c21f924
--- /dev/null
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/vmtrace/ArtTraceTest.kt
@@ -0,0 +1,111 @@
+/*
+ * 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.vmtrace
+
+import androidx.benchmark.Outputs
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import java.io.File
+import kotlin.test.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import perfetto.protos.TracePacket
+import perfetto.protos.TrackDescriptor
+import perfetto.protos.TrackEvent
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class ArtTraceTest {
+
+ @Test
+ fun artToPerfettoTraceConversion() {
+
+ // The art-trace-test.trace is generated using the following code:
+ // fun testTrace() {
+ // MethodTracing.start("art-trace-test")
+ // myTracedMethod()
+ // MethodTracing.stop()
+ // }
+ // fun myTracedMethod() { }
+ //
+ // As such we want to assert 3 trace packets: the track descriptor and the 2 track events
+ // for slice begin and slice end. Note that the track contains other android framework
+ // methods.
+
+ val artTraceFile = fromAssets("art-trace-test.trace")
+ val tracePackets = ArtTrace(
+ artTrace = artTraceFile,
+ uuidProvider = { 1L }
+ ).toPerfettoTrace().packet
+ val toFind = mutableListOf(
+ TracePacket(
+ timestamp = 430421772813000L,
+ timestamp_clock_id = 3,
+ incremental_state_cleared = true,
+ track_descriptor = TrackDescriptor(
+ name = "main",
+ uuid = 1L,
+ )
+ ),
+ TracePacket(
+ timestamp = 430421819817000L,
+ timestamp_clock_id = 3,
+ track_event = TrackEvent(
+ categories = listOf("art_trace"),
+ name = "androidx.benchmark.vmtrace.ArtTraceTest.myTracedMethod: ()V",
+ type = TrackEvent.Type.TYPE_SLICE_BEGIN,
+ track_uuid = 1L
+ ),
+ trusted_packet_sequence_id = 1234543210
+ ),
+ TracePacket(
+ timestamp = 430421819819000,
+ timestamp_clock_id = 3,
+ track_event = TrackEvent(
+ categories = listOf("art_trace"),
+ name = "androidx.benchmark.vmtrace.ArtTraceTest.myTracedMethod: ()V",
+ type = TrackEvent.Type.TYPE_SLICE_END,
+ track_uuid = 1L
+ ),
+ trusted_packet_sequence_id = 1234543210
+ )
+ )
+
+ // Asserts that all the trace packets are found in order
+ tracePackets.iterator().apply {
+ while (hasNext() and toFind.isNotEmpty()) {
+ val nextToFind = toFind.first()
+ if (next() == nextToFind) toFind.removeFirst()
+ }
+ }
+ assertTrue(toFind.isEmpty())
+ }
+
+ companion object {
+ private fun fromAssets(filename: String) = File
+ .createTempFile(filename, "", Outputs.dirUsableByAppAndShell)
+ .apply {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .context
+ .assets
+ .open(filename)
+ .copyTo(outputStream())
+ }
+ }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Api21.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Api21.kt
index adb0d14..745a4a9 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Api21.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Api21.kt
@@ -22,13 +22,15 @@
import android.os.Debug
import android.os.Environment
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
import java.io.File
internal fun startMethodTracingSampling(tracePath: String, bufferSize: Int, intervalUs: Int) {
Debug.startMethodTracingSampling(tracePath, bufferSize, intervalUs)
}
-internal fun Context.getFirstMountedMediaDir(): File? {
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+fun Context.getFirstMountedMediaDir(): File? {
@Suppress("DEPRECATION")
return externalMediaDirs.firstOrNull {
Environment.getExternalStorageState(it) == Environment.MEDIA_MOUNTED
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 5b3fe34..126070c 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
@@ -64,6 +64,7 @@
val killProcessDelayMillis: Long
val enableStartupProfiles: Boolean
val strictStartupProfiles: Boolean
+ val methodTracingOptions: String
val dryRunMode: Boolean
// internal properties are microbenchmark only
@@ -196,6 +197,9 @@
strictStartupProfiles =
arguments.getBenchmarkArgument("startupProfiles.strict")?.toBoolean() ?: false
+
+ methodTracingOptions =
+ arguments.getBenchmarkArgument("methodTracing.options") ?: ""
}
fun throwIfError() {
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Outputs.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Outputs.kt
index 4cbf248..47638f3 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Outputs.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Outputs.kt
@@ -92,10 +92,16 @@
?: dirUsableByAppAndShell
Log.d(BenchmarkState.TAG, "Output Directory: $outputDirectory")
- outputDirectory.mkdirs()
// Clear all the existing files in the output directories
- deleteFiles { true }
+ listOf(outputDirectory, dirUsableByAppAndShell).forEach {
+ it.listFiles()?.forEach { file ->
+ if (file.isFile) file.delete()
+ }
+ }
+
+ // Ensure output dir is created
+ outputDirectory.mkdirs()
}
/**
@@ -162,10 +168,4 @@
}
return relativePath
}
-
- fun deleteFiles(filterBlock: (File) -> (Boolean)) {
- listOf(outputDirectory, dirUsableByAppAndShell)
- .flatMap { it.listFiles(filterBlock)?.asList() ?: emptyList() }
- .forEach { it.delete() }
- }
}
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 bb1e825..3f16542 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
@@ -95,10 +95,11 @@
config: PerfettoConfig,
userspaceTracingPackage: String?,
traceCallback: ((String) -> Unit)? = null,
+ enableTracing: Boolean = true,
block: () -> Unit
): String? {
- // skip if Perfetto not supported, or on Cuttlefish (where tracing doesn't work)
- if (Build.VERSION.SDK_INT < 23 || !isAbiSupported()) {
+ // skip if Perfetto not supported, or if caller opts out
+ if (Build.VERSION.SDK_INT < 23 || !isAbiSupported() || !enableTracing) {
block()
return null
}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
index d5cd112..6d6ddb8 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
@@ -132,6 +132,10 @@
"ion/ion_stat",
"oom/oom_score_adj_update",
+ // Disk I/O
+ "disk",
+ "ufs/ufshcd_clk_gating",
+
// Old (kernel) LMK
"lowmemorykiller/lowmemory_kill",
),
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/ArtTrace.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/ArtTrace.kt
new file mode 100644
index 0000000..fb3cec6
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/ArtTrace.kt
@@ -0,0 +1,138 @@
+/*
+ * 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.vmtrace
+
+import java.io.File
+import java.util.UUID
+import perfetto.protos.Trace
+import perfetto.protos.TracePacket
+import perfetto.protos.TrackDescriptor
+import perfetto.protos.TrackEvent
+
+typealias UuidProvider = () -> (Long)
+
+internal class ArtTrace(
+ private val artTrace: File,
+ private val uuidProvider: UuidProvider = {
+ UUID.randomUUID().mostSignificantBits and Long.MAX_VALUE
+ }
+) {
+
+ private val clockId = 3
+ private val trustedPacketSequenceId: Int = 1_234_543_210
+
+ fun toPerfettoTrace(): Trace {
+ val events = mutableListOf<TracePacket>().also {
+ val parser = PerfettoVmTraceParser(
+ events = it,
+ trustedPacketSequenceId = trustedPacketSequenceId,
+ clockId = clockId,
+ uuidProvider = uuidProvider
+ )
+ VmTraceParser(artTrace, parser).parse()
+ }
+ return Trace(events)
+ }
+
+ private class PerfettoVmTraceParser(
+ private val events: MutableList<TracePacket>,
+ private val trustedPacketSequenceId: Int,
+ private val clockId: Int,
+ private val uuidProvider: UuidProvider
+ ) : VmTraceHandler {
+
+ private data class ThreadTrack(
+ val uuid: Long,
+ val name: String,
+ var created: Boolean
+ )
+
+ private val props: MutableMap<String, String> = mutableMapOf()
+ private val threads: MutableMap<Int, ThreadTrack> = mutableMapOf()
+ private val methods: MutableMap<Long, MethodInfo> = mutableMapOf()
+ private var version: Int = -1
+ private var startTimeUs: Long = 0L
+
+ override fun setVersion(version: Int) {
+ this.version = version
+ }
+
+ override fun setProperty(key: String, value: String) {
+ this.props[key] = value
+ }
+
+ override fun addMethod(id: Long, info: MethodInfo) {
+ this.methods[id] = info
+ }
+
+ override fun setStartTimeUs(startTimeUs: Long) {
+ this.startTimeUs = startTimeUs
+ }
+
+ override fun addThread(id: Int, name: String) {
+ if (id in threads) return
+ this.threads[id] = ThreadTrack(
+ uuid = uuidProvider(),
+ name = name,
+ created = false
+ )
+ }
+
+ override fun addMethodAction(
+ threadId: Int,
+ methodId: Long,
+ methodAction: TraceAction,
+ threadTime: Int,
+ globalTime: Int
+ ) {
+ val threadTrack = threads[threadId]!!
+
+ if (!threadTrack.created) {
+ events.add(
+ TracePacket(
+ timestamp = startTimeUs * 1000,
+ timestamp_clock_id = clockId,
+ incremental_state_cleared = true,
+ track_descriptor = TrackDescriptor(
+ uuid = threadTrack.uuid,
+ name = threadTrack.name
+ )
+ )
+ )
+ threadTrack.created = true
+ }
+
+ events.add(
+ TracePacket(
+ timestamp = (startTimeUs + globalTime) * 1000,
+ timestamp_clock_id = clockId,
+ trusted_packet_sequence_id = trustedPacketSequenceId,
+ track_event = TrackEvent(
+ type = when (methodAction) {
+ TraceAction.METHOD_ENTER -> TrackEvent.Type.TYPE_SLICE_BEGIN
+ TraceAction.METHOD_EXIT -> TrackEvent.Type.TYPE_SLICE_END
+ TraceAction.METHOD_EXIT_UNROLL -> TrackEvent.Type.TYPE_SLICE_END
+ },
+ track_uuid = threadTrack.uuid,
+ categories = listOf("art_trace"),
+ name = methods[methodId]?.fullName ?: "unknown-method"
+ )
+ )
+ )
+ }
+ }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/ByteBufferUtil.java b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/ByteBufferUtil.java
new file mode 100644
index 0000000..f968b6f
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/ByteBufferUtil.java
@@ -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.vmtrace;
+
+import androidx.annotation.NonNull;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+
+class ByteBufferUtil {
+
+ private ByteBufferUtil() {
+ }
+
+ @NonNull
+ public static ByteBuffer mapFile(@NonNull File f, long offset, @NonNull ByteOrder byteOrder)
+ throws IOException {
+ FileInputStream dataFile = new FileInputStream(f);
+ try {
+ FileChannel fc = dataFile.getChannel();
+ MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, offset,
+ f.length() - offset);
+ buffer.order(byteOrder);
+ return buffer;
+ } finally {
+ dataFile.close(); // this *also* closes the associated channel, fc
+ }
+ }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/MethodInfo.java b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/MethodInfo.java
new file mode 100644
index 0000000..edd3552
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/MethodInfo.java
@@ -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.benchmark.vmtrace;
+
+import androidx.annotation.NonNull;
+
+import java.util.Locale;
+
+class MethodInfo {
+ public final long id;
+ public final String className;
+ public final String methodName;
+ public final String signature;
+ public final String srcPath;
+ public final int srcLineNumber;
+
+ private String mFullName;
+ private String mShortName;
+
+ MethodInfo(
+ long id,
+ @NonNull String className,
+ @NonNull String methodName,
+ @NonNull String signature,
+ @NonNull String srcPath,
+ int srcLineNumber) {
+ this.id = id;
+ this.className = className;
+ this.methodName = methodName;
+ this.signature = signature;
+ this.srcPath = srcPath;
+ this.srcLineNumber = srcLineNumber;
+ }
+
+ @NonNull
+ public String getFullName() {
+ if (mFullName == null) {
+ mFullName = String.format(Locale.US, "%s.%s: %s", className, methodName, signature);
+ }
+ return mFullName;
+ }
+
+ @NonNull
+ public String getShortName() {
+ if (mShortName == null) {
+ mShortName = String.format(Locale.US, "%s.%s", getUnqualifiedClassName(), methodName);
+ }
+ return mShortName;
+ }
+
+ @NonNull
+ private String getUnqualifiedClassName() {
+ String cn = className;
+ int i = cn.lastIndexOf('/');
+ if (i > 0) {
+ cn = cn.substring(i + 1);
+ }
+ return cn;
+ }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/TraceAction.java b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/TraceAction.java
new file mode 100644
index 0000000..c4ded0f
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/TraceAction.java
@@ -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.
+ */
+
+package androidx.benchmark.vmtrace;
+
+enum TraceAction {
+ METHOD_ENTER, // method entry
+ METHOD_EXIT, // method exit
+ METHOD_EXIT_UNROLL // method exited by exception unrolling
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/VmClockType.java b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/VmClockType.java
new file mode 100644
index 0000000..9f9aaf6
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/VmClockType.java
@@ -0,0 +1,22 @@
+/*
+ * 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.vmtrace;
+
+enum VmClockType {
+ THREAD_CPU,
+ WALL,
+ DUAL
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/VmTraceHandler.java b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/VmTraceHandler.java
new file mode 100644
index 0000000..55ebfa4
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/VmTraceHandler.java
@@ -0,0 +1,70 @@
+/*
+ * 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.vmtrace;
+
+import androidx.annotation.NonNull;
+
+/**
+ * This interface used by {@link VmTraceParser}. {@link VmTraceParser} parses a trace file and
+ * informs the handler about parsing events.
+ */
+interface VmTraceHandler {
+ /** @param version - version of the trace file. */
+ void setVersion(int version);
+
+ /**
+ * Sets a parsed property of the trace file. Example keys are: "elapsed-time-usec", "clock",
+ * "data-file-overflow", "vm"
+ */
+ void setProperty(@NonNull String key, @NonNull String value);
+
+ /**
+ * Receives notification about a thread.
+ *
+ * @param id - id of the thread.
+ * @param name - name of the thread.
+ */
+ void addThread(int id, @NonNull String name);
+
+ /**
+ * Receives notification about a method.
+ *
+ * @param id - id of the method.
+ * @param info - {@link MethodInfo} that contains information about the method.
+ */
+ void addMethod(long id, @NonNull MethodInfo info);
+
+ /**
+ * Receives notification about a method event. Example events are: method entered, method
+ * exited.
+ *
+ * @param threadId - id of the thread where this event happened.
+ * @param methodId - id of the method where this event happened.
+ * @param methodAction - type of the action
+ * @param threadTime - thread time when this event happened.
+ * @param globalTime - global time when this event
+ */
+ void addMethodAction(
+ int threadId,
+ long methodId,
+ @NonNull TraceAction methodAction,
+ int threadTime,
+ int globalTime
+ );
+
+ /** @param startTimeUs - tracing start time. */
+ void setStartTimeUs(long startTimeUs);
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/VmTraceParser.java b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/VmTraceParser.java
new file mode 100644
index 0000000..f7c8a0b
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/vmtrace/VmTraceParser.java
@@ -0,0 +1,408 @@
+/*
+ * 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.vmtrace;
+
+import androidx.annotation.NonNull;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+class VmTraceParser {
+
+ static final Charset CHARSET_US_ASCII = Charset.forName("US-ASCII");
+ static final Charset CHARSET_UTF_8 = Charset.forName("UTF-8");
+ private static final int TRACE_MAGIC = 0x574f4c53; // 'SLOW'
+ private static final String HEADER_SECTION_VERSION = "*version";
+ private static final String HEADER_SECTION_THREADS = "*threads";
+ private static final String HEADER_SECTION_METHODS = "*methods";
+ private static final String HEADER_END = "*end";
+ private static final String KEY_CLOCK = "clock";
+
+ private final File mTraceFile;
+ final VmTraceHandler mTraceDataHandler;
+ int mVersion;
+ private VmClockType mVmClockType;
+
+ VmTraceParser(@NonNull File traceFile, @NonNull VmTraceHandler traceHandler) {
+ if (!traceFile.exists()) {
+ throw new IllegalArgumentException(
+ "Trace file " + traceFile.getAbsolutePath() + " does not exist.");
+ }
+ mTraceFile = traceFile;
+ mTraceDataHandler = traceHandler;
+ }
+
+ public void parse() throws IOException {
+ ByteBuffer buffer;
+ if (isStreamingTrace(mTraceFile)) {
+ throw new UnsupportedOperationException("Streaming traces are not supported.");
+ } else {
+ long headerLength = parseHeader(mTraceFile);
+ buffer = ByteBufferUtil.mapFile(mTraceFile, headerLength, ByteOrder.LITTLE_ENDIAN);
+ }
+ parseData(buffer);
+ }
+
+ private static boolean isStreamingTrace(File file) throws IOException {
+ BufferedReader in =
+ new BufferedReader(
+ new InputStreamReader(new FileInputStream(file), CHARSET_US_ASCII));
+ try {
+ String firstLine = in.readLine();
+ if (firstLine != null && firstLine.startsWith(HEADER_SECTION_VERSION)) {
+ // Trace file not obtained by using streaming mode
+ return false;
+ }
+ } finally {
+ in.close();
+ }
+ return true;
+ }
+
+ // The values of PARSE_METHODS, PARSE_THREADS and PARSE_SUMMARY match the corresponding value
+ // in trace files,
+ // which are written by Android Runtime (ART) code. Please do not change their values without
+ // a matching change to ART.
+ private static final int PARSE_VERSION = 0;
+ private static final int PARSE_METHODS = 1;
+ private static final int PARSE_THREADS = 2;
+ private static final int PARSE_OPTIONS = 4;
+
+ /** Parses the trace file header and returns the offset in the file where the header ends. */
+ long parseHeader(File f) throws IOException {
+ long offset = 0;
+ BufferedReader in = null;
+ try {
+ in = new BufferedReader(new InputStreamReader(new FileInputStream(f), CHARSET_UTF_8));
+ int mode = PARSE_VERSION;
+ String line;
+ while (true) {
+ line = in.readLine();
+ if (line == null) {
+ throw new IOException("Key section does not have an *end marker");
+ }
+
+ // Calculate how much we have read from the file so far. The extra byte is for
+ // the line ending not included by readLine().
+ // We can't use line.length() as unicode characters can be represented by more
+ // than 1 byte.
+ offset += line.getBytes(CHARSET_UTF_8).length + 1;
+
+ if (line.startsWith("*")) {
+ if (line.equals(HEADER_SECTION_VERSION)) {
+ mode = PARSE_VERSION;
+ continue;
+ }
+ if (line.equals(HEADER_SECTION_THREADS)) {
+ mode = PARSE_THREADS;
+ continue;
+ }
+ if (line.equals(HEADER_SECTION_METHODS)) {
+ mode = PARSE_METHODS;
+ continue;
+ }
+ if (line.equals(HEADER_END)) {
+ break;
+ }
+ }
+
+ switch (mode) {
+ case PARSE_VERSION:
+ mVersion = Integer.decode(line);
+ mTraceDataHandler.setVersion(mVersion);
+ mode = PARSE_OPTIONS;
+ break;
+ case PARSE_THREADS:
+ parseThread(line);
+ break;
+ case PARSE_METHODS:
+ parseMethod(line);
+ break;
+ case PARSE_OPTIONS:
+ parseOption(line);
+ break;
+ }
+ }
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ // cannot happen
+ }
+ }
+ }
+
+ return offset;
+ }
+
+ /** Parses trace option formatted as a key value pair. */
+ void parseOption(String line) {
+ String[] tokens = line.split("=");
+ if (tokens.length == 2) {
+ String key = tokens[0];
+ String value = tokens[1];
+ mTraceDataHandler.setProperty(key, value);
+
+ if (key.equals(KEY_CLOCK)) {
+ if (value.equals("thread-cpu")) {
+ mVmClockType = VmClockType.THREAD_CPU;
+ } else if (value.equals("wall")) {
+ mVmClockType = VmClockType.WALL;
+ } else if (value.equals("dual")) {
+ mVmClockType = VmClockType.DUAL;
+ }
+ }
+
+ }
+ }
+
+ /** Parses thread information comprising an integer id and the thread name */
+ private void parseThread(String line) {
+ int index = line.indexOf('\t');
+ if (index < 0) {
+ return;
+ }
+
+ try {
+ int id = Integer.decode(line.substring(0, index));
+ String name = line.substring(index).trim();
+ mTraceDataHandler.addThread(id, name);
+ } catch (NumberFormatException ignored) {
+ }
+ }
+
+ void parseMethod(String line) {
+ String[] tokens = line.split("\t");
+ long id;
+ try {
+ id = Long.decode(tokens[0]);
+ } catch (NumberFormatException e) {
+ return;
+ }
+
+ String className = tokens[1];
+ String methodName = null;
+ String signature = null;
+ String pathname = null;
+ int lineNumber = -1;
+ if (tokens.length == 6) {
+ methodName = tokens[2];
+ signature = tokens[3];
+ pathname = tokens[4];
+ lineNumber = Integer.decode(tokens[5]);
+ pathname = constructPathname(className, pathname);
+ } else if (tokens.length > 2) {
+ if (tokens[3].startsWith("(")) {
+ methodName = tokens[2];
+ signature = tokens[3];
+ if (tokens.length >= 5) {
+ pathname = tokens[4];
+ }
+ } else {
+ pathname = tokens[2];
+ lineNumber = Integer.decode(tokens[3]);
+ }
+ }
+
+ mTraceDataHandler.addMethod(
+ id, new MethodInfo(id, className, methodName, signature, pathname, lineNumber));
+ }
+
+ private String constructPathname(String className, String pathname) {
+ int index = className.lastIndexOf('/');
+ if (index > 0 && index < className.length() - 1 && pathname.endsWith(".java")) {
+ pathname = className.substring(0, index + 1) + pathname;
+ }
+ return pathname;
+ }
+
+ /**
+ * Parses the data section of the trace. The data section comprises of a header followed
+ * by a list of records.
+ *
+ * All values are stored in little-endian order.
+ */
+ private void parseData(ByteBuffer buffer) {
+ int recordSize = readDataFileHeader(buffer);
+ parseMethodTraceData(buffer, recordSize);
+ }
+
+ /**
+ * Parses the list of records corresponding to each trace event (method entry, exit, ...)
+ * Record format v1:
+ * u1 thread ID
+ * u4 method ID | method action
+ * u4 time delta since start, in usec
+ *
+ * Record format v2:
+ * u2 thread ID
+ * u4 method ID | method action
+ * u4 time delta since start, in usec
+ *
+ * Record format v3:
+ * u2 thread ID
+ * u4 method ID | method action
+ * u4 time delta since start, in usec
+ * u4 wall time since start, in usec (when clock == "dual" only)
+ *
+ * 32 bits of microseconds is 70 minutes.
+ */
+ private void parseMethodTraceData(ByteBuffer buffer, int recordSize) {
+ int methodId;
+ int threadId;
+ int version = mVersion;
+ while (buffer.hasRemaining()) {
+ int threadTime;
+ int globalTime;
+
+ int positionStart = buffer.position();
+
+ threadId = version == 1 ? buffer.get() : buffer.getShort();
+ methodId = buffer.getInt();
+
+ switch (mVmClockType) {
+ case WALL:
+ globalTime = buffer.getInt();
+ threadTime = globalTime;
+ break;
+ case DUAL:
+ threadTime = buffer.getInt();
+ globalTime = buffer.getInt();
+ break;
+ case THREAD_CPU:
+ default:
+ threadTime = buffer.getInt();
+ globalTime = threadTime;
+ break;
+ }
+
+ int positionEnd = buffer.position();
+ int bytesRead = positionEnd - positionStart;
+ if (bytesRead < recordSize) {
+ buffer.position(positionEnd + (recordSize - bytesRead));
+ }
+
+ int action = methodId & 0x03;
+ TraceAction methodAction;
+ switch (action) {
+ case 0:
+ methodAction = TraceAction.METHOD_ENTER;
+ break;
+ case 1:
+ methodAction = TraceAction.METHOD_EXIT;
+ break;
+ case 2:
+ methodAction = TraceAction.METHOD_EXIT_UNROLL;
+ break;
+ default:
+ throw new RuntimeException(
+ "Invalid trace action, expected one of method entry, exit or unroll.");
+ }
+ methodId &= ~0x03;
+
+ mTraceDataHandler.addMethodAction(
+ threadId, unsignedIntToLong(methodId), methodAction, threadTime, globalTime);
+ }
+ }
+
+ private static long unsignedIntToLong(int value) {
+ return value & 0xffffffffL;
+ }
+
+ /**
+ * Parses the data header with the following format:
+ * u4 magic ('SLOW')
+ * u2 version
+ * u2 offset to data
+ * u8 start date/time in usec
+ * u2 record size in bytes (version >= 2 only)
+ * ... padding to 32 bytes
+ *
+ * @param buffer byte buffer pointing to the header
+ * @return record size for each data entry following the header
+ */
+ private int readDataFileHeader(ByteBuffer buffer) {
+ validateMagic(buffer.getInt());
+ // read version
+ int version = buffer.getShort();
+ if (version != mVersion) {
+ String msg =
+ String.format(
+ "Error: version number mismatch; got %d in data header but %d in "
+ + "options\n",
+ version, mVersion);
+ throw new RuntimeException(msg);
+ }
+ validateTraceVersion(version);
+
+ // read offset
+ int offsetToData = buffer.getShort() - 16;
+
+ // read startWhen
+ mTraceDataHandler.setStartTimeUs(buffer.getLong());
+
+ // read record size
+ int recordSize;
+ switch (version) {
+ case 1:
+ recordSize = 9;
+ break;
+ case 2:
+ recordSize = 10;
+ break;
+ default:
+ recordSize = buffer.getShort();
+ offsetToData -= 2;
+ break;
+ }
+
+ // Skip over offsetToData bytes
+ while (offsetToData-- > 0) {
+ buffer.get();
+ }
+
+ return recordSize;
+ }
+
+ static void validateTraceVersion(int version) {
+ if (version < 1 || version > 3) {
+ String msg =
+ String.format(
+ "Error: unsupported trace version number %d. "
+ + "Please use a newer version of TraceView to read this file.",
+ version);
+ throw new RuntimeException(msg);
+ }
+ }
+
+ static void validateMagic(int magic) {
+ if (magic != TRACE_MAGIC) {
+ String msg =
+ String.format(
+ "Error: magic number mismatch; got 0x%x, expected 0x%x\n",
+ magic, TRACE_MAGIC);
+ throw new RuntimeException(msg);
+ }
+ }
+}
diff --git a/benchmark/benchmark-internal/build.gradle b/benchmark/benchmark-internal/build.gradle
new file mode 100644
index 0000000..45da453
--- /dev/null
+++ b/benchmark/benchmark-internal/build.gradle
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.Publish
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("kotlin-android")
+}
+
+android {
+ namespace "androidx.benchmark.internal"
+}
+
+dependencies {
+ implementation(libs.kotlinStdlib)
+ api("androidx.annotation:annotation:1.1.0")
+ api("androidx.annotation:annotation-experimental:1.0.0")
+ implementation("androidx.tracing:tracing-ktx:1.0.0")
+ implementation(libs.testMonitor)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.kotlinTest)
+}
+
+androidx {
+ name = "Benchmark - Internal"
+ publish = Publish.SNAPSHOT_ONLY
+ inceptionYear = "2023"
+ description = "Android Benchmark - Internal"
+}
diff --git a/benchmark/benchmark-internal/src/main/AndroidManifest.xml b/benchmark/benchmark-internal/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..819d8da
--- /dev/null
+++ b/benchmark/benchmark-internal/src/main/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <application>
+ <receiver
+ android:name=".MethodTracingReceiver"
+ android:directBootAware="false"
+ android:enabled="true"
+ android:exported="true"
+ android:permission="android.permission.DUMP">
+ <intent-filter>
+ <action android:name="androidx.benchmark.experiments.ACTION_METHOD_TRACE" />
+ </intent-filter>
+ </receiver>
+ </application>
+
+ <!-- Needed to dump the method traces. -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+</manifest>
diff --git a/benchmark/benchmark-internal/src/main/java/androidx/benchmark/internal/MethodTracingReceiver.kt b/benchmark/benchmark-internal/src/main/java/androidx/benchmark/internal/MethodTracingReceiver.kt
new file mode 100644
index 0000000..9cbc912
--- /dev/null
+++ b/benchmark/benchmark-internal/src/main/java/androidx/benchmark/internal/MethodTracingReceiver.kt
@@ -0,0 +1,168 @@
+/*
+ * 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.internal
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.Debug
+import android.os.Environment
+import android.util.Log
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.benchmark.internal.MethodTracingApi21.getFirstMountedMediaDir
+import java.io.File
+
+/**
+ * Used to toggle method tracing on the application.
+ */
+class MethodTracingReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent?) {
+ val intentAction = intent?.action ?: ""
+ if (intentAction != ACTION_METHOD_TRACE) {
+ val message = "Unknown action $intentAction"
+ Log.w(TAG, message)
+ resultCode = RESULT_CODE_FAILED
+ return
+ }
+ methodTracingRequest(context, intent)
+ }
+
+ private fun methodTracingRequest(context: Context, intent: Intent?) {
+ val packageName = context.packageName
+ val extras = intent?.extras
+ val action = extras?.getString(ACTION)
+ val fileName = extras?.getString(UNIQUE_NAME)
+ if (action.isNullOrBlank()) {
+ Log.d(TAG, "Unknown action.")
+ resultCode = RESULT_CODE_FAILED
+ return
+ }
+ when (action) {
+ METHOD_TRACE_START_SAMPLED -> {
+ require(!fileName.isNullOrBlank()) {
+ Log.d(TAG, "Missing output file name")
+ resultCode = RESULT_CODE_FAILED
+ return
+ }
+ if (Build.VERSION.SDK_INT >= 21) {
+ MethodTracingApi21.startMethodTracingSampling(
+ tracePath = outputTracePath(context, fileName),
+ bufferSize = BUFFER_SIZE_BYTES,
+ intervalUs = INTERVAL_MICRO_SECONDS
+ )
+ } else {
+ // Fallback
+ startMethodTracing(fileName, context)
+ }
+ }
+
+ METHOD_TRACE_START -> {
+ startMethodTracing(fileName, context)
+ }
+
+ METHOD_TRACE_END -> {
+ Log.d(TAG, "Stopping method tracing for $packageName")
+ Debug.stopMethodTracing()
+ resultCode = RESULT_CODE_SUCCESS
+ }
+
+ else -> {
+ Log.w(TAG, "Unknown request: $intent")
+ resultCode = RESULT_CODE_FAILED
+ }
+ }
+ }
+
+ private fun startMethodTracing(fileName: String?, context: Context) {
+ require(!fileName.isNullOrBlank()) {
+ Log.d(TAG, "Missing output file name")
+ resultCode = RESULT_CODE_FAILED
+ return
+ }
+ Debug.startMethodTracing(
+ outputTracePath(context, fileName),
+ BUFFER_SIZE_BYTES
+ )
+ Log.d(TAG, "Enabling method tracing on ${context.packageName} ($fileName)")
+ resultCode = RESULT_CODE_SUCCESS
+ }
+
+ companion object {
+ private const val TAG = "MethodTracingReceiver"
+
+ // Intents
+ private const val ACTION_METHOD_TRACE = "androidx.benchmark.experiments.ACTION_METHOD_TRACE"
+
+ // Extras
+ private const val ACTION = "ACTION"
+ private const val UNIQUE_NAME = "UNIQUE_NAME"
+
+ // Actions
+ private const val METHOD_TRACE_START = "METHOD_TRACE_START"
+ private const val METHOD_TRACE_START_SAMPLED = "METHOD_TRACE_START_SAMPLED"
+ private const val METHOD_TRACE_END = "ACTION_METHOD_TRACE_END"
+
+ // Result codes
+ private const val RESULT_CODE_FAILED = 0
+ private const val RESULT_CODE_SUCCESS = 10
+
+ // Tracing
+ internal fun outputTracePath(context: Context, fileName: String): String {
+ val basePath = if (Build.VERSION.SDK_INT >= 21) {
+ context.getFirstMountedMediaDir()
+ } else {
+ null
+ }
+ val file = File(basePath, fileName)
+ // Delete file if already exists.
+ file.delete()
+ return file.absolutePath
+ }
+
+ // The maximum size of a trace.
+ // Setting this to 1G because that ought to be enough.
+ private const val BUFFER_SIZE_BYTES = 1024 * 1024 * 1024 // bytes
+
+ // The sampling internal. Set to 1/10th of a millisecond.
+ private const val INTERVAL_MICRO_SECONDS = 1000 // micro-seconds
+ }
+}
+
+@RequiresApi(21)
+internal object MethodTracingApi21 {
+ @DoNotInline
+ fun startMethodTracingSampling(
+ tracePath: String,
+ bufferSize: Int,
+ intervalUs: Int
+ ) {
+ Debug.startMethodTracingSampling(tracePath, bufferSize, intervalUs)
+ }
+
+ @DoNotInline
+ @Suppress("DEPRECATION")
+ fun Context.getFirstMountedMediaDir(): File? {
+ // This is identical to the snippet from Outputs.dirUsableByAppAndShell.
+ // This is the only way to write a trace that can be subsequently copied cleanly
+ // by the Shell.
+ return externalMediaDirs.firstOrNull {
+ Environment.getExternalStorageState(it) == Environment.MEDIA_MOUNTED
+ }
+ }
+}
diff --git a/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/AndroidBenchmarkRunner.kt b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/AndroidBenchmarkRunner.kt
index 9cbb6d2..9ad9b62 100644
--- a/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/AndroidBenchmarkRunner.kt
+++ b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/AndroidBenchmarkRunner.kt
@@ -17,6 +17,7 @@
package androidx.benchmark.junit4
import androidx.annotation.CallSuper
+import androidx.benchmark.Arguments
import androidx.benchmark.IsolationActivity
import androidx.benchmark.Shell
import androidx.test.runner.AndroidJUnitRunner
@@ -82,7 +83,8 @@
runOnMainSync {
isResumed = IsolationActivity.resumed
}
- if (!isResumed) {
+ // dryRunMode doesn't care about isolation or sustained perf mode, so skip launch cost
+ if (!isResumed && !Arguments.dryRunMode) {
IsolationActivity.launchSingleton()
}
}
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 73b4c49..b0fc66f 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
@@ -217,7 +217,11 @@
appTagPackages = packages,
useStackSamplingConfig = false
),
- userspaceTracingPackage = null
+ userspaceTracingPackage = null,
+
+ // optimize throughput in dryRunMode, since trace isn't useful, and extremely
+ // expensive on some emulators. Could alternately use UserspaceTracing if desired
+ enableTracing = !Arguments.dryRunMode
) {
UserspaceTracing.commitToTrace() // clear buffer
diff --git a/benchmark/benchmark-macro/api/current.ignore b/benchmark/benchmark-macro/api/current.ignore
index 12f722e..84926d3 100644
--- a/benchmark/benchmark-macro/api/current.ignore
+++ b/benchmark/benchmark-macro/api/current.ignore
@@ -13,8 +13,6 @@
Removed class androidx.benchmark.macro.MacrobenchmarkKt
RemovedClass: androidx.benchmark.macro.MetricKt:
Removed class androidx.benchmark.macro.MetricKt
-RemovedClass: androidx.benchmark.macro.MetricResultExtensionsKt:
- Removed class androidx.benchmark.macro.MetricResultExtensionsKt
RemovedClass: androidx.benchmark.macro.TagKt:
Removed class androidx.benchmark.macro.TagKt
diff --git a/benchmark/benchmark-macro/api/restricted_current.ignore b/benchmark/benchmark-macro/api/restricted_current.ignore
index 0e7f13d..e6c9b40 100644
--- a/benchmark/benchmark-macro/api/restricted_current.ignore
+++ b/benchmark/benchmark-macro/api/restricted_current.ignore
@@ -13,8 +13,6 @@
Removed class androidx.benchmark.macro.MacrobenchmarkKt
RemovedClass: androidx.benchmark.macro.MetricKt:
Removed class androidx.benchmark.macro.MetricKt
-RemovedClass: androidx.benchmark.macro.MetricResultExtensionsKt:
- Removed class androidx.benchmark.macro.MetricResultExtensionsKt
RemovedClass: androidx.benchmark.macro.TagKt:
Removed class androidx.benchmark.macro.TagKt
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 f1321d2..2582f2a 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
@@ -43,7 +43,6 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.tracing.trace
import java.io.File
-import java.lang.StringBuilder
/**
* Get package ApplicationInfo, throw if not found
@@ -202,7 +201,8 @@
it.configure(packageName)
}
val measurements = PerfettoTraceProcessor.runServer {
- List(if (Arguments.dryRunMode) 1 else iterations) { iteration ->
+ 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") {
scope.device.wakeUp()
@@ -214,8 +214,9 @@
}
val iterString = iteration.toString().padStart(3, '0')
+ val fileLabel = "${uniqueName}_iter$iterString"
val tracePath = perfettoCollector.record(
- fileLabel = "${uniqueName}_iter$iterString",
+ fileLabel = fileLabel,
config = PerfettoConfig.Benchmark(
/**
* Prior to API 24, every package name was joined into a single setprop
@@ -238,6 +239,19 @@
) {
try {
trace("start metrics") {
+ if (Arguments.methodTracingOptions.isNotEmpty()) {
+ // Once you turn on method tracing its okay to ignore
+ // the costs of true CompilationMode.COLD as the numbers cannot
+ // be used for anything reasonable.
+
+ // It would be nice if our metrics infra supported this use case
+ // better.
+ MethodTracing.startTracing(
+ packageName = packageName,
+ options = Arguments.methodTracingOptions,
+ uniqueName = fileLabel
+ )
+ }
metrics.forEach {
it.start()
}
@@ -250,6 +264,12 @@
metrics.forEach {
it.stop()
}
+ if (Arguments.methodTracingOptions.isNotEmpty()) {
+ MethodTracing.stopTracing(
+ packageName = packageName,
+ uniqueName = fileLabel
+ )
+ }
}
}
}!!
@@ -289,7 +309,6 @@
appendUiState(uiState)
}
Log.d(TAG, "Iteration $iteration captured $uiState")
-
// report just the metrics
measurementList
}.mergeMultiIterResults()
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
new file mode 100644
index 0000000..7a07561
--- /dev/null
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt
@@ -0,0 +1,89 @@
+package androidx.benchmark.macro
+
+import android.content.Context
+import androidx.annotation.RestrictTo
+import androidx.benchmark.Outputs
+import androidx.benchmark.Shell
+import androidx.benchmark.getFirstMountedMediaDir
+import androidx.benchmark.userspaceTrace
+import androidx.test.platform.app.InstrumentationRegistry
+import java.io.File
+
+private const val OPTION_SAMPLED = "Sampled"
+private const val RECEIVER_NAME = "androidx.benchmark.internal.MethodTracingReceiver"
+
+// Extras
+private const val ACTION = "ACTION"
+private const val UNIQUE_NAME = "UNIQUE_NAME"
+
+// Actions
+private const val METHOD_TRACE_START = "METHOD_TRACE_START"
+private const val METHOD_TRACE_START_SAMPLED = "METHOD_TRACE_START_SAMPLED"
+private const val METHOD_TRACE_END = "ACTION_METHOD_TRACE_END"
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+object MethodTracing {
+ private val context: Context = InstrumentationRegistry.getInstrumentation().context
+
+ /**
+ * Starts method tracing on the [packageName].
+ * <br/>
+ * The only [options] supported are `Full` and `Sampled`.
+ */
+ fun startTracing(packageName: String, uniqueName: String, options: String) {
+ val fileName = fileName(uniqueName)
+ // The only options possible are `Full` and `Sampled`
+ val extras = if (options == (OPTION_SAMPLED)) {
+ "-e $ACTION $METHOD_TRACE_START_SAMPLED -e $UNIQUE_NAME $fileName"
+ } else {
+ "-e $ACTION $METHOD_TRACE_START -e $UNIQUE_NAME $fileName"
+ }
+ broadcast(packageName, extras)
+ }
+
+ /**
+ * Stops method tracing and copies the output trace to the `additionalTestOutputDir`.
+ */
+ fun stopTracing(packageName: String, uniqueName: String) {
+ val fileName = fileName(uniqueName)
+ val extras = "-e $ACTION $METHOD_TRACE_END"
+ broadcast(packageName, extras)
+ // The reason we are doing this is to make trace collection possible.
+ // The target APK stores the method traces in the first media mounted directory.
+ // This is because, that happens to be the only directory accessible to the app and shell.
+ // We then subsequently copy it to the actual `Outputs.dirUsableByAppAndShell` from the
+ // perspective of the test APK.
+ val mediaDirParent = context.getFirstMountedMediaDir()?.parentFile
+ val sourcePath = "$mediaDirParent/$packageName/$fileName"
+ // Staging location before we write it again using Outputs.writeFile(...)
+ // :(
+ val stagingPath = "${Outputs.dirUsableByAppAndShell}/_$fileName"
+ Shell.executeScriptSilent("cp '$sourcePath' '$stagingPath'")
+ // Report
+ Outputs.writeFile(fileName, fileName) {
+ val staging = File(stagingPath)
+ // No need to clean up, here because the clean up happens automatically on subsequent
+ // test runs.
+ staging.copyTo(it, overwrite = true)
+ }
+ }
+
+ private fun fileName(uniqueName: String): String {
+ return "${uniqueName}_method.trace"
+ }
+
+ private fun broadcast(targetPackageName: String, extras: String) {
+ userspaceTrace("methodTracingBroadcast") {
+ val action = "androidx.benchmark.experiments.ACTION_METHOD_TRACE"
+ val result =
+ Shell.amBroadcast("-a $action $extras $targetPackageName/$RECEIVER_NAME") ?: 0
+ require(result > 0) {
+ """
+ Operation with $extras failed (result code $result).
+ Make sure you add a dependency on:
+ `project(":benchmark:benchmark-internal")`
+ """.trimIndent()
+ }
+ }
+ }
+}
diff --git a/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-baseline-prof.txt b/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-baseline-prof.txt
index bac885e..5ba869c 100644
--- a/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-baseline-prof.txt
+++ b/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-baseline-prof.txt
@@ -334,8 +334,6 @@
HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->captureLayoutInfos(IIIIII)V
HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->didMeasures()V
HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->measure(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;)V
-Landroidx/constraintlayout/widget/ConstraintLayoutStates;
-Landroidx/constraintlayout/widget/ConstraintSet;
Landroidx/constraintlayout/widget/Guideline;
Landroidx/constraintlayout/widget/Placeholder;
Landroidx/constraintlayout/widget/R$styleable;
@@ -414,7 +412,6 @@
PLandroidx/profileinstaller/ProfileVerifier$Cache;-><init>(IIJJ)V
PLandroidx/profileinstaller/ProfileVerifier$Cache;->equals(Ljava/lang/Object;)Z
PLandroidx/profileinstaller/ProfileVerifier$Cache;->readFromFile(Ljava/io/File;)Landroidx/profileinstaller/ProfileVerifier$Cache;
-Landroidx/profileinstaller/ProfileVerifier$CompilationStatus;
PLandroidx/profileinstaller/ProfileVerifier$CompilationStatus;-><init>(IZZ)V
PLandroidx/profileinstaller/ProfileVerifier$CompilationStatus;->getProfileInstallResultCode()I
PLandroidx/profileinstaller/ProfileVerifier$CompilationStatus;->hasProfileEnqueuedForCompilation()Z
diff --git a/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-startup-prof.txt b/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-startup-prof.txt
index 8ac4720..14ed653 100644
--- a/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-startup-prof.txt
+++ b/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-startup-prof.txt
@@ -334,8 +334,6 @@
HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->captureLayoutInfos(IIIIII)V
HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->didMeasures()V
HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->measure(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;)V
-Landroidx/constraintlayout/widget/ConstraintLayoutStates;
-Landroidx/constraintlayout/widget/ConstraintSet;
Landroidx/constraintlayout/widget/Guideline;
Landroidx/constraintlayout/widget/Placeholder;
Landroidx/constraintlayout/widget/R$styleable;
@@ -413,7 +411,6 @@
PLandroidx/profileinstaller/ProfileVerifier$Api33Impl;->getPackageInfo(Landroid/content/pm/PackageManager;Landroid/content/Context;)Landroid/content/pm/PackageInfo;
PLandroidx/profileinstaller/ProfileVerifier$Cache;-><init>(IIJJ)V
PLandroidx/profileinstaller/ProfileVerifier$Cache;->writeOnFile(Ljava/io/File;)V
-Landroidx/profileinstaller/ProfileVerifier$CompilationStatus;
PLandroidx/profileinstaller/ProfileVerifier$CompilationStatus;-><init>(IZZ)V
PLandroidx/profileinstaller/ProfileVerifier$CompilationStatus;->getProfileInstallResultCode()I
PLandroidx/profileinstaller/ProfileVerifier$CompilationStatus;->hasProfileEnqueuedForCompilation()Z
diff --git a/benchmark/integration-tests/baselineprofile-flavors-consumer/build.gradle b/benchmark/integration-tests/baselineprofile-flavors-consumer/build.gradle
index d8f0efa..893b521 100644
--- a/benchmark/integration-tests/baselineprofile-flavors-consumer/build.gradle
+++ b/benchmark/integration-tests/baselineprofile-flavors-consumer/build.gradle
@@ -30,7 +30,7 @@
}
}
productFlavors {
- flavorDimensions = ["version"]
+ flavorDimensions = ["version", "color"]
free {
dimension "version"
applicationIdSuffix ".free"
@@ -41,6 +41,15 @@
applicationIdSuffix ".paid"
versionNameSuffix "-paid"
}
+ red {
+ dimension "color"
+ }
+ blue {
+ dimension "color"
+ // Note that the producer does not have a `red` flavor dimension to test matching
+ // fallbacks with baseline profiles.
+ matchingFallbacks += "red"
+ }
}
namespace "androidx.benchmark.integration.baselineprofile.flavors.consumer"
}
@@ -52,20 +61,14 @@
baselineProfile {
filter {
- include "androidx.benchmark.integration.baselineprofile.flavors.consumer.*"
+ include "androidx.benchmark.integration.baselineprofile.flavors.consumer.**"
}
variants {
- freeRelease {
- filter {
- include "androidx.benchmark.integration.baselineprofile.flavors.consumer.free.*"
- from(project(":benchmark:integration-tests:baselineprofile-flavors-producer"))
- }
+ free {
+ from(project(":benchmark:integration-tests:baselineprofile-flavors-producer"))
}
- paidRelease {
- filter {
- include "androidx.benchmark.integration.baselineprofile.flavors.consumer.paid.*"
- from(project(":benchmark:integration-tests:baselineprofile-flavors-producer"))
- }
+ paid {
+ from(project(":benchmark:integration-tests:baselineprofile-flavors-producer"))
}
}
diff --git a/benchmark/integration-tests/baselineprofile-flavors-consumer/src/freeRelease/generated/baselineProfiles/expected-baseline-prof.txt b/benchmark/integration-tests/baselineprofile-flavors-consumer/src/freeBlueRelease/generated/baselineProfiles/expected-baseline-prof.txt
similarity index 100%
rename from benchmark/integration-tests/baselineprofile-flavors-consumer/src/freeRelease/generated/baselineProfiles/expected-baseline-prof.txt
rename to benchmark/integration-tests/baselineprofile-flavors-consumer/src/freeBlueRelease/generated/baselineProfiles/expected-baseline-prof.txt
diff --git a/benchmark/integration-tests/baselineprofile-flavors-consumer/src/freeRelease/generated/baselineProfiles/expected-baseline-prof.txt b/benchmark/integration-tests/baselineprofile-flavors-consumer/src/freeRedRelease/generated/baselineProfiles/expected-baseline-prof.txt
similarity index 100%
copy from benchmark/integration-tests/baselineprofile-flavors-consumer/src/freeRelease/generated/baselineProfiles/expected-baseline-prof.txt
copy to benchmark/integration-tests/baselineprofile-flavors-consumer/src/freeRedRelease/generated/baselineProfiles/expected-baseline-prof.txt
diff --git a/benchmark/integration-tests/baselineprofile-flavors-consumer/src/paidRelease/generated/baselineProfiles/expected-baseline-prof.txt b/benchmark/integration-tests/baselineprofile-flavors-consumer/src/paidBlueRelease/generated/baselineProfiles/expected-baseline-prof.txt
similarity index 100%
copy from benchmark/integration-tests/baselineprofile-flavors-consumer/src/paidRelease/generated/baselineProfiles/expected-baseline-prof.txt
copy to benchmark/integration-tests/baselineprofile-flavors-consumer/src/paidBlueRelease/generated/baselineProfiles/expected-baseline-prof.txt
diff --git a/benchmark/integration-tests/baselineprofile-flavors-consumer/src/paidRelease/generated/baselineProfiles/expected-baseline-prof.txt b/benchmark/integration-tests/baselineprofile-flavors-consumer/src/paidRedRelease/generated/baselineProfiles/expected-baseline-prof.txt
similarity index 100%
rename from benchmark/integration-tests/baselineprofile-flavors-consumer/src/paidRelease/generated/baselineProfiles/expected-baseline-prof.txt
rename to benchmark/integration-tests/baselineprofile-flavors-consumer/src/paidRedRelease/generated/baselineProfiles/expected-baseline-prof.txt
diff --git a/benchmark/integration-tests/baselineprofile-flavors-producer/build.gradle b/benchmark/integration-tests/baselineprofile-flavors-producer/build.gradle
index 05d1c99..dcec54e 100644
--- a/benchmark/integration-tests/baselineprofile-flavors-producer/build.gradle
+++ b/benchmark/integration-tests/baselineprofile-flavors-producer/build.gradle
@@ -36,9 +36,12 @@
}
}
productFlavors {
- flavorDimensions = ["version"]
+ flavorDimensions = ["version", "color"]
free { dimension "version" }
paid { dimension "version" }
+ red { dimension "color" }
+ // Note that the consumer has an additional `blue` flavor for dimension `color`. This is
+ // not in this producer to test baseline profile matching fallback.
}
targetProjectPath = ":benchmark:integration-tests:baselineprofile-flavors-consumer"
namespace "androidx.benchmark.integration.baselineprofile.flavors.producer"
diff --git a/benchmark/integration-tests/macrobenchmark-target/build.gradle b/benchmark/integration-tests/macrobenchmark-target/build.gradle
index d455803..10a09b7 100644
--- a/benchmark/integration-tests/macrobenchmark-target/build.gradle
+++ b/benchmark/integration-tests/macrobenchmark-target/build.gradle
@@ -35,6 +35,7 @@
implementation(libs.kotlinStdlib)
implementation(libs.constraintLayout)
implementation(project(":appcompat:appcompat"))
+ implementation(project(":benchmark:benchmark-internal"))
implementation(project(":activity:activity"))
implementation(project(":profileinstaller:profileinstaller"))
implementation(project(":recyclerview:recyclerview"))
diff --git a/biometric/integration-tests/testapp/src/main/AndroidManifest.xml b/biometric/integration-tests/testapp/src/main/AndroidManifest.xml
index 18e63d8..6d3cb6c 100644
--- a/biometric/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/biometric/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -39,12 +39,14 @@
android:name=".BiometricPromptTestActivity"
android:label="@string/biometric_prompt_test_title"
android:exported="false"
- android:theme="@style/Theme.AppCompat.Light" />
+ android:theme="@style/Theme.AppCompat.Light"
+ android:screenOrientation="fullSensor" />
<activity
android:name=".AuthPromptTestActivity"
android:label="@string/auth_prompt_test_title"
android:exported="false"
- android:theme="@style/Theme.AppCompat.Light" />
+ android:theme="@style/Theme.AppCompat.Light"
+ android:screenOrientation="fullSensor" />
</application>
</manifest>
\ No newline at end of file
diff --git a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothGattCharacteristicTest.kt b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothGattCharacteristicTest.kt
index fe2a87b..7dfbbd3 100644
--- a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothGattCharacteristicTest.kt
+++ b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothGattCharacteristicTest.kt
@@ -16,9 +16,7 @@
package androidx.bluetooth
-import android.bluetooth.BluetoothGattCharacteristic.PERMISSION_READ
-import android.bluetooth.BluetoothGattCharacteristic.PROPERTY_NOTIFY
-import android.bluetooth.BluetoothGattCharacteristic.PROPERTY_READ
+import android.bluetooth.BluetoothGattCharacteristic as FwkBluetoothGattCharacteristic
import java.util.UUID
import org.junit.Assert
import org.junit.Test
@@ -29,19 +27,62 @@
class BluetoothGattCharacteristicTest {
@Test
fun constructorWithFwkInstance() {
- val characteristicUuid = UUID.randomUUID()
- val properties = PROPERTY_READ or PROPERTY_NOTIFY
- val permissions = PERMISSION_READ
-
- val fwkGattCharacteristic = android.bluetooth.BluetoothGattCharacteristic(
- characteristicUuid,
- properties,
- permissions,
+ val propertiesMap = mapOf(
+ FwkBluetoothGattCharacteristic.PROPERTY_BROADCAST to
+ BluetoothGattCharacteristic.PROPERTY_BROADCAST,
+ FwkBluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS to
+ BluetoothGattCharacteristic.PROPERTY_EXTENDS_PROP,
+ FwkBluetoothGattCharacteristic.PROPERTY_INDICATE to
+ BluetoothGattCharacteristic.PROPERTY_INDICATE,
+ FwkBluetoothGattCharacteristic.PROPERTY_NOTIFY
+ to BluetoothGattCharacteristic.PROPERTY_NOTIFY,
+ FwkBluetoothGattCharacteristic.PROPERTY_READ
+ to BluetoothGattCharacteristic.PROPERTY_READ,
+ FwkBluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE
+ to BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE,
+ FwkBluetoothGattCharacteristic.PROPERTY_WRITE
+ to BluetoothGattCharacteristic.PROPERTY_WRITE,
+ FwkBluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE
+ to BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
)
- val gattCharacteristic = BluetoothGattCharacteristic(fwkGattCharacteristic)
- Assert.assertEquals(fwkGattCharacteristic.uuid, gattCharacteristic.uuid)
- Assert.assertEquals(fwkGattCharacteristic.properties, gattCharacteristic.properties)
- Assert.assertEquals(fwkGattCharacteristic.permissions, gattCharacteristic.permissions)
+ val permissionMap = mapOf(
+ FwkBluetoothGattCharacteristic.PERMISSION_READ to
+ BluetoothGattCharacteristic.PERMISSION_READ,
+ FwkBluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED to
+ BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED,
+ FwkBluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED_MITM to
+ BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED_MITM,
+ FwkBluetoothGattCharacteristic.PERMISSION_WRITE to
+ BluetoothGattCharacteristic.PERMISSION_WRITE,
+ FwkBluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED to
+ BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED,
+ FwkBluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM to
+ BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM,
+ FwkBluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED to
+ BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED,
+ FwkBluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED_MITM to
+ BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED_MITM
+ )
+
+ propertiesMap.forEach {
+ val charUuid = UUID.randomUUID()
+ val fwkGattCharacteristic = FwkBluetoothGattCharacteristic(charUuid, it.key,
+ /*permissions=*/0)
+ val gattCharacteristic = BluetoothGattCharacteristic(fwkGattCharacteristic)
+
+ Assert.assertEquals(fwkGattCharacteristic.uuid, gattCharacteristic.uuid)
+ Assert.assertEquals(it.value, gattCharacteristic.properties)
+ }
+
+ permissionMap.forEach {
+ val charUuid = UUID.randomUUID()
+ val fwkGattCharacteristic = FwkBluetoothGattCharacteristic(charUuid,
+ /*properties=*/0, it.key)
+ val gattCharacteristic = BluetoothGattCharacteristic(fwkGattCharacteristic)
+
+ Assert.assertEquals(fwkGattCharacteristic.uuid, gattCharacteristic.uuid)
+ Assert.assertEquals(it.value, gattCharacteristic.permissions)
+ }
}
}
\ No newline at end of file
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattCharacteristic.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattCharacteristic.kt
index cd842d8..89b407b 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattCharacteristic.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattCharacteristic.kt
@@ -16,7 +16,7 @@
package androidx.bluetooth
-import android.bluetooth.BluetoothGattCharacteristic as FwkBluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattCharacteristic as FwkGattCharacteristic
import androidx.annotation.RestrictTo
import java.util.UUID
@@ -25,12 +25,48 @@
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
class BluetoothGattCharacteristic internal constructor(
- internal var characteristic: FwkBluetoothGattCharacteristic
+ internal var characteristic: FwkGattCharacteristic
) {
+ companion object {
+ const val PROPERTY_BROADCAST = FwkGattCharacteristic.PROPERTY_BROADCAST
+ const val PROPERTY_EXTENDS_PROP = FwkGattCharacteristic.PROPERTY_EXTENDED_PROPS
+ const val PROPERTY_INDICATE = FwkGattCharacteristic.PROPERTY_INDICATE
+ const val PROPERTY_NOTIFY = FwkGattCharacteristic.PROPERTY_NOTIFY
+ const val PROPERTY_READ = FwkGattCharacteristic.PROPERTY_READ
+ const val PROPERTY_SIGNED_WRITE = FwkGattCharacteristic.PROPERTY_SIGNED_WRITE
+ const val PROPERTY_WRITE = FwkGattCharacteristic.PROPERTY_WRITE
+ const val PROPERTY_WRITE_NO_RESPONSE = FwkGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE
+
+ const val PERMISSION_READ: Int = FwkGattCharacteristic.PERMISSION_READ
+ const val PERMISSION_READ_ENCRYPTED: Int =
+ FwkGattCharacteristic.PERMISSION_READ_ENCRYPTED
+ const val PERMISSION_READ_ENCRYPTED_MITM: Int =
+ FwkGattCharacteristic.PERMISSION_READ_ENCRYPTED_MITM
+ const val PERMISSION_WRITE: Int = FwkGattCharacteristic.PERMISSION_WRITE
+ const val PERMISSION_WRITE_ENCRYPTED: Int =
+ FwkGattCharacteristic.PERMISSION_WRITE_ENCRYPTED
+ const val PERMISSION_WRITE_ENCRYPTED_MITM: Int =
+ FwkGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM
+ const val PERMISSION_WRITE_SIGNED: Int = FwkGattCharacteristic.PERMISSION_WRITE_SIGNED
+ const val PERMISSION_WRITE_SIGNED_MITM: Int =
+ FwkGattCharacteristic.PERMISSION_WRITE_SIGNED_MITM
+ }
+
+ /**
+ * The UUID of the characteristic
+ */
val uuid: UUID
get() = characteristic.uuid
+
+ /**
+ * The properties of the characteristic
+ */
val properties: Int
get() = characteristic.properties
+
+ /**
+ * The permissions for the characteristic
+ */
val permissions: Int
get() = characteristic.permissions
}
\ No newline at end of file
diff --git a/bluetooth/integration-tests/testapp/build.gradle b/bluetooth/integration-tests/testapp/build.gradle
index 9e3f5fa..a78656b 100644
--- a/bluetooth/integration-tests/testapp/build.gradle
+++ b/bluetooth/integration-tests/testapp/build.gradle
@@ -46,7 +46,7 @@
implementation(libs.kotlinStdlib)
implementation(project(":bluetooth:bluetooth"))
- implementation("androidx.activity:activity-ktx:1.7.1")
+ implementation("androidx.activity:activity-ktx:1.7.2")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation(libs.constraintLayout)
implementation("androidx.core:core-ktx:1.10.1")
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt
index f1989e9..72087b1 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt
@@ -17,11 +17,20 @@
package androidx.bluetooth.integration.testapp
import android.Manifest
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothManager
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.bluetooth.integration.testapp.databinding.ActivityMainBinding
+import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
@@ -30,10 +39,19 @@
class MainActivity : AppCompatActivity() {
- companion object {
+ private companion object {
private const val TAG = "MainActivity"
}
+ private val bluetoothStateBroadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action == BluetoothAdapter.ACTION_STATE_CHANGED) {
+ val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0)
+ isBluetoothEnabled = state == BluetoothAdapter.STATE_ON
+ }
+ }
+ }
+
private val requestBluetoothPermissions =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { perms ->
perms.entries.forEach { permission ->
@@ -41,6 +59,12 @@
}
}
+ private var isBluetoothEnabled: Boolean = false
+ set(value) {
+ field = value
+ binding.layoutBluetoothDisabled.isVisible = value.not()
+ }
+
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
@@ -57,6 +81,27 @@
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
+
+ val bluetoothManager = getSystemService(BluetoothManager::class.java)
+ isBluetoothEnabled = bluetoothManager.adapter.isEnabled
+
+ binding.buttonEnable.setOnClickListener {
+ if (ContextCompat.checkSelfPermission(
+ this, Manifest.permission.BLUETOOTH_CONNECT
+ ) == PackageManager.PERMISSION_GRANTED
+ ) {
+ startActivity(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE))
+ }
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+
+ registerReceiver(
+ bluetoothStateBroadcastReceiver,
+ IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
+ )
}
override fun onResume() {
@@ -72,4 +117,10 @@
)
)
}
+
+ override fun onStop() {
+ super.onStop()
+
+ unregisterReceiver(bluetoothStateBroadcastReceiver)
+ }
}
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/connection/DeviceConnection.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/connection/DeviceConnection.kt
new file mode 100644
index 0000000..7f8eb2c
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/connection/DeviceConnection.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.integration.testapp.data.connection
+
+// TODO(ofy) Migrate to androidx.bluetooth.BluetoothDevice
+// TODO(ofy) Migrate to androidx.bluetooth.BluetoothGattCharacteristic
+// TODO(ofy) Migrate to androidx.bluetooth.BluetoothGattService
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattService
+import java.util.UUID
+import kotlinx.coroutines.Job
+
+class DeviceConnection(
+ val bluetoothDevice: BluetoothDevice
+) {
+ var job: Job? = null
+ var onClickReadCharacteristic: OnClickCharacteristic? = null
+ var onClickWriteCharacteristic: OnClickCharacteristic? = null
+ var status = Status.NOT_CONNECTED
+ var services = emptyList<BluetoothGattService>()
+
+ private val values = mutableMapOf<UUID, ByteArray?>()
+
+ fun storeValueFor(characteristic: BluetoothGattCharacteristic, value: ByteArray?) {
+ values[characteristic.uuid] = value
+ }
+
+ fun valueFor(characteristic: BluetoothGattCharacteristic): ByteArray? {
+ return values[characteristic.uuid]
+ }
+}
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/connection/OnClickCharacteristic.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/connection/OnClickCharacteristic.kt
new file mode 100644
index 0000000..fa5133f
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/connection/OnClickCharacteristic.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.integration.testapp.data.connection
+
+// TODO(ofy) Migrate to androidx.bluetooth.BluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattCharacteristic
+
+interface OnClickCharacteristic {
+ fun onClick(deviceConnection: DeviceConnection, characteristic: BluetoothGattCharacteristic)
+}
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/connection/Status.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/connection/Status.kt
new file mode 100644
index 0000000..4087921
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/connection/Status.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.integration.testapp.data.connection
+
+enum class Status {
+ NOT_CONNECTED,
+ CONNECTING,
+ CONNECTED,
+ CONNECTION_FAILED
+}
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/advertiser/AdvertiserFragment.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/advertiser/AdvertiserFragment.kt
index 193adf1..81554a2 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/advertiser/AdvertiserFragment.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/advertiser/AdvertiserFragment.kt
@@ -41,7 +41,7 @@
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
+import androidx.fragment.app.viewModels
import com.google.android.material.tabs.TabLayout
import java.util.UUID
import kotlinx.coroutines.CoroutineScope
@@ -57,8 +57,6 @@
private const val TAB_ADVERTISER_POSITION = 0
}
- private lateinit var advertiserViewModel: AdvertiserViewModel
-
private lateinit var bluetoothLe: BluetoothLe
// TODO(ofy) Migrate to androidx.bluetooth.BluetoothLe once scan API is in place
@@ -124,9 +122,9 @@
}
}
- private var _binding: FragmentAdvertiserBinding? = null
+ private val viewModel: AdvertiserViewModel by viewModels()
- // This property is only valid between onCreateView and onDestroyView.
+ private var _binding: FragmentAdvertiserBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
@@ -134,8 +132,6 @@
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
- advertiserViewModel = ViewModelProvider(this)[AdvertiserViewModel::class.java]
-
bluetoothLe = BluetoothLe(requireContext())
bluetoothLeExperimental = BluetoothLeExperimental(requireContext())
@@ -145,15 +141,15 @@
binding.tabLayout.addOnTabSelectedListener(onTabSelectedListener)
binding.checkBoxIncludeDeviceName.setOnCheckedChangeListener { _, isChecked ->
- advertiserViewModel.includeDeviceName = isChecked
+ viewModel.includeDeviceName = isChecked
}
binding.checkBoxConnectable.setOnCheckedChangeListener { _, isChecked ->
- advertiserViewModel.connectable = isChecked
+ viewModel.connectable = isChecked
}
binding.checkBoxDiscoverable.setOnCheckedChangeListener { _, isChecked ->
- advertiserViewModel.discoverable = isChecked
+ viewModel.discoverable = isChecked
}
binding.buttonAddData.setOnClickListener {
@@ -171,7 +167,7 @@
}
advertiseDataAdapter = AdvertiseDataAdapter(
- advertiserViewModel.advertiseData,
+ viewModel.advertiseData,
::onClickRemoveAdvertiseData
)
binding.recyclerViewAdvertiseData.adapter = advertiseDataAdapter
@@ -215,9 +211,9 @@
.adapter.name
)
}
- binding.checkBoxIncludeDeviceName.isChecked = advertiserViewModel.includeDeviceName
- binding.checkBoxConnectable.isChecked = advertiserViewModel.connectable
- binding.checkBoxDiscoverable.isChecked = advertiserViewModel.discoverable
+ binding.checkBoxIncludeDeviceName.isChecked = viewModel.includeDeviceName
+ binding.checkBoxConnectable.isChecked = viewModel.connectable
+ binding.checkBoxDiscoverable.isChecked = viewModel.discoverable
}
private fun showDialogFor(title: String) {
@@ -238,7 +234,7 @@
.setPositiveButton(getString(R.string.add)) { _, _ ->
val editTextInput = editText.text.toString()
- advertiserViewModel.serviceUuids.add(UUID.fromString(editTextInput))
+ viewModel.serviceUuids.add(UUID.fromString(editTextInput))
refreshAdvertiseData()
}
.setNegativeButton(getString(R.string.cancel), null)
@@ -263,7 +259,7 @@
UUID.fromString(editTextUuidOrServiceNameInput),
editTextDataHexInput.toByteArray()
)
- advertiserViewModel.serviceDatas.add(serviceData)
+ viewModel.serviceDatas.add(serviceData)
}
.setNegativeButton(getString(R.string.cancel), null)
.create()
@@ -288,7 +284,7 @@
editText16BitCompanyIdentifierInput.toInt(),
editTextDataHexInput.toByteArray()
)
- advertiserViewModel.manufacturerDatas.add(manufacturerData)
+ viewModel.manufacturerDatas.add(manufacturerData)
}
.setNegativeButton(getString(R.string.cancel), null)
.create()
@@ -297,13 +293,13 @@
@SuppressLint("NotifyDataSetChanged")
private fun refreshAdvertiseData() {
- advertiseDataAdapter?.advertiseData = advertiserViewModel.advertiseData
+ advertiseDataAdapter?.advertiseData = viewModel.advertiseData
advertiseDataAdapter?.notifyDataSetChanged()
}
private fun onClickRemoveAdvertiseData(index: Int) {
- advertiserViewModel.removeAdvertiseDataAtIndex(index)
- advertiseDataAdapter?.advertiseData = advertiserViewModel.advertiseData
+ viewModel.removeAdvertiseDataAtIndex(index)
+ advertiseDataAdapter?.advertiseData = viewModel.advertiseData
advertiseDataAdapter?.notifyItemRemoved(index)
}
@@ -313,7 +309,7 @@
advertiseJob = advertiseScope.launch {
isAdvertising = true
- bluetoothLe.advertise(advertiserViewModel.advertiseParams)
+ bluetoothLe.advertise(viewModel.advertiseParams)
.collect {
Log.d(TAG, "AdvertiseResult collected: $it")
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/common/ByteArray.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/common/ByteArray.kt
new file mode 100644
index 0000000..40b8f5b
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/common/ByteArray.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.integration.testapp.ui.common
+
+fun ByteArray.toHexString(): String =
+ joinToString(separator = " ", prefix = "0x") { String.format("%02X", it) }
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/home/HomeFragment.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/home/HomeFragment.kt
index f4e7d85..ef8e022 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/home/HomeFragment.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/home/HomeFragment.kt
@@ -36,7 +36,7 @@
import androidx.bluetooth.integration.testapp.experimental.GattServerCallback
import androidx.bluetooth.integration.testapp.ui.common.ScanResultAdapter
import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
+import androidx.fragment.app.viewModels
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -54,11 +54,9 @@
private lateinit var bluetoothLe: BluetoothLe
- private lateinit var mHomeViewModel: HomeViewModel
+ private val viewModel: HomeViewModel by viewModels()
private var _binding: FragmentHomeBinding? = null
-
- // This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
@@ -66,8 +64,6 @@
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
- mHomeViewModel = ViewModelProvider(this)[HomeViewModel::class.java]
-
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
@@ -132,9 +128,9 @@
Log.d(TAG, "ScanResult collected: $it")
if (it.scanRecord?.serviceUuids?.isEmpty() == false)
- mHomeViewModel.scanResults[it.device.address] = it
- scanResultAdapter?.submitList(mHomeViewModel.scanResults.values.toMutableList())
- scanResultAdapter?.notifyItemInserted(mHomeViewModel.scanResults.size)
+ viewModel.scanResults[it.device.address] = it
+ scanResultAdapter?.submitList(viewModel.scanResults.values.toMutableList())
+ scanResultAdapter?.notifyItemInserted(viewModel.scanResults.size)
}
}
}
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/DeviceServiceCharacteristicsAdapter.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/DeviceServiceCharacteristicsAdapter.kt
new file mode 100644
index 0000000..7804498
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/DeviceServiceCharacteristicsAdapter.kt
@@ -0,0 +1,135 @@
+/*
+ * 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.integration.testapp.ui.scanner
+
+// TODO(ofy) Migrate to androidx.bluetooth.BluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattCharacteristic
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.bluetooth.integration.testapp.R
+import androidx.bluetooth.integration.testapp.data.connection.DeviceConnection
+import androidx.bluetooth.integration.testapp.data.connection.OnClickCharacteristic
+import androidx.bluetooth.integration.testapp.ui.common.toHexString
+import androidx.core.view.isVisible
+import androidx.recyclerview.widget.RecyclerView
+
+class DeviceServiceCharacteristicsAdapter(
+ private val deviceConnection: DeviceConnection,
+ private val characteristics: List<BluetoothGattCharacteristic>,
+ private val onClickReadCharacteristic: OnClickCharacteristic,
+ private val onClickWriteCharacteristic: OnClickCharacteristic
+) : RecyclerView.Adapter<DeviceServiceCharacteristicsAdapter.ViewHolder>() {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val view = LayoutInflater.from(parent.context)
+ .inflate(R.layout.item_device_service_characteristic, parent, false)
+ return ViewHolder(view, onClickReadCharacteristic, onClickWriteCharacteristic)
+ }
+
+ override fun getItemCount(): Int {
+ return characteristics.size
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val characteristic = characteristics[position]
+ holder.bind(deviceConnection, characteristic)
+ }
+
+ inner class ViewHolder(
+ itemView: View,
+ private val onClickReadCharacteristic: OnClickCharacteristic,
+ private val onClickWriteCharacteristic: OnClickCharacteristic
+ ) : RecyclerView.ViewHolder(itemView) {
+
+ private val textViewUuid: TextView = itemView.findViewById(R.id.text_view_uuid)
+ private val textViewProperties: TextView = itemView.findViewById(R.id.text_view_properties)
+
+ private val layoutValue: LinearLayout = itemView.findViewById(R.id.layout_value)
+ private val textViewValue: TextView = itemView.findViewById(R.id.text_view_value)
+
+ private val buttonReadCharacteristic: Button =
+ itemView.findViewById(R.id.button_read_characteristic)
+
+ private val buttonWriteCharacteristic: Button =
+ itemView.findViewById(R.id.button_write_characteristic)
+
+ private var currentDeviceConnection: DeviceConnection? = null
+ private var currentCharacteristic: BluetoothGattCharacteristic? = null
+
+ init {
+ buttonReadCharacteristic.setOnClickListener {
+ currentDeviceConnection?.let { deviceConnection ->
+ currentCharacteristic?.let { characteristic ->
+ onClickReadCharacteristic.onClick(deviceConnection, characteristic)
+ }
+ }
+ }
+
+ buttonWriteCharacteristic.setOnClickListener {
+ currentDeviceConnection?.let { deviceConnection ->
+ currentCharacteristic?.let { characteristic ->
+ onClickWriteCharacteristic.onClick(deviceConnection, characteristic)
+ }
+ }
+ }
+ }
+
+ fun bind(deviceConnection: DeviceConnection, characteristic: BluetoothGattCharacteristic) {
+ currentDeviceConnection = deviceConnection
+ currentCharacteristic = characteristic
+
+ textViewUuid.text = characteristic.uuid.toString()
+
+ val properties = characteristic.properties
+ val context = itemView.context
+
+ val propertiesList = mutableListOf<String>()
+ // TODO(ofy) Update these with BluetoothGattCharacteristic.isReadable, isWriteable, ...
+ if (properties.and(BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) {
+ propertiesList.add(context.getString(R.string.indicate))
+ }
+ if (properties.and(BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
+ propertiesList.add(context.getString(R.string.notify))
+ }
+ val isReadable = properties.and(BluetoothGattCharacteristic.PROPERTY_READ) != 0
+ if (isReadable) {
+ propertiesList.add(context.getString(R.string.read))
+ }
+ val isWriteable = (properties.and(BluetoothGattCharacteristic.PROPERTY_WRITE) != 0 ||
+ properties.and(BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0 ||
+ properties.and(BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE) != 0)
+ if (isWriteable) {
+ propertiesList.add(context.getString(R.string.write))
+ }
+ textViewProperties.text = propertiesList.joinToString()
+
+ buttonReadCharacteristic.isVisible = isReadable
+ buttonWriteCharacteristic.isVisible = isWriteable
+
+ val value = deviceConnection.valueFor(characteristic)
+ layoutValue.isVisible = value != null
+ textViewValue.text = buildString {
+ append("toHexString: " + value?.toHexString() + "\n")
+ append("decodeToString: " + value?.decodeToString())
+ }
+ }
+ }
+}
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/DeviceServicesAdapter.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/DeviceServicesAdapter.kt
index 8e5ab73..d7829b1 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/DeviceServicesAdapter.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/DeviceServicesAdapter.kt
@@ -16,40 +16,60 @@
package androidx.bluetooth.integration.testapp.ui.scanner
-// TODO(ofy) Migrate to androidx.bluetooth.BluetoothGattService once in place
+// TODO(ofy) Migrate to androidx.bluetooth.BluetoothGattService
import android.bluetooth.BluetoothGattService
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.bluetooth.integration.testapp.R
+import androidx.bluetooth.integration.testapp.data.connection.DeviceConnection
+import androidx.bluetooth.integration.testapp.data.connection.OnClickCharacteristic
import androidx.recyclerview.widget.RecyclerView
-class DeviceServicesAdapter(var services: List<BluetoothGattService>) :
- RecyclerView.Adapter<DeviceServicesAdapter.ViewHolder>() {
+class DeviceServicesAdapter(
+ var deviceConnection: DeviceConnection? = null,
+ private val onClickReadCharacteristic: OnClickCharacteristic,
+ private val onClickWriteCharacteristic: OnClickCharacteristic
+) : RecyclerView.Adapter<DeviceServicesAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_device_service, parent, false)
- return ViewHolder(view)
+ return ViewHolder(view, onClickReadCharacteristic, onClickWriteCharacteristic)
}
override fun getItemCount(): Int {
- return services.size
+ return deviceConnection?.services.orEmpty().size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val service = services[position]
- holder.bind(service)
+ deviceConnection?.let {
+ val service = it.services[position]
+ holder.bind(it, service)
+ }
}
- inner class ViewHolder(itemView: View) :
- RecyclerView.ViewHolder(itemView) {
+ inner class ViewHolder(
+ itemView: View,
+ private val onClickReadCharacteristic: OnClickCharacteristic,
+ private val onClickWriteCharacteristic: OnClickCharacteristic
+ ) : RecyclerView.ViewHolder(itemView) {
private val textViewUuid: TextView = itemView.findViewById(R.id.text_view_uuid)
- fun bind(service: BluetoothGattService) {
+ private val recyclerViewServiceCharacteristic: RecyclerView =
+ itemView.findViewById(R.id.recycler_view_service_characteristic)
+
+ fun bind(deviceConnection: DeviceConnection, service: BluetoothGattService) {
textViewUuid.text = service.uuid.toString()
+
+ recyclerViewServiceCharacteristic.adapter = DeviceServiceCharacteristicsAdapter(
+ deviceConnection,
+ service.characteristics,
+ onClickReadCharacteristic,
+ onClickWriteCharacteristic
+ )
}
}
}
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerAdapter.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerAdapter.kt
index 6f8ca9f..3b59942 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerAdapter.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerAdapter.kt
@@ -16,6 +16,8 @@
package androidx.bluetooth.integration.testapp.ui.scanner
+// TODO(ofy) Migrate to androidx.bluetooth.BluetoothDevice
+// TODO(ofy) Migrate to androidx.bluetooth.ScanResult
import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice
import android.bluetooth.le.ScanResult
@@ -30,8 +32,9 @@
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
-class ScannerAdapter(private val onClick: (BluetoothDevice) -> Unit) :
- ListAdapter<ScanResult, ScannerAdapter.ViewHolder>(ScannerDiffCallback) {
+class ScannerAdapter(
+ private val onClick: (BluetoothDevice) -> Unit
+) : ListAdapter<ScanResult, ScannerAdapter.ViewHolder>(ScannerDiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
@@ -44,8 +47,10 @@
holder.bind(scanResult.device)
}
- inner class ViewHolder(itemView: View, private val onClick: (BluetoothDevice) -> Unit) :
- RecyclerView.ViewHolder(itemView) {
+ inner class ViewHolder(
+ itemView: View,
+ private val onClick: (BluetoothDevice) -> Unit
+ ) : RecyclerView.ViewHolder(itemView) {
private val textViewDeviceName: TextView = itemView.findViewById(R.id.text_view_device_name)
private val textViewDeviceAddress: TextView =
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerFragment.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerFragment.kt
index 485c94c..209e95a 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerFragment.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerFragment.kt
@@ -16,9 +16,12 @@
package androidx.bluetooth.integration.testapp.ui.scanner
-// TODO(ofy) Migrate to androidx.bluetooth.BluetoothLe once scan API is in place
+// TODO(ofy) Migrate to androidx.bluetooth.AdvertiseParams
+// TODO(ofy) Migrate to androidx.bluetooth.BluetoothDevice
+// TODO(ofy) Migrate to androidx.bluetooth.BluetoothGattCharacteristic
import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.le.ScanSettings
import android.os.Bundle
import android.util.Log
@@ -26,46 +29,50 @@
import android.view.View
import android.view.ViewGroup
import android.widget.Button
+import android.widget.EditText
import android.widget.TextView
+import androidx.appcompat.app.AlertDialog
import androidx.bluetooth.integration.testapp.R
+import androidx.bluetooth.integration.testapp.data.connection.DeviceConnection
+import androidx.bluetooth.integration.testapp.data.connection.OnClickCharacteristic
+import androidx.bluetooth.integration.testapp.data.connection.Status
import androidx.bluetooth.integration.testapp.databinding.FragmentScannerBinding
import androidx.bluetooth.integration.testapp.experimental.BluetoothLe
import androidx.bluetooth.integration.testapp.ui.common.getColor
+import androidx.bluetooth.integration.testapp.ui.common.toast
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
+import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.Tab
-import java.lang.Exception
+import kotlin.coroutines.cancellation.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
class ScannerFragment : Fragment() {
- private companion object {
+ internal companion object {
private const val TAG = "ScannerFragment"
private const val TAB_RESULTS_POSITION = 0
- }
- private lateinit var scannerViewModel: ScannerViewModel
+ internal const val MANUAL_DISCONNECT = "MANUAL_DISCONNECT"
+ }
// TODO(ofy) Migrate to androidx.bluetooth.BluetoothLe once scan API is in place
private lateinit var bluetoothLe: BluetoothLe
- private var scannerAdapter: ScannerAdapter? = null
-
private var deviceServicesAdapter: DeviceServicesAdapter? = null
private val scanScope = CoroutineScope(Dispatchers.Main + Job())
private var scanJob: Job? = null
private val connectScope = CoroutineScope(Dispatchers.Default + Job())
- private var connectJob: Job? = null
private var isScanning: Boolean = false
set(value) {
@@ -92,7 +99,7 @@
override fun onTabSelected(tab: Tab) {
showingScanResults = tab.position == TAB_RESULTS_POSITION
if (tab.position != TAB_RESULTS_POSITION) {
- updateDeviceUI(scannerViewModel.deviceConnection(tab.position))
+ updateDeviceUI(viewModel.deviceConnection(tab.position))
}
}
@@ -103,9 +110,27 @@
}
}
- private var _binding: FragmentScannerBinding? = null
+ private val onClickReadCharacteristic = object : OnClickCharacteristic {
+ override fun onClick(
+ deviceConnection: DeviceConnection,
+ characteristic: BluetoothGattCharacteristic
+ ) {
+ deviceConnection.onClickReadCharacteristic?.onClick(deviceConnection, characteristic)
+ }
+ }
- // This property is only valid between onCreateView and onDestroyView.
+ private val onClickWriteCharacteristic = object : OnClickCharacteristic {
+ override fun onClick(
+ deviceConnection: DeviceConnection,
+ characteristic: BluetoothGattCharacteristic
+ ) {
+ deviceConnection.onClickWriteCharacteristic?.onClick(deviceConnection, characteristic)
+ }
+ }
+
+ private val viewModel: ScannerViewModel by viewModels()
+
+ private var _binding: FragmentScannerBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
@@ -113,21 +138,25 @@
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
- scannerViewModel = ViewModelProvider(this)[ScannerViewModel::class.java]
+ _binding = FragmentScannerBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
bluetoothLe = BluetoothLe(requireContext())
- _binding = FragmentScannerBinding.inflate(inflater, container, false)
-
binding.tabLayout.addOnTabSelectedListener(onTabSelectedListener)
- scannerAdapter = ScannerAdapter { bluetoothDevice -> onClickScanResult(bluetoothDevice) }
+ val scannerAdapter = ScannerAdapter(::onClickScanResult)
binding.recyclerViewScanResults.adapter = scannerAdapter
binding.recyclerViewScanResults.addItemDecoration(
DividerItemDecoration(context, LinearLayoutManager.VERTICAL)
)
- deviceServicesAdapter = DeviceServicesAdapter(emptyList())
+ deviceServicesAdapter =
+ DeviceServicesAdapter(null, onClickReadCharacteristic, onClickWriteCharacteristic)
binding.recyclerViewDeviceServices.adapter = deviceServicesAdapter
binding.recyclerViewDeviceServices.addItemDecoration(
DividerItemDecoration(context, LinearLayoutManager.VERTICAL)
@@ -142,12 +171,17 @@
}
binding.buttonReconnect.setOnClickListener {
- connectTo(scannerViewModel.deviceConnection(binding.tabLayout.selectedTabPosition))
+ connectTo(viewModel.deviceConnection(binding.tabLayout.selectedTabPosition))
}
- initData()
+ binding.buttonDisconnect.setOnClickListener {
+ disconnect(viewModel.deviceConnection(binding.tabLayout.selectedTabPosition))
+ }
- return binding.root
+ viewModel.scanResults
+ .observe(viewLifecycleOwner) { scannerAdapter.submitList(it) }
+
+ initData()
}
override fun onDestroyView() {
@@ -157,10 +191,7 @@
}
private fun initData() {
- scannerAdapter?.submitList(scannerViewModel.scanResults)
- scannerAdapter?.notifyItemRangeChanged(0, scannerViewModel.scanResults.size)
-
- scannerViewModel.deviceConnections.map { it.bluetoothDevice }.forEach(::addNewTab)
+ viewModel.deviceConnections.map { it.bluetoothDevice }.forEach(::addNewTab)
}
private fun startScan() {
@@ -175,10 +206,7 @@
.collect {
Log.d(TAG, "ScanResult collected: $it")
- if (scannerViewModel.addScanResultIfNew(it)) {
- scannerAdapter?.submitList(scannerViewModel.scanResults)
- scannerAdapter?.notifyItemInserted(scannerViewModel.scanResults.size)
- }
+ viewModel.addScanResultIfNew(it)
}
}
}
@@ -186,7 +214,7 @@
private fun onClickScanResult(bluetoothDevice: BluetoothDevice) {
isScanning = false
- val index = scannerViewModel.addDeviceConnectionIfNew(bluetoothDevice)
+ val index = viewModel.addDeviceConnectionIfNew(bluetoothDevice)
val deviceTab = if (index == ScannerViewModel.NEW_DEVICE) {
addNewTab(bluetoothDevice)
@@ -201,7 +229,7 @@
showingScanResults = false
- connectTo(scannerViewModel.deviceConnection(binding.tabLayout.selectedTabPosition))
+ connectTo(viewModel.deviceConnection(binding.tabLayout.selectedTabPosition))
}
@SuppressLint("MissingPermission")
@@ -218,7 +246,7 @@
textViewName?.text = deviceName
textViewName?.isVisible = deviceName.isNullOrEmpty().not()
customView?.findViewById<Button>(R.id.image_button_remove)?.setOnClickListener {
- scannerViewModel.remove(bluetoothDevice)
+ viewModel.remove(bluetoothDevice)
binding.tabLayout.removeTab(newTab)
}
@@ -229,7 +257,7 @@
private fun connectTo(deviceConnection: DeviceConnection) {
Log.d(TAG, "connectTo() called with: deviceConnection = $deviceConnection")
- connectJob = connectScope.launch {
+ deviceConnection.job = connectScope.launch {
deviceConnection.status = Status.CONNECTING
launch(Dispatchers.Main) {
updateDeviceUI(deviceConnection)
@@ -237,34 +265,113 @@
try {
bluetoothLe.connectGatt(requireContext(), deviceConnection.bluetoothDevice) {
- Log.d(TAG, "connectGatt result. getServices() = ${getServices()}")
+ Log.d(TAG, "connectGatt result: getServices() = ${getServices()}")
deviceConnection.status = Status.CONNECTED
deviceConnection.services = getServices()
launch(Dispatchers.Main) {
updateDeviceUI(deviceConnection)
}
+
+ // TODO(ofy) Improve this. Remove OnClickCharacteristic as it's not ideal
+ // to hold so many OnClickCharacteristic and difficult to use with Compose.
+ deviceConnection.onClickReadCharacteristic =
+ object : OnClickCharacteristic {
+ override fun onClick(
+ deviceConnection: DeviceConnection,
+ characteristic: BluetoothGattCharacteristic
+ ) {
+ connectScope.launch {
+ val result = readCharacteristic(characteristic)
+ Log.d(TAG, "readCharacteristic() called with: result = $result")
+
+ deviceConnection.storeValueFor(
+ characteristic,
+ result.getOrNull()
+ )
+ launch(Dispatchers.Main) {
+ updateDeviceUI(deviceConnection)
+ }
+ }
+ }
+ }
+
+ // TODO(ofy) Improve this. Remove OnClickCharacteristic as it's not ideal
+ // to hold so many OnClickCharacteristic and difficult to use with Compose.
+ deviceConnection.onClickWriteCharacteristic =
+ object : OnClickCharacteristic {
+ override fun onClick(
+ deviceConnection: DeviceConnection,
+ characteristic: BluetoothGattCharacteristic
+ ) {
+ val view = layoutInflater.inflate(
+ R.layout.dialog_write_characteristic,
+ null
+ )
+ val editTextValue =
+ view.findViewById<EditText>(R.id.edit_text_value)
+
+ AlertDialog.Builder(requireContext())
+ .setTitle(getString(R.string.write))
+ .setView(view)
+ .setPositiveButton(getString(R.string.write)) { _, _ ->
+ val editTextValueString = editTextValue.text.toString()
+ val value = editTextValueString.toByteArray()
+
+ connectScope.launch {
+ val result = writeCharacteristic(
+ characteristic,
+ value,
+ BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
+ )
+ Log.d(TAG, "writeCharacteristic() called with: " +
+ "result = $result")
+ launch(Dispatchers.Main) {
+ toast("Called write with: `$editTextValueString`")
+ .show()
+ }
+ }
+ }
+ .setNegativeButton(getString(R.string.cancel), null)
+ .create()
+ .show()
+ }
+ }
}
} catch (exception: Exception) {
- Log.e(TAG, "connectTo: exception", exception)
-
- deviceConnection.status = Status.CONNECTION_FAILED
- launch(Dispatchers.Main) {
- updateDeviceUI(deviceConnection)
+ if (exception is CancellationException) {
+ Log.d(TAG, "connectGatt() CancellationException")
+ } else {
+ Log.e(TAG, "connectGatt() exception", exception)
+ deviceConnection.status = Status.CONNECTION_FAILED
+ launch(Dispatchers.Main) {
+ updateDeviceUI(deviceConnection)
+ }
}
}
}
}
+ private fun disconnect(deviceConnection: DeviceConnection) {
+ Log.d(TAG, "disconnect() called with: deviceConnection = $deviceConnection")
+
+ deviceConnection.job?.cancel(MANUAL_DISCONNECT)
+ deviceConnection.job = null
+ deviceConnection.status = Status.NOT_CONNECTED
+ updateDeviceUI(deviceConnection)
+ }
+
@SuppressLint("NotifyDataSetChanged")
private fun updateDeviceUI(deviceConnection: DeviceConnection) {
binding.progressIndicatorDeviceConnection.isVisible = false
binding.buttonReconnect.isVisible = false
+ binding.buttonDisconnect.isVisible = false
when (deviceConnection.status) {
Status.NOT_CONNECTED -> {
binding.textViewDeviceConnectionStatus.text = getString(R.string.not_connected)
binding.textViewDeviceConnectionStatus.setTextColor(getColor(R.color.green_500))
+ binding.buttonReconnect.isVisible = true
}
Status.CONNECTING -> {
binding.progressIndicatorDeviceConnection.isVisible = true
@@ -274,6 +381,7 @@
Status.CONNECTED -> {
binding.textViewDeviceConnectionStatus.text = getString(R.string.connected)
binding.textViewDeviceConnectionStatus.setTextColor(getColor(R.color.indigo_500))
+ binding.buttonDisconnect.isVisible = true
}
Status.CONNECTION_FAILED -> {
binding.textViewDeviceConnectionStatus.text = getString(R.string.connection_failed)
@@ -281,7 +389,7 @@
binding.buttonReconnect.isVisible = true
}
}
- deviceServicesAdapter?.services = deviceConnection.services
+ deviceServicesAdapter?.deviceConnection = deviceConnection
deviceServicesAdapter?.notifyDataSetChanged()
}
}
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerViewModel.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerViewModel.kt
index 9e15997..906188a 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerViewModel.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerViewModel.kt
@@ -16,11 +16,15 @@
package androidx.bluetooth.integration.testapp.ui.scanner
+// TODO(ofy) Migrate to androidx.bluetooth.BluetoothDevice
// TODO(ofy) Migrate to androidx.bluetooth.ScanResult once in place
import android.bluetooth.BluetoothDevice
-import android.bluetooth.BluetoothGattService
import android.bluetooth.le.ScanResult
+import androidx.bluetooth.integration.testapp.data.connection.DeviceConnection
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
+import kotlinx.coroutines.cancel
class ScannerViewModel : ViewModel() {
@@ -30,21 +34,27 @@
internal const val NEW_DEVICE = -1
}
- internal val scanResults: List<ScanResult> get() = _scanResults.values.toList()
- private val _scanResults = mutableMapOf<String, ScanResult>()
+ val scanResults: LiveData<List<ScanResult>>
+ get() = _scanResults
+ private val _scanResults = MutableLiveData<List<ScanResult>>()
+ private val _scanResultsMap = mutableMapOf<String, ScanResult>()
internal val deviceConnections: Set<DeviceConnection> get() = _deviceConnections
private val _deviceConnections = mutableSetOf<DeviceConnection>()
- fun addScanResultIfNew(scanResult: ScanResult): Boolean {
+ override fun onCleared() {
+ super.onCleared()
+
+ _deviceConnections.forEach { it.job?.cancel() }
+ }
+
+ fun addScanResultIfNew(scanResult: ScanResult) {
val deviceAddress = scanResult.device.address
- if (_scanResults.containsKey(deviceAddress)) {
- return false
+ if (_scanResultsMap.containsKey(deviceAddress).not()) {
+ _scanResultsMap[deviceAddress] = scanResult
+ _scanResults.value = _scanResultsMap.values.toList()
}
-
- _scanResults[deviceAddress] = scanResult
- return true
}
fun addDeviceConnectionIfNew(bluetoothDevice: BluetoothDevice): Int {
@@ -62,6 +72,8 @@
fun remove(bluetoothDevice: BluetoothDevice) {
val deviceConnection = _deviceConnections.find { it.bluetoothDevice == bluetoothDevice }
+ deviceConnection?.job?.cancel(ScannerFragment.MANUAL_DISCONNECT)
+ deviceConnection?.job = null
_deviceConnections.remove(deviceConnection)
}
@@ -71,14 +83,3 @@
return deviceConnections.elementAt(position - 1)
}
}
-
-class DeviceConnection(
- val bluetoothDevice: BluetoothDevice
-) {
- var status = Status.NOT_CONNECTED
- var services = emptyList<BluetoothGattService>()
-}
-
-enum class Status {
- NOT_CONNECTED, CONNECTING, CONNECTED, CONNECTION_FAILED
-}
diff --git a/bluetooth/integration-tests/testapp/src/main/res/layout/activity_main.xml b/bluetooth/integration-tests/testapp/src/main/res/layout/activity_main.xml
index 5d9372f..2ffebe8 100644
--- a/bluetooth/integration-tests/testapp/src/main/res/layout/activity_main.xml
+++ b/bluetooth/integration-tests/testapp/src/main/res/layout/activity_main.xml
@@ -47,4 +47,38 @@
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
+ <LinearLayout
+ android:id="@+id/layout_bluetooth_disabled"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/red_500"
+ android:gravity="center_vertical"
+ android:paddingStart="16dp"
+ android:paddingTop="8dp"
+ android:paddingEnd="16dp"
+ android:paddingBottom="8dp"
+ android:visibility="gone"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:visibility="visible">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bluetooth_is_disabled"
+ android:textColor="@color/white"
+ android:textSize="19sp" />
+
+ <View
+ android:layout_width="0dp"
+ android:layout_height="1dp"
+ android:layout_weight="1" />
+
+ <Button
+ android:id="@+id/button_enable"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/enable" />
+
+ </LinearLayout>
+
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/bluetooth/integration-tests/testapp/src/main/res/layout/dialog_write_characteristic.xml b/bluetooth/integration-tests/testapp/src/main/res/layout/dialog_write_characteristic.xml
new file mode 100644
index 0000000..c61798e
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/res/layout/dialog_write_characteristic.xml
@@ -0,0 +1,42 @@
+<?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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dp"
+ android:paddingTop="8dp"
+ android:paddingEnd="16dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="0x"
+ android:textColor="@color/black"
+ android:textSize="21sp"
+ tools:ignore="HardcodedText" />
+
+ <EditText
+ android:id="@+id/edit_text_value"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp"
+ android:hint="@string/value"
+ android:inputType="text" />
+
+</LinearLayout>
diff --git a/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_scanner.xml b/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_scanner.xml
index dc4f3a1..674759b 100644
--- a/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_scanner.xml
+++ b/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_scanner.xml
@@ -68,7 +68,10 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
- android:padding="16dp"
+ android:paddingStart="16dp"
+ android:paddingTop="8dp"
+ android:paddingEnd="16dp"
+ android:paddingBottom="8dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tab_layout"
@@ -109,6 +112,13 @@
android:text="@string/reconnect"
android:visibility="gone" />
+ <Button
+ android:id="@+id/button_disconnect"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/disconnect"
+ android:visibility="gone" />
+
</LinearLayout>
<View
diff --git a/bluetooth/integration-tests/testapp/src/main/res/layout/item_device_service.xml b/bluetooth/integration-tests/testapp/src/main/res/layout/item_device_service.xml
index cb091804..6a7aa85 100644
--- a/bluetooth/integration-tests/testapp/src/main/res/layout/item_device_service.xml
+++ b/bluetooth/integration-tests/testapp/src/main/res/layout/item_device_service.xml
@@ -15,6 +15,7 @@
limitations under the License.
-->
<LinearLayout 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="wrap_content"
@@ -25,13 +26,29 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/generic_attribute"
- android:textColor="#000000" />
+ android:textColor="@color/black"
+ android:textStyle="bold" />
- <TextView
- android:id="@+id/text_view_uuid"
- android:layout_width="match_parent"
+ <LinearLayout
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- tools:text="UUID: 0x1800" />
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/uuid"
+ android:textAllCaps="true" />
+
+ <TextView
+ android:id="@+id/text_view_uuid"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:textColor="@color/black"
+ tools:text="0x1800" />
+
+ </LinearLayout>
<TextView
android:layout_width="match_parent"
@@ -39,4 +56,13 @@
android:text="@string/primary_service"
android:textAllCaps="true" />
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/recycler_view_service_characteristic"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ app:layoutManager="LinearLayoutManager"
+ tools:itemCount="3"
+ tools:listitem="@layout/item_device_service_characteristic" />
+
</LinearLayout>
diff --git a/bluetooth/integration-tests/testapp/src/main/res/layout/item_device_service_characteristic.xml b/bluetooth/integration-tests/testapp/src/main/res/layout/item_device_service_characteristic.xml
new file mode 100644
index 0000000..2d63d34
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/res/layout/item_device_service_characteristic.xml
@@ -0,0 +1,110 @@
+<?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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="8dp">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/uuid"
+ android:textAllCaps="true" />
+
+ <TextView
+ android:id="@+id/text_view_uuid"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:textColor="@color/black"
+ tools:text="0x1800" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/properties" />
+
+ <TextView
+ android:id="@+id/text_view_properties"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:textAllCaps="true"
+ android:textColor="@color/black"
+ tools:text="@string/read" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/layout_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/value" />
+
+ <TextView
+ android:id="@+id/text_view_value"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:textColor="@color/black"
+ tools:text="(0x) 01" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ tools:ignore="ButtonStyle">
+
+ <Button
+ android:id="@+id/button_read_characteristic"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/read" />
+
+ <Button
+ android:id="@+id/button_write_characteristic"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:text="@string/write" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml b/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
index cab9c9f..8c164df 100644
--- a/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
+++ b/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
@@ -21,19 +21,31 @@
<string name="title_scanner">Scanner</string>
<string name="title_advertiser">Advertiser</string>
+ <!-- Main -->
+ <string name="bluetooth_is_disabled">Bluetooth is disabled</string>
+ <string name="enable">Enable</string>
+
<!-- Scanner -->
<string name="start_scanning">Start Scanning</string>
<string name="stop_scanning">Stop scanning</string>
<string name="scan_result_icon">Scan Result Icon</string>
<string name="connect">Connect</string>
<string name="reconnect">Reconnect</string>
+ <string name="disconnect">Disconnect</string>
<string name="scan_results">Scan Results</string>
<string name="not_connected">Not Connected</string>
<string name="connecting">Connecting…</string>
<string name="connected">Connected</string>
<string name="connection_failed">Connection Failed</string>
<string name="generic_attribute">Generic Attribute</string>
+ <string name="uuid">uuid</string>
+ <string name="properties">Properties</string>
<string name="primary_service">Primary Service</string>
+ <string name="indicate">Indicate</string>
+ <string name="notify">Notify</string>
+ <string name="read">Read</string>
+ <string name="write">Write</string>
+ <string name="value">Value</string>
<!-- Advertiser -->
<string name="configure_advertising_packet">Configure Advertising Packet</string>
diff --git a/browser/browser/api/aidlRelease/current/android/support/customtabs/ICustomTabsService.aidl b/browser/browser/api/aidlRelease/current/android/support/customtabs/ICustomTabsService.aidl
index e289f12..18d2223 100644
--- a/browser/browser/api/aidlRelease/current/android/support/customtabs/ICustomTabsService.aidl
+++ b/browser/browser/api/aidlRelease/current/android/support/customtabs/ICustomTabsService.aidl
@@ -47,5 +47,4 @@
boolean receiveFile(in android.support.customtabs.ICustomTabsCallback callback, in android.net.Uri uri, int purpose, in android.os.Bundle extras) = 11;
boolean isEngagementSignalsApiAvailable(in android.support.customtabs.ICustomTabsCallback customTabsCallback, in android.os.Bundle extras) = 12;
boolean setEngagementSignalsCallback(in android.support.customtabs.ICustomTabsCallback customTabsCallback, in IBinder callback, in android.os.Bundle extras) = 13;
- int getGreatestScrollPercentage(in android.support.customtabs.ICustomTabsCallback customTabsCallback, in android.os.Bundle extras) = 14;
}
diff --git a/browser/browser/api/current.txt b/browser/browser/api/current.txt
index 5b284c8..81804aa 100644
--- a/browser/browser/api/current.txt
+++ b/browser/browser/api/current.txt
@@ -195,7 +195,6 @@
ctor public CustomTabsService();
method protected boolean cleanUpSession(androidx.browser.customtabs.CustomTabsSessionToken);
method protected abstract android.os.Bundle? extraCommand(String, android.os.Bundle?);
- method @IntRange(from=0, to=100) protected int getGreatestScrollPercentage(androidx.browser.customtabs.CustomTabsSessionToken, android.os.Bundle);
method protected boolean isEngagementSignalsApiAvailable(androidx.browser.customtabs.CustomTabsSessionToken, android.os.Bundle);
method protected abstract boolean mayLaunchUrl(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri?, android.os.Bundle?, java.util.List<android.os.Bundle!>?);
method protected abstract boolean newSession(androidx.browser.customtabs.CustomTabsSessionToken);
@@ -203,6 +202,7 @@
method @androidx.browser.customtabs.CustomTabsService.Result protected abstract int postMessage(androidx.browser.customtabs.CustomTabsSessionToken, String, android.os.Bundle?);
method protected abstract boolean receiveFile(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri, int, android.os.Bundle?);
method protected abstract boolean requestPostMessageChannel(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri);
+ method protected boolean requestPostMessageChannel(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri, android.net.Uri?, android.os.Bundle);
method protected boolean setEngagementSignalsCallback(androidx.browser.customtabs.CustomTabsSessionToken, androidx.browser.customtabs.EngagementSignalsCallback, android.os.Bundle);
method protected abstract boolean updateVisuals(androidx.browser.customtabs.CustomTabsSessionToken, android.os.Bundle?);
method protected abstract boolean validateRelationship(androidx.browser.customtabs.CustomTabsSessionToken, @androidx.browser.customtabs.CustomTabsService.Relation int, android.net.Uri, android.os.Bundle?);
@@ -238,12 +238,12 @@
public final class CustomTabsSession {
method @VisibleForTesting public static androidx.browser.customtabs.CustomTabsSession createMockSessionForTesting(android.content.ComponentName);
- method @IntRange(from=0, to=100) @RequiresFeature(name=androidx.browser.customtabs.CustomTabsFeatures.ENGAGEMENT_SIGNALS, enforcement="androidx.browser.customtabs.CustomTabsSession#isEngagementSignalsApiAvailable") public int getGreatestScrollPercentage(android.os.Bundle) throws android.os.RemoteException;
method public boolean isEngagementSignalsApiAvailable(android.os.Bundle) throws android.os.RemoteException;
method public boolean mayLaunchUrl(android.net.Uri?, android.os.Bundle?, java.util.List<android.os.Bundle!>?);
method @androidx.browser.customtabs.CustomTabsService.Result public int postMessage(String, android.os.Bundle?);
method public boolean receiveFile(android.net.Uri, int, android.os.Bundle?);
method public boolean requestPostMessageChannel(android.net.Uri);
+ method public boolean requestPostMessageChannel(android.net.Uri, android.net.Uri?, android.os.Bundle);
method public boolean setActionButton(android.graphics.Bitmap, String);
method @RequiresFeature(name=androidx.browser.customtabs.CustomTabsFeatures.ENGAGEMENT_SIGNALS, enforcement="androidx.browser.customtabs.CustomTabsSession#isEngagementSignalsApiAvailable") public boolean setEngagementSignalsCallback(androidx.browser.customtabs.EngagementSignalsCallback, android.os.Bundle) throws android.os.RemoteException;
method @RequiresFeature(name=androidx.browser.customtabs.CustomTabsFeatures.ENGAGEMENT_SIGNALS, enforcement="androidx.browser.customtabs.CustomTabsSession#isEngagementSignalsApiAvailable") public boolean setEngagementSignalsCallback(java.util.concurrent.Executor, androidx.browser.customtabs.EngagementSignalsCallback, android.os.Bundle) throws android.os.RemoteException;
diff --git a/browser/browser/api/restricted_current.txt b/browser/browser/api/restricted_current.txt
index 3862b78..30e1d8e 100644
--- a/browser/browser/api/restricted_current.txt
+++ b/browser/browser/api/restricted_current.txt
@@ -206,7 +206,6 @@
ctor public CustomTabsService();
method protected boolean cleanUpSession(androidx.browser.customtabs.CustomTabsSessionToken);
method protected abstract android.os.Bundle? extraCommand(String, android.os.Bundle?);
- method @IntRange(from=0, to=100) protected int getGreatestScrollPercentage(androidx.browser.customtabs.CustomTabsSessionToken, android.os.Bundle);
method protected boolean isEngagementSignalsApiAvailable(androidx.browser.customtabs.CustomTabsSessionToken, android.os.Bundle);
method protected abstract boolean mayLaunchUrl(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri?, android.os.Bundle?, java.util.List<android.os.Bundle!>?);
method protected abstract boolean newSession(androidx.browser.customtabs.CustomTabsSessionToken);
@@ -214,6 +213,7 @@
method @androidx.browser.customtabs.CustomTabsService.Result protected abstract int postMessage(androidx.browser.customtabs.CustomTabsSessionToken, String, android.os.Bundle?);
method protected abstract boolean receiveFile(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri, int, android.os.Bundle?);
method protected abstract boolean requestPostMessageChannel(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri);
+ method protected boolean requestPostMessageChannel(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri, android.net.Uri?, android.os.Bundle);
method protected boolean setEngagementSignalsCallback(androidx.browser.customtabs.CustomTabsSessionToken, androidx.browser.customtabs.EngagementSignalsCallback, android.os.Bundle);
method protected abstract boolean updateVisuals(androidx.browser.customtabs.CustomTabsSessionToken, android.os.Bundle?);
method protected abstract boolean validateRelationship(androidx.browser.customtabs.CustomTabsSessionToken, @androidx.browser.customtabs.CustomTabsService.Relation int, android.net.Uri, android.os.Bundle?);
@@ -249,12 +249,12 @@
public final class CustomTabsSession {
method @VisibleForTesting public static androidx.browser.customtabs.CustomTabsSession createMockSessionForTesting(android.content.ComponentName);
- method @IntRange(from=0, to=100) @RequiresFeature(name=androidx.browser.customtabs.CustomTabsFeatures.ENGAGEMENT_SIGNALS, enforcement="androidx.browser.customtabs.CustomTabsSession#isEngagementSignalsApiAvailable") public int getGreatestScrollPercentage(android.os.Bundle) throws android.os.RemoteException;
method public boolean isEngagementSignalsApiAvailable(android.os.Bundle) throws android.os.RemoteException;
method public boolean mayLaunchUrl(android.net.Uri?, android.os.Bundle?, java.util.List<android.os.Bundle!>?);
method @androidx.browser.customtabs.CustomTabsService.Result public int postMessage(String, android.os.Bundle?);
method public boolean receiveFile(android.net.Uri, int, android.os.Bundle?);
method public boolean requestPostMessageChannel(android.net.Uri);
+ method public boolean requestPostMessageChannel(android.net.Uri, android.net.Uri?, android.os.Bundle);
method public boolean setActionButton(android.graphics.Bitmap, String);
method @RequiresFeature(name=androidx.browser.customtabs.CustomTabsFeatures.ENGAGEMENT_SIGNALS, enforcement="androidx.browser.customtabs.CustomTabsSession#isEngagementSignalsApiAvailable") public boolean setEngagementSignalsCallback(androidx.browser.customtabs.EngagementSignalsCallback, android.os.Bundle) throws android.os.RemoteException;
method @RequiresFeature(name=androidx.browser.customtabs.CustomTabsFeatures.ENGAGEMENT_SIGNALS, enforcement="androidx.browser.customtabs.CustomTabsSession#isEngagementSignalsApiAvailable") public boolean setEngagementSignalsCallback(java.util.concurrent.Executor, androidx.browser.customtabs.EngagementSignalsCallback, android.os.Bundle) throws android.os.RemoteException;
diff --git a/browser/browser/src/androidTest/java/androidx/browser/customtabs/CustomTabsSessionTest.java b/browser/browser/src/androidTest/java/androidx/browser/customtabs/CustomTabsSessionTest.java
index f5e2389..79616dc 100644
--- a/browser/browser/src/androidTest/java/androidx/browser/customtabs/CustomTabsSessionTest.java
+++ b/browser/browser/src/androidTest/java/androidx/browser/customtabs/CustomTabsSessionTest.java
@@ -16,7 +16,6 @@
package androidx.browser.customtabs;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
@@ -80,11 +79,4 @@
verify(mService.getMock()).setEngagementSignalsCallback(any(ICustomTabsCallback.class),
any(IBinder.class), any(Bundle.class));
}
-
- @Test
- public void testGetGreatestScrollPercentage() throws RemoteException {
- when(mService.getMock().getGreatestScrollPercentage(any(ICustomTabsCallback.class),
- any(Bundle.class))).thenReturn(75);
- assertEquals(75, mSession.getGreatestScrollPercentage(Bundle.EMPTY));
- }
}
diff --git a/browser/browser/src/androidTest/java/androidx/browser/customtabs/PostMessageTest.java b/browser/browser/src/androidTest/java/androidx/browser/customtabs/PostMessageTest.java
index ab0d51b..c719cfe 100644
--- a/browser/browser/src/androidTest/java/androidx/browser/customtabs/PostMessageTest.java
+++ b/browser/browser/src/androidTest/java/androidx/browser/customtabs/PostMessageTest.java
@@ -17,6 +17,7 @@
package androidx.browser.customtabs;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -143,4 +144,23 @@
PollingCheck.waitFor(() -> mPostMessageServiceConnected);
assertTrue(mPostMessageServiceConnected);
}
+
+ @Test
+ public void testWithDisallowedTargetOrigin() {
+ PollingCheck.waitFor(() -> mCustomTabsServiceConnected);
+ assertTrue(mCustomTabsServiceConnected);
+ assertFalse(mSession.requestPostMessageChannel(Uri.EMPTY, Uri.parse("www.notallowed.com"),
+ new Bundle()));
+ assertEquals(CustomTabsService.RESULT_FAILURE_DISALLOWED, mSession.postMessage("", null));
+ }
+
+ @Test
+ public void testWithAllowedTargetOrigin() {
+ PollingCheck.waitFor(() -> mCustomTabsServiceConnected);
+ assertTrue(mCustomTabsServiceConnected);
+ assertTrue(mSession.requestPostMessageChannel(Uri.EMPTY,
+ Uri.parse(TestCustomTabsService.ALLOWED_TARGET_ORIGIN),
+ new Bundle()));
+ assertEquals(CustomTabsService.RESULT_SUCCESS, mSession.postMessage("", null));
+ }
}
diff --git a/browser/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsService.java b/browser/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsService.java
index 62bef7e..dad53be 100644
--- a/browser/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsService.java
+++ b/browser/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsService.java
@@ -44,10 +44,10 @@
public class TestCustomTabsService extends CustomTabsService {
public static final String CALLBACK_BIND_TO_POST_MESSAGE = "BindToPostMessageService";
+ public static final String ALLOWED_TARGET_ORIGIN = "www.example.com";
private static TestCustomTabsService sInstance;
private final CountDownLatch mFileReceivingLatch = new CountDownLatch(1);
-
private boolean mPostMessageRequested;
private CustomTabsSessionToken mSession;
private ICustomTabsService mMock;
@@ -106,7 +106,6 @@
Uri postMessageOrigin, Bundle extras) throws RemoteException {
return false;
}
-
@Override
public int postMessage(ICustomTabsCallback callback, String message, Bundle extras)
throws RemoteException {
@@ -136,12 +135,6 @@
IBinder callback, Bundle extras) throws RemoteException {
return mMock.setEngagementSignalsCallback(customTabsCallback, callback, extras);
}
-
- @Override
- public int getGreatestScrollPercentage(ICustomTabsCallback customTabsCallback,
- Bundle extras) throws RemoteException {
- return mMock.getGreatestScrollPercentage(customTabsCallback, extras);
- }
};
@NonNull
@@ -182,7 +175,16 @@
@Override
protected boolean requestPostMessageChannel(
@NonNull CustomTabsSessionToken sessionToken, @NonNull Uri postMessageOrigin) {
+ return requestPostMessageChannel(sessionToken, postMessageOrigin, null, new Bundle());
+ }
+
+ @Override
+ protected boolean requestPostMessageChannel(@NonNull CustomTabsSessionToken sessionToken,
+ @NonNull Uri postMessageOrigin, @Nullable Uri postMessageTargetOrigin,
+ @NonNull Bundle extras) {
if (mSession == null) return false;
+ if (postMessageTargetOrigin != null
+ && !postMessageTargetOrigin.toString().equals(ALLOWED_TARGET_ORIGIN)) return false;
mPostMessageRequested = true;
mSession.getCallback().extraCallback(CALLBACK_BIND_TO_POST_MESSAGE, null);
return true;
diff --git a/browser/browser/src/main/java/androidx/browser/customtabs/Api33Impl.java b/browser/browser/src/main/java/androidx/browser/customtabs/Api33Impl.java
new file mode 100644
index 0000000..ca13623
--- /dev/null
+++ b/browser/browser/src/main/java/androidx/browser/customtabs/Api33Impl.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.browser.customtabs;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import android.os.Bundle;
+
+import androidx.annotation.DoNotInline;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+@RequiresApi(TIRAMISU)
+class Api33Impl {
+ private Api33Impl() {
+ // This class is non-instantiable.
+ }
+
+ @DoNotInline
+ static <T> T getParcelable(@NonNull Bundle in, @Nullable String key,
+ @NonNull Class<T> clazz) {
+ return in.getParcelable(key, clazz);
+ }
+}
diff --git a/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsFeatures.java b/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsFeatures.java
index f2095bf..02c272a 100644
--- a/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsFeatures.java
+++ b/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsFeatures.java
@@ -41,7 +41,6 @@
* This feature covers {@link EngagementSignalsCallback},
* {@link CustomTabsSession#isEngagementSignalsApiAvailable},
* {@link CustomTabsSession#setEngagementSignalsCallback} and
- * {@link CustomTabsSession#getGreatestScrollPercentage}.
*/
public static final String ENGAGEMENT_SIGNALS = "ENGAGEMENT_SIGNALS";
}
diff --git a/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java b/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java
index ee1e791..c843ae8 100644
--- a/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java
+++ b/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java
@@ -20,6 +20,7 @@
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
@@ -28,7 +29,6 @@
import android.support.customtabs.ICustomTabsService;
import androidx.annotation.IntDef;
-import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
@@ -226,7 +226,8 @@
public boolean requestPostMessageChannel(@NonNull ICustomTabsCallback callback,
@NonNull Uri postMessageOrigin) {
return CustomTabsService.this.requestPostMessageChannel(
- new CustomTabsSessionToken(callback, null), postMessageOrigin);
+ new CustomTabsSessionToken(callback, null), postMessageOrigin,
+ null, new Bundle());
}
@Override
@@ -234,7 +235,7 @@
@NonNull Uri postMessageOrigin, @NonNull Bundle extras) {
return CustomTabsService.this.requestPostMessageChannel(
new CustomTabsSessionToken(callback, getSessionIdFromBundle(extras)),
- postMessageOrigin);
+ postMessageOrigin, getTargetOriginFromBundle(extras), extras);
}
@Override
@@ -281,13 +282,6 @@
remote, extras);
}
- @Override
- public int getGreatestScrollPercentage(@NonNull ICustomTabsCallback callback,
- @NonNull Bundle extras) throws RemoteException {
- return CustomTabsService.this.getGreatestScrollPercentage(
- new CustomTabsSessionToken(callback, getSessionIdFromBundle(extras)), extras);
- }
-
@SuppressWarnings("deprecation")
private @Nullable PendingIntent getSessionIdFromBundle(@Nullable Bundle bundle) {
if (bundle == null) return null;
@@ -296,6 +290,17 @@
bundle.remove(CustomTabsIntent.EXTRA_SESSION_ID);
return sessionId;
}
+
+ @SuppressWarnings("deprecation")
+ private @Nullable Uri getTargetOriginFromBundle(@Nullable Bundle bundle) {
+ if (bundle == null) return null;
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ return Api33Impl.getParcelable(bundle, CustomTabsSession.TARGET_ORIGIN_KEY,
+ Uri.class);
+ } else {
+ return bundle.getParcelable(CustomTabsSession.TARGET_ORIGIN_KEY);
+ }
+ }
};
@Override
@@ -434,6 +439,25 @@
@NonNull CustomTabsSessionToken sessionToken, @NonNull Uri postMessageOrigin);
/**
+ * Same as above method with specifying the target origin to establish communication with.
+ *
+ * @param sessionToken The unique identifier for the session. Can not be null.
+ * @param postMessageOrigin A origin that the client is requesting to be identified as
+ * during the postMessage communication.
+ * @param postMessageTargetOrigin The target Origin to establish PostMessageChannel with and
+ * send messages to.
+ * @param extras Reserved for future use.
+ * @return Whether the implementation accepted the request. Note that returning true
+ * here doesn't mean an origin has already been assigned as the validation is
+ * asynchronous.
+ */
+ protected boolean requestPostMessageChannel(
+ @NonNull CustomTabsSessionToken sessionToken, @NonNull Uri postMessageOrigin,
+ @Nullable Uri postMessageTargetOrigin, @NonNull Bundle extras) {
+ return requestPostMessageChannel(sessionToken, postMessageOrigin);
+ }
+
+ /**
* Sends a postMessage request using the origin communicated via
* {@link CustomTabsService#requestPostMessageChannel(
*CustomTabsSessionToken, Uri)}. Fails when called before
@@ -496,8 +520,6 @@
* @param sessionToken The unique identifier for the session.
* @param extras Reserved for future use.
* @return Whether the Engagement Signals API is available. A false value means
- * {@link #getGreatestScrollPercentage} will throw an
- * {@link UnsupportedOperationException} if called, and
* {@link #setEngagementSignalsCallback} will return false and not set the callback.
*/
protected boolean isEngagementSignalsApiAvailable(@NonNull CustomTabsSessionToken sessionToken,
@@ -523,28 +545,4 @@
@NonNull EngagementSignalsCallback callback, @NonNull Bundle extras) {
return false;
}
-
- /**
- * Returns the greatest scroll percentage the user has reached on the page based on the page
- * height at the moment the percentage was reached. This method only returns values that have
- * been or would have been reported by
- * {@link EngagementSignalsCallback#onGreatestScrollPercentageIncreased}, and the percentage
- * is not updated if the page height changes after the last scroll event that caused the
- * greatest scroll percentage to change. The greatest scroll percentage is reset when the user
- * navigates to a different page. Note that an {@link EngagementSignalsCallback} does not need
- * to be registered before calling this method.
- *
- * @param sessionToken The unique identifier for the session.
- * @param extras Reserved for future use.
- * @return An integer in the range of [0, 100] indicating the amount that the user has
- * scrolled the page with 0 indicating the user has never scrolled the page and 100
- * indicating they have scrolled to the very bottom.
- * @throws UnsupportedOperationException If this method isn't supported, i.e.
- * {@link #isEngagementSignalsApiAvailable} returns false.
- */
- @IntRange(from = 0, to = 100)
- protected int getGreatestScrollPercentage(
- @NonNull CustomTabsSessionToken sessionToken, @NonNull Bundle extras) {
- throw new UnsupportedOperationException("Engagement Signals API is not available.");
- }
}
diff --git a/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsSession.java b/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsSession.java
index 0a59a38..8f4f865 100644
--- a/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsSession.java
+++ b/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsSession.java
@@ -32,7 +32,6 @@
import android.view.View;
import android.widget.RemoteViews;
-import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresFeature;
@@ -50,6 +49,7 @@
*/
public final class CustomTabsSession {
private static final String TAG = "CustomTabsSession";
+ static final String TARGET_ORIGIN_KEY = "target_origin";
private final Object mLock = new Object();
private final ICustomTabsService mService;
private final ICustomTabsCallback mCallback;
@@ -63,7 +63,8 @@
*
* {@see Intent#filterEquals()}
*/
- @Nullable private final PendingIntent mId;
+ @Nullable
+ private final PendingIntent mId;
/**
* Provides browsers a way to generate a mock {@link CustomTabsSession} for testing
@@ -104,7 +105,7 @@
* likelihood order. Inside each Bundle, the client should provide a
* {@link Uri} using {@link CustomTabsService#KEY_URL} with
* {@link Bundle#putParcelable(String, android.os.Parcelable)}.
- * @return true for success.
+ * @return true for success.
*/
@SuppressWarnings("NullAway") // TODO: b/142938599
public boolean mayLaunchUrl(@Nullable Uri url, @Nullable Bundle extras,
@@ -121,9 +122,8 @@
* This sets the action button on the toolbar with ID
* {@link CustomTabsIntent#TOOLBAR_ACTION_BUTTON_ID}.
*
- * @param icon The new icon of the action button.
- * @param description Content description of the action button.
- *
+ * @param icon The new icon of the action button.
+ * @param description Content description of the action button.
* @see CustomTabsSession#setToolbarItem(int, Bitmap, String)
*/
public boolean setActionButton(@NonNull Bitmap icon, @NonNull String description) {
@@ -143,6 +143,7 @@
/**
* Updates the {@link RemoteViews} of the secondary toolbar in an existing custom tab session.
+ *
* @param remoteViews The updated {@link RemoteViews} that will be shown in secondary toolbar.
* If null, the current secondary toolbar will be dismissed.
* @param clickableIDs The ids of clickable views. The onClick event of these views will be
@@ -167,10 +168,11 @@
/**
* Updates the visuals for toolbar items. Will only succeed if a custom tab created using this
* session is in the foreground in browser and the given id is valid.
- * @param id The id for the item to update.
- * @param icon The new icon of the toolbar item.
- * @param description Content description of the toolbar item.
- * @return Whether the update succeeded.
+ *
+ * @param id The id for the item to update.
+ * @param icon The new icon of the toolbar item.
+ * @param description Content description of the toolbar item.
+ * @return Whether the update succeeded.
* @deprecated Use
* CustomTabsSession#setSecondaryToolbarViews(RemoteViews, int[], PendingIntent)
*/
@@ -194,26 +196,41 @@
/**
* Sends a request to create a two way postMessage channel between the client and the browser.
*
- * @param postMessageOrigin A origin that the client is requesting to be identified as
- * during the postMessage communication.
+ * @param postMessageOrigin A origin that the client is requesting to be identified as
+ * during the postMessage communication.
* @return Whether the implementation accepted the request. Note that returning true
- * here doesn't mean an origin has already been assigned as the validation is
- * asynchronous.
+ * here doesn't mean an origin has already been assigned as the validation is
+ * asynchronous.
*/
public boolean requestPostMessageChannel(@NonNull Uri postMessageOrigin) {
+ return requestPostMessageChannel(postMessageOrigin, null, new Bundle());
+ }
+
+ /**
+ * Sends a request to create a two way postMessage channel between the client and the browser
+ * with specifying the target origin to communicate with.
+ *
+ * @param postMessageOrigin A origin that the client is requesting to be identified as
+ * during the postMessage communication.
+ * @param postMessageTargetOrigin The target Origin to establish the postMessage communication
+ * with.
+ * @param extras Reserved for future use.
+ * @return Whether the implementation accepted the request. Note that returning true
+ * here doesn't mean an origin has already been assigned as the validation is
+ * asynchronous.
+ */
+ public boolean requestPostMessageChannel(@NonNull Uri postMessageOrigin,
+ @Nullable Uri postMessageTargetOrigin, @NonNull Bundle extras) {
try {
- // If mId is not null we know that the CustomTabsService supports
- // requestPostMessageChannelWithExtras. That is because non-null mId means that
- // CustomTabsSession was created with CustomTabsClient#newSession(Callback int), which
- // can succeed only when browsers supporting CustomTabsService#newSessionWithExtras.
- // This was added at the same time as requestPostMessageChannelWithExtras.
- if (mId != null) {
+ Bundle targetOriginWithIdBundle =
+ createPostMessageExtraBundle(postMessageTargetOrigin);
+ if (targetOriginWithIdBundle != null) {
+ extras.putAll(targetOriginWithIdBundle);
return mService.requestPostMessageChannelWithExtras(
- mCallback, postMessageOrigin, createBundleWithId(null));
+ mCallback, postMessageOrigin, extras);
} else {
return mService.requestPostMessageChannel(mCallback, postMessageOrigin);
}
-
} catch (RemoteException e) {
return false;
}
@@ -222,14 +239,14 @@
/**
* Sends a postMessage request using the origin communicated via
* {@link CustomTabsService#requestPostMessageChannel(
- * CustomTabsSessionToken, Uri)}. Fails when called before
+ *CustomTabsSessionToken, Uri)}. Fails when called before
* {@link PostMessageServiceConnection#notifyMessageChannelReady(Bundle)} is received on
* the client side.
*
* @param message The message that is being sent.
- * @param extras Reserved for future use.
+ * @param extras Reserved for future use.
* @return An integer constant about the postMessage request result. Will return
- * {@link CustomTabsService#RESULT_SUCCESS} if successful.
+ * {@link CustomTabsService#RESULT_SUCCESS} if successful.
*/
@Result
public int postMessage(@NonNull String message, @Nullable Bundle extras) {
@@ -259,8 +276,8 @@
*
* @param relation Relation to check, must be one of the {@code CustomTabsService#RELATION_* }
* constants.
- * @param origin Origin.
- * @param extras Reserved for future use.
+ * @param origin Origin.
+ * @param extras Reserved for future use.
* @return {@code true} if the request has been submitted successfully.
*/
public boolean validateRelationship(@Relation int relation, @NonNull Uri origin,
@@ -287,10 +304,10 @@
* The file is read and processed (where applicable) synchronously, therefore it's recommended
* to call this method on a background thread.
*
- * @param uri {@link Uri} of the file.
+ * @param uri {@link Uri} of the file.
* @param purpose Purpose of transferring this file, one of the constants enumerated in
* {@code CustomTabsService#FilePurpose}.
- * @param extras Reserved for future use.
+ * @param extras Reserved for future use.
* @return {@code true} if the file was received successfully.
*/
public boolean receiveFile(@NonNull Uri uri, @CustomTabsService.FilePurpose int purpose,
@@ -311,12 +328,10 @@
*
* @param extras Reserved for future use.
* @return Whether the Engagement Signals API is available. A false value means
- * {@link #getGreatestScrollPercentage} will throw an
- * {@link UnsupportedOperationException} if called, and
* {@link #setEngagementSignalsCallback} will return false and not set the callback.
* @throws RemoteException If the Service dies while responding to the request.
* @throws UnsupportedOperationException If this method isn't supported by the Custom Tabs
- * implementation.
+ * implementation.
*/
public boolean isEngagementSignalsApiAvailable(@NonNull Bundle extras) throws RemoteException {
try {
@@ -336,12 +351,12 @@
* {@link #setEngagementSignalsCallback(Executor, EngagementSignalsCallback, Bundle)}.
*
* @param callback The {@link EngagementSignalsCallback} to receive the user engagement signals.
- * @param extras Reserved for future use.
+ * @param extras Reserved for future use.
* @return Whether the callback connection is allowed. If false, no callbacks will be called for
- * this session.
- * @throws RemoteException If the Service dies while responding to the request.
+ * this session.
+ * @throws RemoteException If the Service dies while responding to the request.
* @throws UnsupportedOperationException If this method isn't supported by the Custom Tabs
- * implementation.
+ * implementation.
*/
@RequiresFeature(name = CustomTabsFeatures.ENGAGEMENT_SIGNALS, enforcement =
"androidx.browser.customtabs.CustomTabsSession#isEngagementSignalsApiAvailable")
@@ -385,12 +400,12 @@
*
* @param executor The {@link Executor} to be used to execute the callbacks.
* @param callback The {@link EngagementSignalsCallback} to receive the user engagement signals.
- * @param extras Reserved for future use.
+ * @param extras Reserved for future use.
* @return Whether the callback connection is allowed. If false, no callbacks will be called for
- * this session.
- * @throws RemoteException If the Service dies while responding to the request.
+ * this session.
+ * @throws RemoteException If the Service dies while responding to the request.
* @throws UnsupportedOperationException If this method isn't supported by the Custom Tabs
- * implementation.
+ * implementation.
*/
@RequiresFeature(name = CustomTabsFeatures.ENGAGEMENT_SIGNALS, enforcement =
"androidx.browser.customtabs.CustomTabsSession#isEngagementSignalsApiAvailable")
@@ -403,7 +418,7 @@
return mService.setEngagementSignalsCallback(mCallback, wrapper.asBinder(), extras);
} catch (SecurityException e) {
throw new UnsupportedOperationException("This method isn't supported by the "
- + "Custom Tabs implementation.", e);
+ + "Custom Tabs implementation.", e);
}
}
@@ -445,35 +460,20 @@
};
}
- /**
- * Returns the greatest scroll percentage the user has reached on the page based on the page
- * height at the moment the percentage was reached. This method only returns values that have
- * been or would have been reported by
- * {@link EngagementSignalsCallback#onGreatestScrollPercentageIncreased}, and the percentage
- * is not updated if the page height changes after the last scroll event that caused the
- * greatest scroll percentage to change. The greatest scroll percentage is reset when the user
- * navigates to a different page. Note that an {@link EngagementSignalsCallback} does not need
- * to be registered before calling this method.
- *
- * @param extras Reserved for future use.
- * @return An integer in the range of [0, 100] indicating the amount that the user has
- * scrolled the page with 0 indicating the user has never scrolled the page and 100
- * indicating they have scrolled to the very bottom.
- * @throws RemoteException If the Service dies while responding to the request.
- * @throws UnsupportedOperationException If the Engagement Signals API isn't available, i.e.
- * {@link #isEngagementSignalsApiAvailable} returns false, or the method isn't supported
- * by the Custom Tabs implementation.
- */
- @RequiresFeature(name = CustomTabsFeatures.ENGAGEMENT_SIGNALS, enforcement =
- "androidx.browser.customtabs.CustomTabsSession#isEngagementSignalsApiAvailable")
- public @IntRange(from = 0, to = 100) int getGreatestScrollPercentage(@NonNull Bundle extras)
- throws RemoteException {
- try {
- return mService.getGreatestScrollPercentage(mCallback, extras);
- } catch (SecurityException e) {
- throw new UnsupportedOperationException("This method isn't supported by the "
- + "Custom Tabs implementation.", e);
+ private @Nullable Bundle createPostMessageExtraBundle(@Nullable Uri targetOrigin) {
+ Bundle toReturn = new Bundle();
+ if (targetOrigin != null) {
+ toReturn.putParcelable(CustomTabsSession.TARGET_ORIGIN_KEY, targetOrigin);
}
+ // If mId is not null we know that the CustomTabsService supports
+ // requestPostMessageChannelWithExtras. That is because non-null mId means that
+ // CustomTabsSession was created with CustomTabsClient#newSession(Callback int), which
+ // can succeed only when browsers supporting CustomTabsService#newSessionWithExtras.
+ // This was added at the same time as requestPostMessageChannelWithExtras.
+ if (mId != null) {
+ addIdToBundle(toReturn);
+ }
+ return toReturn.isEmpty() ? null : toReturn;
}
private Bundle createBundleWithId(@Nullable Bundle bundle) {
@@ -496,7 +496,7 @@
}
@Nullable
- /* package */ PendingIntent getId() {
+ /* package */ PendingIntent getId() {
return mId;
}
@@ -505,12 +505,13 @@
* {@link CustomTabsService}.
*
* Use {@link CustomTabsClient#attachSession(PendingSession)} to get {@link CustomTabsSession}.
- *
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public static class PendingSession {
- @Nullable private final CustomTabsCallback mCallback;
- @Nullable private final PendingIntent mId;
+ @Nullable
+ private final CustomTabsCallback mCallback;
+ @Nullable
+ private final PendingIntent mId;
/* package */ PendingSession(
@Nullable CustomTabsCallback callback, @Nullable PendingIntent sessionId) {
@@ -519,12 +520,12 @@
}
@Nullable
- /* package */ PendingIntent getId() {
+ /* package */ PendingIntent getId() {
return mId;
}
@Nullable
- /* package */ CustomTabsCallback getCallback() {
+ /* package */ CustomTabsCallback getCallback() {
return mCallback;
}
}
@@ -606,11 +607,5 @@
IBinder callback, Bundle extras) throws RemoteException {
return false;
}
-
- @Override
- public int getGreatestScrollPercentage(ICustomTabsCallback callback, Bundle extras)
- throws RemoteException {
- return 0;
- }
}
}
diff --git a/browser/browser/src/main/java/androidx/browser/customtabs/EngagementSignalsCallback.java b/browser/browser/src/main/java/androidx/browser/customtabs/EngagementSignalsCallback.java
index bc92b3b..99999e9 100644
--- a/browser/browser/src/main/java/androidx/browser/customtabs/EngagementSignalsCallback.java
+++ b/browser/browser/src/main/java/androidx/browser/customtabs/EngagementSignalsCallback.java
@@ -23,8 +23,9 @@
/**
* A callback class for custom tabs clients to get messages regarding the user's engagement with the
- * webpage within their custom tabs. In the implementation, all callbacks are sent to the UI thread
- * for the client.
+ * webpage within their custom tabs. These methods may not be called for some webpages. In the
+ * implementation, all callbacks are sent to the
+ * {@link Executor} provided by the client or its UI thread if one is not provided.
*/
public interface EngagementSignalsCallback {
/**
diff --git a/browser/browser/src/main/res/values-vi/strings.xml b/browser/browser/src/main/res/values-vi/strings.xml
index 983d194..3a822e4 100644
--- a/browser/browser/src/main/res/values-vi/strings.xml
+++ b/browser/browser/src/main/res/values-vi/strings.xml
@@ -18,6 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="fallback_menu_item_open_in_browser" msgid="3413186855122069269">"Mở trong trình duyệt"</string>
<string name="fallback_menu_item_copy_link" msgid="4566929209979330987">"Sao chép đường liên kết"</string>
- <string name="fallback_menu_item_share_link" msgid="7145444925855055364">"Chia sẻ liên kết"</string>
+ <string name="fallback_menu_item_share_link" msgid="7145444925855055364">"Chia sẻ đường liên kết"</string>
<string name="copy_toast_msg" msgid="3260749812566568062">"Đã sao chép đường liên kết vào bảng nhớ tạm"</string>
</resources>
diff --git a/browser/browser/src/main/stableAidl/android/support/customtabs/ICustomTabsService.aidl b/browser/browser/src/main/stableAidl/android/support/customtabs/ICustomTabsService.aidl
index cccdf3c8..7b1df53 100644
--- a/browser/browser/src/main/stableAidl/android/support/customtabs/ICustomTabsService.aidl
+++ b/browser/browser/src/main/stableAidl/android/support/customtabs/ICustomTabsService.aidl
@@ -43,5 +43,4 @@
boolean receiveFile(in ICustomTabsCallback callback, in Uri uri, int purpose, in Bundle extras) = 11;
boolean isEngagementSignalsApiAvailable(in ICustomTabsCallback customTabsCallback, in Bundle extras) = 12;
boolean setEngagementSignalsCallback(in ICustomTabsCallback customTabsCallback, in IBinder callback, in Bundle extras) = 13;
- int getGreatestScrollPercentage(in ICustomTabsCallback customTabsCallback, in Bundle extras) = 14;
}
diff --git a/buildSrc/lint.xml b/buildSrc/lint.xml
index f766c40..749708c 100644
--- a/buildSrc/lint.xml
+++ b/buildSrc/lint.xml
@@ -40,8 +40,10 @@
<issue id="WrongThread" severity="fatal" />
<issue id="MissingTestSizeAnnotation" severity="fatal" />
<issue id="IgnoreClassLevelDetector" severity="fatal" />
- <!-- Disable all lint checks on transformed classes by default. -->
+ <!-- Disable all lint checks on transformed classes by default. b/283812176 -->
<issue id="all">
<ignore path="**/.transforms/**" />
+ <!-- playground builds have dependency files in "transformed" instead of ".transforms" -->
+ <ignore path="**/.gradle/**/transforms*/**/transformed/**" />
</issue>
</lint>
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
index f0b5bb6..755dff6 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
@@ -336,6 +336,11 @@
type.publish != Publish.UNSET
)
+ fun shouldPublishSbom(): Boolean {
+ // IDE plugins are used by and ship inside Studio
+ return shouldPublish() || type == LibraryType.IDE_PLUGIN
+ }
+
/**
* Whether to run API tasks such as tracking and linting. The default value is
* [RunApiTasks.Auto], which automatically picks based on the project's properties.
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index f4339cd..b23ef80 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -33,6 +33,7 @@
import androidx.build.gradle.isRoot
import androidx.build.license.configureExternalDependencyLicenseCheck
import androidx.build.resources.configurePublicResourcesStub
+import androidx.build.sbom.configureSbomPublishing
import androidx.build.sbom.validateAllArchiveInputsRecognized
import androidx.build.studio.StudioTask
import androidx.build.testConfiguration.ModuleInfoGenerator
@@ -155,6 +156,11 @@
project.configureConstraintsWithinGroup(extension)
project.validateProjectParser(extension)
project.validateAllArchiveInputsRecognized()
+ project.afterEvaluate {
+ if (extension.shouldPublishSbom()) {
+ project.configureSbomPublishing()
+ }
+ }
}
private fun Project.registerProjectOrArtifact() {
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
index 27076c2..4313048 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
@@ -151,7 +151,7 @@
// find list of all tasks
val allTasks = mutableListOf<Task>()
project.allprojects { otherProject ->
- otherProject.tasks.all { task ->
+ otherProject.tasks.forEach { task ->
allTasks.add(task)
}
}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
index 6cd994a..8e4e20d 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
@@ -237,7 +237,23 @@
"guava" to "https://guava.dev/releases/18.0/api/docs/",
"kotlin" to "https://kotlinlang.org/api/latest/jvm/stdlib/",
"junit" to "https://junit.org/junit4/javadoc/4.12/",
- "okio" to "https://square.github.io/okio/3.x/okio/"
+ "okio" to "https://square.github.io/okio/3.x/okio/",
+ "protobuf" to "https://protobuf.dev/reference/java/api-docs/",
+ "kotlinpoet" to "https://square.github.io/kotlinpoet/1.x/kotlinpoet/",
+ "skiko" to "https://jetbrains.github.io/skiko/",
+ "reactivex" to "https://reactivex.io/RxJava/2.x/javadoc/",
+ "reactivex-rxjava3" to "http://reactivex.io/RxJava/3.x/javadoc/",
+ "grpc" to "https://grpc.github.io/grpc-java/javadoc/",
+ // From developer.android.com/reference/com/google/android/play/core/package-list
+ "play" to "https://developer.android.com/reference/",
+ // From developer.android.com/reference/com/google/android/material/package-list
+ "material" to "https://developer.android.com/reference",
+ // All package-lists below were created manually
+ "mlkit" to "https://developers.google.com/android/reference/",
+ "dagger" to "https://dagger.dev/api/latest/",
+ "reactivestreams" to "https://www.reactive-streams.org/reactive-streams-1.0.4-javadoc/",
+ "jetbrains-annotations" to "https://javadoc.io/doc/org.jetbrains/annotations/latest/",
+ "auto-value" to "https://www.javadoc.io/doc/com.google.auto.value/auto-value/latest/",
)
}
}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt b/buildSrc/private/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt
index 059f4ef..2123fe6 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt
@@ -77,12 +77,14 @@
val jvmTarget = kmpExtension.targets.requirePlatform(
KotlinPlatformType.jvm
)
- val sourceCollection = jvmTarget.sourceFiles(
- compilationName = KotlinCompilation.MAIN_COMPILATION_NAME
- )
+ val sourceCollection = project.files(project.provider {
+ jvmTarget.sourceFiles(
+ compilationName = KotlinCompilation.MAIN_COMPILATION_NAME
+ )
+ })
return JavaCompileInputs(
- sourcePaths = project.files(sourceCollection),
+ sourcePaths = sourceCollection,
dependencyClasspath = jvmTarget
.compilations[KotlinCompilation.MAIN_COMPILATION_NAME].compileDependencyFiles,
bootClasspath = project.getAndroidJar()
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/sbom/Sbom.kt b/buildSrc/private/src/main/kotlin/androidx/build/sbom/Sbom.kt
index 8889212..a5d8f99 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/sbom/Sbom.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/sbom/Sbom.kt
@@ -18,15 +18,31 @@
import androidx.build.BundleInsideHelper
import androidx.build.GMavenZipTask
+import androidx.build.ProjectLayoutType
+import androidx.build.addToBuildOnServer
+import androidx.build.getPrebuiltsRoot
+import androidx.build.getSupportRootFolder
+import androidx.build.gitclient.MultiGitClient
import androidx.inspection.gradle.EXPORT_INSPECTOR_DEPENDENCIES
import androidx.inspection.gradle.IMPORT_INSPECTOR_DEPENDENCIES
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
+import java.io.File
+import java.net.URI
+import java.util.UUID
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.ModuleVersionIdentifier
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.gradle.api.tasks.bundling.Zip
import org.gradle.jvm.tasks.Jar
+import org.gradle.kotlin.dsl.apply
+import org.gradle.kotlin.dsl.getByType
+import org.spdx.sbom.gradle.SpdxSbomExtension
+import org.spdx.sbom.gradle.SpdxSbomTask
+import org.spdx.sbom.gradle.extensions.DefaultSpdxSbomTaskExtension
+import org.spdx.sbom.gradle.project.ProjectInfo
+import org.spdx.sbom.gradle.project.ScmInfo
/**
* Tells whether the contents of the Configuration with the given name should be listed in our sbom
@@ -44,10 +60,15 @@
appliesShadowPlugin() && project.configurations.findByName("shadowed") == null
EXPORT_INSPECTOR_DEPENDENCIES -> true
IMPORT_INSPECTOR_DEPENDENCIES -> true
+ // https://github.com/spdx/spdx-gradle-plugin/issues/12
+ sbomEmptyConfiguration -> true
else -> false
}
}
+// An empty Configuration for the sbom plugin to ensure it has at least one Configuration
+private val sbomEmptyConfiguration = "sbomEmpty"
+
// some tasks that don't embed configurations having external dependencies
private val excludeTaskNames = setOf(
"distZip",
@@ -71,7 +92,7 @@
* for example, we embed protobuf-javalite into our artifact
*
* The purpose of this function is to detect new archive tasks and remind developers to
- * update shouldSbomIncludeConfiguration
+ * update shouldSbomIncludeConfigurationName
*/
fun Project.listSbomConfigurationNamesForArchive(task: AbstractArchiveTask): List<String> {
if (task is Jar && !(task is ShadowJar)) {
@@ -134,7 +155,7 @@
"Not sure which external dependencies are included in $projectPath:$taskName of type " +
"${task::class.java} (this is used for publishing sboms). Please update " +
"AndroidXImplPlugin's listSbomConfigurationNamesForArchive and " +
- "shouldSbomIncludeConfiguration"
+ "shouldSbomIncludeConfigurationName"
)
}
@@ -184,5 +205,131 @@
}
}
+/**
+ * Enables the publishing of an sbom that lists our embedded dependencies
+ */
+fun Project.configureSbomPublishing() {
+ val uuid = project.coordinatesToUUID().toString()
+
+ project.configurations.create(sbomEmptyConfiguration)
+ project.apply(plugin = "org.spdx.sbom")
+ val repos = if (ProjectLayoutType.isPlayground(this)) {
+ emptyMap()
+ } else {
+ getRepoPublicUrls()
+ }
+ val gitsClient = MultiGitClient.create(project)
+ val supportRootDir = getSupportRootFolder()
+
+ val allowPublicRepos = System.getenv("ALLOW_PUBLIC_REPOS") != null
+
+ project.tasks.withType(SpdxSbomTask::class.java).configureEach { task ->
+ val sbomProjectDir = project.projectDir
+ task.taskExtension.set(object : DefaultSpdxSbomTaskExtension() {
+ override fun mapRepoUri(repoUri: URI, artifact: ModuleVersionIdentifier): URI {
+ val uriString = repoUri.toString()
+ for (repo in repos) {
+ val ourRepoUrl = repo.key
+ val publicRepoUrl = repo.value
+ if (uriString.startsWith(ourRepoUrl)) {
+ return URI.create(publicRepoUrl)
+ }
+ if (allowPublicRepos) {
+ if (uriString.startsWith(publicRepoUrl)) {
+ return URI.create(publicRepoUrl)
+ }
+ }
+ }
+ throw GradleException(
+ "Cannot determine public repo url for repo $uriString artifact $artifact"
+ )
+ }
+ override fun mapScmForProject(original: ScmInfo, projectInfo: ProjectInfo): ScmInfo {
+ val gitClient = gitsClient.getGitClient(projectInfo.projectDirectory)
+ val commit = gitClient.getHeadSha()
+ val url = getGitRemoteUrl(projectInfo.projectDirectory, supportRootDir)
+ return ScmInfo.from("git", url, commit)
+ }
+
+ override fun shouldCreatePackageForProject(projectInfo: ProjectInfo): Boolean {
+ // sbom should include the project it describes
+ if (sbomProjectDir.equals(projectInfo.projectDirectory))
+ return true
+ // sbom doesn't need to list our projects as dependencies;
+ // they're implementation details
+ // Example: glance:glance-appwidget uses glance:glance-appwidget-proto
+ if (pathContains(supportRootDir, projectInfo.projectDirectory))
+ return false
+ // sbom should list remaining project dependencies
+ return true
+ }
+ })
+ }
+
+ val sbomExtension = project.extensions.getByType<SpdxSbomExtension>()
+ val sbomConfigurations = mutableListOf<String>()
+
+ project.afterEvaluate {
+ project.configurations.configureEach { configuration ->
+ if (shouldSbomIncludeConfigurationName(configuration.name)) {
+ sbomConfigurations.add(configuration.getName())
+ }
+ }
+
+ sbomExtension.targets.create("release") { target ->
+ val googleOrganization = "Organization: Google LLC"
+ val document = target.document
+ document.namespace.set("https://spdx.google.com/$uuid")
+ document.creator.set(googleOrganization)
+ document.packageSupplier.set(googleOrganization)
+
+ target.getConfigurations().set(sbomConfigurations)
+ }
+ project.addToBuildOnServer(tasks.named("spdxSbomForRelease"))
+ }
+}
+
+// Returns a UUID whose contents are based on the project's coordinates (group:artifact:version)
+fun Project.coordinatesToUUID(): UUID {
+ val coordinates = "${project.group}:${project.name}:${project.version}"
+ val bytes = coordinates.toByteArray()
+ return UUID.nameUUIDFromBytes(bytes)
+}
+
+fun pathContains(ancestor: File, child: File): Boolean {
+ val childNormalized = child.getCanonicalPath() + File.separator
+ val ancestorNormalized = ancestor.getCanonicalPath() + File.separator
+ return childNormalized.startsWith(ancestorNormalized)
+}
+
+fun getGitRemoteUrl(dir: File, supportRootDir: File): String {
+ if (pathContains(supportRootDir, dir)) {
+ return "android.googlesource.com/platform/frameworks/support"
+ }
+
+ val notoFontsDir = File("$supportRootDir/../../external/noto-fonts")
+ if (pathContains(notoFontsDir, dir)) {
+ return "android.googlesource.com/platform/external/noto-fonts"
+ }
+
+ val icingDir = File("$supportRootDir/../../external/icing")
+ if (pathContains(icingDir, dir)) {
+ return "android.googlesource.com/platform/external/icing"
+ }
+ throw GradleException("Could not identify git remote url for project at $dir")
+}
+
+/**
+ * Returns a mapping from local repo url to public repo url
+ */
+fun Project.getRepoPublicUrls(): Map<String, String> {
+ return mapOf(
+ "file:${project.getPrebuiltsRoot()}/androidx/external"
+ to "https://repo.maven.apache.org/maven2",
+ "file:${project.getPrebuiltsRoot()}/androidx/internal"
+ to "https://dl.google.com/android/maven2"
+ )
+}
+
private fun Project.appliesShadowPlugin() =
pluginManager.hasPlugin("com.github.johnrengelman.shadow")
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt b/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
index f91049f..3b1abc6 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
@@ -147,6 +147,9 @@
"partiallyDejetifyArchive",
"stripArchiveForPartialDejetification",
"createArchive",
+
+ // https://github.com/spdx/spdx-gradle-plugin/issues/18
+ "spdxSbomForRelease",
)
val DONT_TRY_RERUNNING_TASK_TYPES = setOf(
diff --git a/buildSrc/shared-dependencies.gradle b/buildSrc/shared-dependencies.gradle
index 1b67981..107c4ef 100644
--- a/buildSrc/shared-dependencies.gradle
+++ b/buildSrc/shared-dependencies.gradle
@@ -16,6 +16,7 @@
implementation(libs.androidToolsRepository) // com.android.repository for Stable AIDL plugin
implementation(libs.androidToolsSdkCommon) // com.android.ide.common for Stable AIDL plugin
implementation(libs.kotlinGradlePluginz)
+ implementation(libs.spdxGradlePluginz)
// variety of json parsers
implementation(libs.gson)
diff --git a/busytown/impl/build.sh b/busytown/impl/build.sh
index 0e45231..023909d 100755
--- a/busytown/impl/build.sh
+++ b/busytown/impl/build.sh
@@ -93,6 +93,15 @@
fi
fi
+function checkForLeftoverKotlinSessions() {
+ KOTLIN_SESSIONS_DIR=$OUT_DIR/gradle-project-cache/kotlin/sessions
+ NUM_KOTLIN_SESSIONS="$(ls $KOTLIN_SESSIONS_DIR 2>/dev/null | wc -l)"
+ if [ "$NUM_KOTLIN_SESSIONS" -gt 0 ]; then
+ echo "Found $NUM_KOTLIN_SESSIONS leftover kotlin sessions in $KOTLIN_SESSIONS_DIR"
+ fi
+}
+checkForLeftoverKotlinSessions
+
# run the build
if run ./gradlew --ci "$@"; then
echo build passed
diff --git a/camera/camera-camera2-pipe-integration/build.gradle b/camera/camera-camera2-pipe-integration/build.gradle
index 3a1f95e..79bacaa 100644
--- a/camera/camera-camera2-pipe-integration/build.gradle
+++ b/camera/camera-camera2-pipe-integration/build.gradle
@@ -15,9 +15,7 @@
*/
-import androidx.build.BundleInsideHelper
import androidx.build.Publish
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("AndroidXPlugin")
@@ -26,44 +24,24 @@
id("kotlin-kapt")
}
-apply from: "../camera-camera2-pipe/dependencies.gradle"
-
-BundleInsideHelper.forInsideAar(
- project,
- /* from = */ "androidx.camera.camera2.pipe",
- /* to = */ "androidx.camera.camera2.pipe"
-)
-
-configurations {
- bundleInside {
- attributes {
- attribute(Attribute.of("com.android.build.api.attributes.BuildTypeAttr", String), "release")
- attribute(Attribute.of("artifactType", String), "jar")
- }
- transitive = false
- }
-}
-
-
dependencies {
implementation("androidx.core:core:1.3.2")
implementation("androidx.concurrent:concurrent-listenablefuture-callback:1.0.0-beta01")
- bundleInside(project(path: ":camera:camera-camera2-pipe"))
// Classes and types that are needed at compile & runtime
- api("androidx.annotation:annotation:1.1.0")
+ api("androidx.annotation:annotation:1.2.0")
api(project(":camera:camera-core"))
// Classes and types that are only needed at runtime
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.3.1")
implementation("androidx.concurrent:concurrent-futures:1.0.0")
+ implementation(libs.atomicFu)
+ implementation(libs.dagger)
implementation(libs.kotlinStdlib)
+ implementation(libs.kotlinCoroutinesAndroid)
+ implementation(project(":camera:camera-camera2-pipe"))
implementation(project(":concurrent:concurrent-futures-ktx"))
- // Since we jarjar CameraPipe, include the transitive dependencies as implementation
- implementation(CAMERA_PIPE_DEPS.API)
- implementation(CAMERA_PIPE_DEPS.IMPLEMENTATION)
-
kapt(libs.daggerCompiler)
testImplementation(libs.testCore)
@@ -107,6 +85,10 @@
namespace "androidx.camera.camera2.pipe.integration"
}
+tasks.withType(Test).configureEach { test ->
+ test.maxParallelForks(2)
+}
+
kapt {
javacOptions {
option("-Adagger.fastInit=enabled")
diff --git a/camera/camera-camera2-pipe-integration/lint-baseline.xml b/camera/camera-camera2-pipe-integration/lint-baseline.xml
index 53ad38e..fa2dcee 100644
--- a/camera/camera-camera2-pipe-integration/lint-baseline.xml
+++ b/camera/camera-camera2-pipe-integration/lint-baseline.xml
@@ -1,32 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override var useCaseCamera"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override var useCaseCamera"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override fun reset() {"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt"/>
- </issue>
+<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">
<issue
id="BanHideAnnotation"
@@ -40,24 +13,6 @@
<issue
id="BanHideAnnotation"
message="@hide is not allowed in Javadoc"
- errorLine1=" fun create("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun create("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
errorLine1=" companion object {"
errorLine2=" ~~~~~~">
<location
@@ -67,24 +22,6 @@
<issue
id="BanHideAnnotation"
message="@hide is not allowed in Javadoc"
- errorLine1=" fun create(cameraProperties: CameraProperties) = Camera2CameraInfo(cameraProperties)"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraInfo.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun create(cameraProperties: CameraProperties) = Camera2CameraInfo(cameraProperties)"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraInfo.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
errorLine1=" companion object {"
errorLine2=" ~~~~~~">
<location
@@ -94,33 +31,6 @@
<issue
id="BanHideAnnotation"
message="@hide is not allowed in Javadoc"
- errorLine1=" constructor(config: Config) : this(config, false)"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/CaptureRequestOptions.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun <ValueT> getCaptureRequestOption("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/CaptureRequestOptions.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override fun getConfig(): Config {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/CaptureRequestOptions.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
errorLine1=" companion object {"
errorLine2=" ~~~~~~">
<location
@@ -128,33 +38,6 @@
</issue>
<issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun from(config: Config): Builder {"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/CaptureRequestOptions.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun from(config: Config): Builder {"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/CaptureRequestOptions.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override fun getMutableConfig(): MutableConfig {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/pipe/integration/interop/CaptureRequestOptions.kt"/>
- </issue>
-
- <issue
id="CameraXQuirksClassDetector"
message="CameraX quirks should include this template in the javadoc:

* <p>QuirkSummary
* Bug Id:
* Description:
* Device(s):

"
errorLine1="class AspectRatioLegacyApi21Quirk : Quirk {"
@@ -166,7 +49,7 @@
<issue
id="CameraXQuirksClassDetector"
message="CameraX quirks should include this template in the javadoc:

* <p>QuirkSummary
* Bug Id:
* Description:
* Device(s):

"
- errorLine1="class ExcludedSupportedSizesQuirk() : Quirk {"
+ errorLine1="class ExcludedSupportedSizesQuirk : Quirk {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExcludedSupportedSizesQuirk.kt"/>
@@ -202,8 +85,8 @@
<issue
id="SupportAnnotationUsage"
message="Did you mean `@get:VisibleForTesting`? Without `get:` this annotates the constructor parameter itself instead of the associated getter."
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal val requestListener:"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ errorLine1=" @VisibleForTesting internal val requestListener:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt"/>
</issue>
diff --git a/camera/camera-camera2-pipe-integration/lint.xml b/camera/camera-camera2-pipe-integration/lint.xml
deleted file mode 100644
index 0843ecf..0000000
--- a/camera/camera-camera2-pipe-integration/lint.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
- <!-- Disable NewApi lint check temporarily for unit tests.
- This file can be removed once b/200599470 is resolved. -->
- <issue id="NewApi">
- <ignore path="src/test/**" />
- </issue>
-</lint>
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
index 5ed3f28..4acf60b 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
@@ -117,7 +117,6 @@
}
},
state = UseCaseCameraState(useCaseCameraGraphConfig, threads),
- threads = threads,
useCaseGraphConfig = useCaseCameraGraphConfig,
).apply {
SessionConfigAdapter(useCases).getValidSessionConfigOrNull()?.let { sessionConfig ->
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraControlAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraControlAdapter.kt
index 50a01d6..c0f375e 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraControlAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraControlAdapter.kt
@@ -28,9 +28,9 @@
import androidx.camera.camera2.pipe.integration.impl.EvCompControl
import androidx.camera.camera2.pipe.integration.impl.FlashControl
import androidx.camera.camera2.pipe.integration.impl.FocusMeteringControl
+import androidx.camera.camera2.pipe.integration.impl.StillCaptureRequestControl
import androidx.camera.camera2.pipe.integration.impl.TorchControl
import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
-import androidx.camera.camera2.pipe.integration.impl.UseCaseManager
import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
import androidx.camera.camera2.pipe.integration.impl.ZoomControl
import androidx.camera.camera2.pipe.integration.interop.Camera2CameraControl
@@ -49,7 +49,6 @@
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
/**
* Adapt the [CameraControlInternal] interface to [CameraPipe].
@@ -64,13 +63,12 @@
@OptIn(ExperimentalCoroutinesApi::class, ExperimentalCamera2Interop::class)
class CameraControlAdapter @Inject constructor(
private val cameraProperties: CameraProperties,
- private val cameraControlStateAdapter: CameraControlStateAdapter,
private val evCompControl: EvCompControl,
private val flashControl: FlashControl,
private val focusMeteringControl: FocusMeteringControl,
+ private val stillCaptureRequestControl: StillCaptureRequestControl,
private val torchControl: TorchControl,
private val threads: UseCaseThreads,
- private val useCaseManager: UseCaseManager,
private val zoomControl: ZoomControl,
val camera2cameraControl: Camera2CameraControl,
) : CameraControlInternal {
@@ -152,26 +150,11 @@
captureConfigs: List<CaptureConfig>,
captureMode: Int,
flashType: Int,
- ): ListenableFuture<List<Void?>> {
- val camera = useCaseManager.camera
- checkNotNull(camera) { "Attempted to issue capture requests while the camera isn't ready." }
-
- val flashMode = flashMode
- // Prior to submitStillCaptures, wait until the pending flash mode session change is
- // completed. On some devices, AE preCapture triggered in submitStillCaptures may not
- // work properly if the repeating request to change the flash mode is not completed.
- return Futures.nonCancellationPropagating(
- threads.sequentialScope.async {
- flashControl.updateSignal.join()
- camera.requestControl.issueSingleCaptureAsync(
- captureConfigs,
- captureMode,
- flashType,
- flashMode,
- ).awaitAll()
- }.asListenableFuture()
- )
- }
+ ) = stillCaptureRequestControl.issueCaptureRequests(
+ captureConfigs,
+ captureMode,
+ flashType
+ )
override fun getSessionConfig(): SessionConfig {
warn { "TODO: getSessionConfig is not yet supported" }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
index 9fb1916..f8d6362 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
@@ -40,6 +40,7 @@
import androidx.camera.camera2.pipe.integration.impl.FocusMeteringControl
import androidx.camera.camera2.pipe.integration.interop.Camera2CameraInfo
import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop
+import androidx.camera.core.CameraInfo
import androidx.camera.core.CameraSelector
import androidx.camera.core.CameraState
import androidx.camera.core.DynamicRange
@@ -82,6 +83,12 @@
) : CameraInfoInternal {
init { DeviceInfoLogger.logDeviceInfo(cameraProperties) }
+ private val isLegacyDevice by lazy {
+ cameraProperties.metadata[
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL
+ ] == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+ }
+
@OptIn(ExperimentalCamera2Interop::class)
internal val camera2CameraInfo: Camera2CameraInfo by lazy {
Camera2CameraInfo.create(cameraProperties)
@@ -137,7 +144,9 @@
override fun removeSessionCaptureCallback(callback: CameraCaptureCallback) =
cameraCallbackMap.removeCaptureCallback(callback)
- override fun getImplementationType(): String = "CameraPipe"
+ override fun getImplementationType(): String =
+ if (isLegacyDevice) CameraInfo.IMPLEMENTATION_TYPE_CAMERA2_LEGACY
+ else CameraInfo.IMPLEMENTATION_TYPE_CAMERA2
override fun getEncoderProfilesProvider(): EncoderProfilesProvider {
return encoderProfilesProviderAdapter
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
index 0cf7c6c..416b0e4 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
@@ -84,6 +84,7 @@
when (captureType) {
CaptureType.IMAGE_CAPTURE,
CaptureType.PREVIEW,
+ CaptureType.METERING_REPEATING,
CaptureType.IMAGE_ANALYSIS -> sessionBuilder.setTemplateType(
CameraDevice.TEMPLATE_PREVIEW
)
@@ -105,7 +106,8 @@
CaptureType.PREVIEW,
CaptureType.IMAGE_ANALYSIS,
CaptureType.VIDEO_CAPTURE,
- CaptureType.STREAM_SHARING ->
+ CaptureType.STREAM_SHARING,
+ CaptureType.METERING_REPEATING ->
captureBuilder.templateType = CameraDevice.TEMPLATE_RECORD
}
mutableConfig.insertOption(
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CoroutineAdapters.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CoroutineAdapters.kt
index 491c696..903671e 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CoroutineAdapters.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CoroutineAdapters.kt
@@ -78,18 +78,25 @@
return CallbackToFutureAdapter.getFuture(resolver)
}
-@OptIn(ExperimentalCoroutinesApi::class)
fun <T> Deferred<T>.propagateTo(destination: CompletableDeferred<T>) {
invokeOnCompletion {
- if (it != null) {
- if (it is CancellationException) {
- destination.cancel(it)
- } else {
- destination.completeExceptionally(it)
- }
- } else {
- // Ignore exceptions - This should never throw in this situation.
- destination.complete(getCompleted())
- }
+ propagateOnceTo(destination, it)
}
-}
\ No newline at end of file
+}
+
+@OptIn(ExperimentalCoroutinesApi::class)
+fun <T> Deferred<T>.propagateOnceTo(
+ destination: CompletableDeferred<T>,
+ throwable: Throwable?,
+) {
+ if (throwable != null) {
+ if (throwable is CancellationException) {
+ destination.cancel(throwable)
+ } else {
+ destination.completeExceptionally(throwable)
+ }
+ } else {
+ // Ignore exceptions - This should never throw in this situation.
+ destination.complete(getCompleted())
+ }
+}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt
index a84d164..8ba00e1 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt
@@ -131,7 +131,9 @@
// TODO(b/262772650): camera-pipe support for concurrent camera
val targetSurfaceCombinations = getSurfaceCombinationsByCameraMode(cameraMode)
for (surfaceCombination in targetSurfaceCombinations) {
- if (surfaceCombination.isSupported(surfaceConfigList)) {
+ if (surfaceCombination
+ .getOrderedSupportedSurfaceConfigList(surfaceConfigList) != null
+ ) {
return true
}
}
@@ -539,7 +541,7 @@
* CamcorderProfile.
*/
private fun getRecordSize(): Size {
- val cameraId: Int = try {
+ try {
this.cameraId.toInt()
} catch (e: NumberFormatException) {
// The camera Id is not an integer because the camera may be a removable device. Use
@@ -547,8 +549,8 @@
return getRecordSizeFromStreamConfigurationMapCompat()
}
var profiles: EncoderProfilesProxy? = null
- if (encoderProfilesProviderAdapter.hasProfile(cameraId)) {
- profiles = encoderProfilesProviderAdapter.getAll(cameraId)
+ if (encoderProfilesProviderAdapter.hasProfile(CamcorderProfile.QUALITY_HIGH)) {
+ profiles = encoderProfilesProviderAdapter.getAll(CamcorderProfile.QUALITY_HIGH)
}
return if (profiles != null && profiles.videoProfiles.isNotEmpty()) {
Size(profiles.videoProfiles[0].width, profiles.videoProfiles[0].height)
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CameraQuirks.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CameraQuirks.kt
index 71ea477..df03c5d 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CameraQuirks.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CameraQuirks.kt
@@ -107,7 +107,7 @@
companion object {
fun isImmediateSurfaceReleaseAllowed(): Boolean {
- return Build.BRAND == "google"
+ return Build.BRAND == "google" && Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1
}
}
}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CloseCameraDeviceOnCameraGraphCloseQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CloseCameraDeviceOnCameraGraphCloseQuirk.kt
new file mode 100644
index 0000000..f3ebd6b
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CloseCameraDeviceOnCameraGraphCloseQuirk.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.camera2.pipe.integration.compat.quirk
+
+import android.annotation.SuppressLint
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.camera.core.impl.Quirk
+
+/**
+ * Quirk needed on devices where not closing the camera device before creating a new capture session
+ * can lead to undesirable behaviors, such as native camera HAL crashes. On Exynos7870 platforms
+ * for example, once their 3A pipeline times out, recreating a capture session has a high chance of
+ * triggering use-after-free crashes.
+ *
+ * QuirkSummary
+ * - Bug Id: 282871038
+ * - Description: Instructs CameraPipe to close the camera device before creating a new capture
+ * session to avoid undesirable behaviors
+ *
+ * TODO(b/270421716): enable CameraXQuirksClassDetector lint check when kotlin is supported.
+ */
+@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+@SuppressLint("CameraXQuirksClassDetector")
+class CloseCameraDeviceOnCameraGraphCloseQuirk : Quirk {
+ companion object {
+ @JvmStatic
+ fun isEnabled(): Boolean {
+ return Build.HARDWARE == "samsungexynos7870"
+ }
+ }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CloseCaptureSessionOnDisconnectQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CloseCaptureSessionOnDisconnectQuirk.kt
new file mode 100644
index 0000000..89bb55b3
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CloseCaptureSessionOnDisconnectQuirk.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+@file:RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+
+package androidx.camera.camera2.pipe.integration.compat.quirk
+
+import android.annotation.SuppressLint
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.camera.core.impl.Quirk
+
+/**
+ * Quirk needed on devices where not closing capture session before creating a new capture session
+ * can lead to undesirable behaviors:
+ * - CameraDevice.close() call might stall indefinitely
+ * - Crashes in the camera HAL
+ *
+ * QuirkSummary
+ * - Bug Id: 277675483, 282871038
+ * - Description: Instructs CameraPipe to close the capture session before creating a new one to
+ * avoid undesirable behaviors
+ *
+ * TODO(b/270421716): enable CameraXQuirksClassDetector lint check when kotlin is supported.
+ */
+@SuppressLint("CameraXQuirksClassDetector")
+class CloseCaptureSessionOnDisconnectQuirk : Quirk {
+
+ companion object {
+
+ @JvmStatic
+ fun isEnabled(): Boolean {
+ if (CameraQuirks.isImmediateSurfaceReleaseAllowed()) {
+ // If we can release Surfaces immediately, we'll finalize the session when the
+ // camera graph is closed (through FinalizeSessionOnCloseQuirk), and thus we won't
+ // need to explicitly close the capture session.
+ return false
+ }
+ return if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
+ // TODO(b/277675483): Older devices (Android version <= 8.1.0) seem to have a higher
+ // chance of encountering an issue where not closing the capture session would lead
+ // to CameraDevice.close() stalling indefinitely. This version check might need to
+ // be further fine-turned down the line.
+ true
+ } else {
+ // TODO(b/282871038): On some platforms, not closing the capture session before
+ // switching to a new capture session may trigger camera HAL crashes. Add more
+ // hardware platforms here when they're identified.
+ Build.HARDWARE == "samsungexynos7870"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirksLoader.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirksLoader.kt
index 0bbb1e9b..20b4dfc 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirksLoader.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirksLoader.kt
@@ -34,18 +34,21 @@
val quirks: MutableList<Quirk> = mutableListOf()
// Load all device specific quirks, preferably in lexicographical order
+ if (CloseCameraDeviceOnCameraGraphCloseQuirk.isEnabled()) {
+ quirks.add(CloseCameraDeviceOnCameraGraphCloseQuirk())
+ }
+ if (CloseCaptureSessionOnDisconnectQuirk.isEnabled()) {
+ quirks.add(CloseCaptureSessionOnDisconnectQuirk())
+ }
if (CrashWhenTakingPhotoWithAutoFlashAEModeQuirk.isEnabled()) {
quirks.add(CrashWhenTakingPhotoWithAutoFlashAEModeQuirk())
}
-
if (ControlZoomRatioRangeAssertionErrorQuirk.isEnabled()) {
quirks.add(ControlZoomRatioRangeAssertionErrorQuirk())
}
-
if (FlashAvailabilityBufferUnderflowQuirk.isEnabled()) {
quirks.add(FlashAvailabilityBufferUnderflowQuirk())
}
-
if (ImageCapturePixelHDRPlusQuirk.isEnabled()) {
quirks.add(ImageCapturePixelHDRPlusQuirk())
}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt
index 0c5a985..f61915c 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt
@@ -46,6 +46,7 @@
import androidx.camera.camera2.pipe.integration.impl.FlashControl
import androidx.camera.camera2.pipe.integration.impl.FocusMeteringControl
import androidx.camera.camera2.pipe.integration.impl.State3AControl
+import androidx.camera.camera2.pipe.integration.impl.StillCaptureRequestControl
import androidx.camera.camera2.pipe.integration.impl.TorchControl
import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
import androidx.camera.camera2.pipe.integration.impl.ZoomControl
@@ -79,6 +80,7 @@
FlashControl.Bindings::class,
FocusMeteringControl.Bindings::class,
State3AControl.Bindings::class,
+ StillCaptureRequestControl.Bindings::class,
TorchControl.Bindings::class,
ZoomCompat.Bindings::class,
ZoomControl.Bindings::class,
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt
index 730067e..01bdd6e 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt
@@ -19,7 +19,6 @@
package androidx.camera.camera2.pipe.integration.config
import android.media.MediaCodec
-import android.os.Build
import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.CameraId
@@ -33,7 +32,10 @@
import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter
import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter.Companion.toCamera2ImplConfig
import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
+import androidx.camera.camera2.pipe.integration.compat.quirk.CloseCameraDeviceOnCameraGraphCloseQuirk
+import androidx.camera.camera2.pipe.integration.compat.quirk.CloseCaptureSessionOnDisconnectQuirk
import androidx.camera.camera2.pipe.integration.compat.quirk.CloseCaptureSessionOnVideoQuirk
+import androidx.camera.camera2.pipe.integration.compat.quirk.DeviceQuirks
import androidx.camera.camera2.pipe.integration.compat.workaround.CapturePipelineTorchCorrection
import androidx.camera.camera2.pipe.integration.impl.CameraCallbackMap
import androidx.camera.camera2.pipe.integration.impl.CameraInteropStateCallbackRepository
@@ -157,16 +159,15 @@
containsVideo
) {
true
- } else
- // TODO(b/277675483): From the current test results, older devices (Android
- // version <= 8.1.0) seem to have a higher chance of encountering an issue where
- // not closing the capture session would lead to CameraDevice.close stalling
- // indefinitely. This version check might need to be further fine-turned down the
- // line.
- Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1
+ } else {
+ DeviceQuirks[CloseCaptureSessionOnDisconnectQuirk::class.java] != null
+ }
}
+ val shouldCloseCameraDeviceOnClose =
+ DeviceQuirks[CloseCameraDeviceOnCameraGraphCloseQuirk::class.java] != null
val combinedFlags = cameraGraphFlags.copy(
quirkCloseCaptureSessionOnDisconnect = shouldCloseCaptureSessionOnDisconnect,
+ quirkCloseCameraDeviceOnClose = shouldCloseCameraDeviceOnClose,
)
// Build up a config (using TEMPLATE_PREVIEW by default)
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CapturePipeline.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CapturePipeline.kt
index d854d2b..146f2b4 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CapturePipeline.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CapturePipeline.kt
@@ -40,13 +40,15 @@
import android.hardware.camera2.CaptureFailure
import android.hardware.camera2.CaptureResult
import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.FrameInfo
import androidx.camera.camera2.pipe.FrameNumber
import androidx.camera.camera2.pipe.Lock3ABehavior
import androidx.camera.camera2.pipe.Request
import androidx.camera.camera2.pipe.RequestMetadata
import androidx.camera.camera2.pipe.Result3A
-import androidx.camera.camera2.pipe.core.Log
+import androidx.camera.camera2.pipe.core.Log.debug
+import androidx.camera.camera2.pipe.core.Log.info
import androidx.camera.camera2.pipe.integration.compat.workaround.UseTorchAsFlash
import androidx.camera.camera2.pipe.integration.compat.workaround.isFlashAvailable
import androidx.camera.camera2.pipe.integration.compat.workaround.shouldStopRepeatingBeforeCapture
@@ -65,6 +67,7 @@
import androidx.camera.core.TorchState
import java.util.concurrent.TimeUnit
import javax.inject.Inject
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.joinAll
@@ -230,7 +233,7 @@
}.await()
private fun submitRequestInternal(requests: List<Request>): List<Deferred<Void?>> {
- val deferredList = mutableListOf<Deferred<Void?>>()
+ val deferredList = mutableListOf<CompletableDeferred<Void?>>()
val requestsToSubmit = requests.map { request ->
request.copy(listeners = request.listeners.toMutableList().also { newRequestListeners ->
deferredList.add(CompletableDeferred<Void?>().also { completeSignal ->
@@ -273,7 +276,29 @@
}
threads.sequentialScope.launch {
- graph.acquireSession().use {
+ // graph.acquireSession may fail if camera has entered closing stage
+ var cameraGraphSession: CameraGraph.Session? = null
+ try {
+ cameraGraphSession = graph.acquireSession()
+ } catch (_: CancellationException) {
+ info {
+ "CapturePipeline#submitRequestInternal:" +
+ " CameraGraph.Session could not be acquired, requests may need re-submission"
+ }
+
+ // completing the requests exceptionally so that they are retried with next camera
+ deferredList.forEach {
+ it.completeExceptionally(
+ ImageCaptureException(
+ ERROR_CAMERA_CLOSED,
+ "Capture request is cancelled because camera is closed",
+ null
+ )
+ )
+ }
+ }
+
+ cameraGraphSession?.use {
val requiresStopRepeating = requestsToSubmit.shouldStopRepeatingBeforeCapture()
if (requiresStopRepeating) {
it.stopRepeating()
@@ -367,7 +392,7 @@
currentTimestampNs - timestampOfFirstUpdateNs > timeLimitNs
) {
completeSignal.complete(null)
- Log.debug {
+ debug {
"Wait for capture result timeout, current: $currentTimestampNs " +
"first: $timestampOfFirstUpdateNs"
}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestControl.kt
new file mode 100644
index 0000000..47a80ac
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestControl.kt
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.impl
+
+import androidx.annotation.GuardedBy
+import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.core.Log.debug
+import androidx.camera.camera2.pipe.integration.adapter.asListenableFuture
+import androidx.camera.camera2.pipe.integration.adapter.propagateOnceTo
+import androidx.camera.camera2.pipe.integration.config.CameraScope
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCaptureException
+import androidx.camera.core.impl.CaptureConfig
+import androidx.camera.core.impl.utils.futures.Futures
+import com.google.common.util.concurrent.ListenableFuture
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+import java.util.LinkedList
+import javax.inject.Inject
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+@CameraScope
+class StillCaptureRequestControl @Inject constructor(
+ private val flashControl: FlashControl,
+ private val threads: UseCaseThreads,
+) : UseCaseCameraControl {
+ private val mutex = Mutex()
+
+ private var _useCaseCamera: UseCaseCamera? = null
+ override var useCaseCamera: UseCaseCamera?
+ get() = _useCaseCamera
+ set(value) {
+ _useCaseCamera = value
+ _useCaseCamera?.let {
+ submitPendingRequests()
+ }
+ }
+
+ data class CaptureRequest(
+ val captureConfigs: List<CaptureConfig>,
+ val captureMode: Int,
+ val flashType: Int,
+ val result: CompletableDeferred<List<Void?>>,
+ )
+
+ /**
+ * These requests failed to be completely processed with some UseCaseCamera that was open when
+ * corresponding request was issued. (e.g. UseCaseCamera was closed for recreation)
+ * Thus, these requests should be retried when a new UseCaseCamera is created.
+ */
+ @GuardedBy("mutex")
+ private val pendingRequests = LinkedList<CaptureRequest>()
+
+ override fun reset() {
+ threads.sequentialScope.launch {
+ mutex.withLock {
+ while (pendingRequests.isNotEmpty()) {
+ pendingRequests.poll()?.result?.completeExceptionally(
+ ImageCaptureException(
+ ImageCapture.ERROR_CAMERA_CLOSED,
+ "Capture request is cancelled due to a reset",
+ null
+ )
+ )
+ }
+ }
+ }
+ }
+
+ fun issueCaptureRequests(
+ captureConfigs: List<CaptureConfig>,
+ captureMode: Int,
+ flashType: Int,
+ ): ListenableFuture<List<Void?>> {
+ val signal = CompletableDeferred<List<Void?>>()
+
+ threads.sequentialScope.launch {
+ val request = CaptureRequest(captureConfigs, captureMode, flashType, signal)
+ useCaseCamera?.let { camera ->
+ submitRequest(request, camera).propagateResultOrEnqueueRequest(request, camera)
+ } ?: run {
+ // UseCaseCamera may become null by the time the coroutine is started
+ mutex.withLock {
+ pendingRequests.add(request)
+ }
+ debug {
+ "StillCaptureRequestControl: useCaseCamera is null, $request" +
+ " will be retried with a future UseCaseCamera"
+ }
+ }
+ }
+
+ return Futures.nonCancellationPropagating(signal.asListenableFuture())
+ }
+
+ private fun submitPendingRequests() {
+ threads.sequentialScope.launch {
+ mutex.withLock {
+ while (pendingRequests.isNotEmpty()) {
+ pendingRequests.poll()?.let { request ->
+ useCaseCamera?.let { camera ->
+ submitRequest(request, camera).propagateResultOrEnqueueRequest(
+ submittedRequest = request,
+ requestCamera = camera
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private suspend fun submitRequest(
+ request: CaptureRequest,
+ camera: UseCaseCamera
+ ): Deferred<List<Void?>> {
+ debug { "StillCaptureRequestControl: submitting $request at $camera" }
+ val flashMode = flashControl.flashMode
+ // Prior to submitStillCaptures, wait until the pending flash mode session change is
+ // completed. On some devices, AE preCapture triggered in submitStillCaptures may not
+ // work properly if the repeating request to change the flash mode is not completed.
+ flashControl.updateSignal.join()
+ val deferredList = camera.requestControl.issueSingleCaptureAsync(
+ request.captureConfigs,
+ request.captureMode,
+ request.flashType,
+ flashMode,
+ )
+
+ return threads.sequentialScope.async {
+ // requestControl.issueSingleCaptureAsync shouldn't be invoked from here directly,
+ // because sequentialScope.async is may not be executed immediately
+ deferredList.awaitAll()
+ }
+ }
+
+ private fun Deferred<List<Void?>>.propagateResultOrEnqueueRequest(
+ submittedRequest: CaptureRequest,
+ requestCamera: UseCaseCamera
+ ) {
+ invokeOnCompletion { cause: Throwable? ->
+ if (cause is ImageCaptureException &&
+ cause.imageCaptureError == ImageCapture.ERROR_CAMERA_CLOSED
+ ) {
+ threads.sequentialScope.launch {
+ var isPending = true
+
+ useCaseCamera?.let { latestCamera ->
+ if (requestCamera != latestCamera) {
+ // camera has already been changed, can retry immediately
+ submitRequest(
+ submittedRequest,
+ latestCamera
+ ).propagateResultOrEnqueueRequest(
+ submittedRequest = submittedRequest,
+ requestCamera = latestCamera
+ )
+ isPending = false
+ }
+ }
+
+ // no new camera to retry at, adding to pending list for trying later
+ if (isPending) {
+ mutex.withLock {
+ pendingRequests.add(submittedRequest)
+ }
+ debug {
+ "StillCaptureRequestControl: failed to submit $submittedRequest" +
+ ", will be retried with a future UseCaseCamera"
+ }
+ }
+ }
+ } else {
+ propagateOnceTo(submittedRequest.result, cause)
+ }
+ }
+ }
+
+ @Module
+ abstract class Bindings {
+ @Binds
+ @IntoSet
+ abstract fun provideControls(control: StillCaptureRequestControl): UseCaseCameraControl
+ }
+}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/TorchControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/TorchControl.kt
index 5822ecd..fad5c9a 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/TorchControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/TorchControl.kt
@@ -105,6 +105,9 @@
// Hold the internal AE mode to ON while the torch is turned ON.
state3AControl.preferredAeMode =
if (torch) CaptureRequest.CONTROL_AE_MODE_ON else null
+
+ // Always update3A again to reset the AE state in the Camera-pipe controller.
+ state3AControl.invalidate()
state3AControl.updateSignal?.propagateTo(signal) ?: run { signal.complete(Unit) }
}
} ?: run {
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControl.kt
index beb29c8..fda33c0 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControl.kt
@@ -24,8 +24,6 @@
import androidx.annotation.GuardedBy
import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.AeMode
-import androidx.camera.camera2.pipe.AfMode
-import androidx.camera.camera2.pipe.AwbMode
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.CameraGraph.Constants3A.METERING_REGIONS_DEFAULT
import androidx.camera.camera2.pipe.Lock3ABehavior
@@ -38,6 +36,8 @@
import androidx.camera.camera2.pipe.integration.adapter.CaptureConfigAdapter
import androidx.camera.camera2.pipe.integration.config.UseCaseCameraScope
import androidx.camera.camera2.pipe.integration.config.UseCaseGraphConfig
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCaptureException
import androidx.camera.core.impl.CaptureConfig
import androidx.camera.core.impl.CaptureConfig.TEMPLATE_TYPE_NONE
import androidx.camera.core.impl.Config
@@ -46,8 +46,8 @@
import dagger.Binds
import dagger.Module
import javax.inject.Inject
+import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.async
internal const val DEFAULT_REQUEST_TEMPLATE = CameraDevice.TEMPLATE_PREVIEW
@@ -157,7 +157,6 @@
private val configAdapter: CaptureConfigAdapter,
private val capturePipeline: CapturePipeline,
private val state: UseCaseCameraState,
- private val threads: UseCaseThreads,
private val useCaseGraphConfig: UseCaseGraphConfig,
) : UseCaseCameraRequestControl {
private val graph = useCaseGraphConfig.graph
@@ -265,6 +264,20 @@
flashType: Int,
flashMode: Int,
): List<Deferred<Void?>> {
+ if (captureSequence.hasInvalidSurface()) {
+ return List(captureSequence.size) {
+ CompletableDeferred<Void?>().apply {
+ completeExceptionally(
+ ImageCaptureException(
+ ImageCapture.ERROR_CAPTURE_FAILED,
+ "Capture request failed due to invalid surface",
+ null
+ )
+ )
+ }
+ }
+ }
+
return synchronized(lock) {
infoBundleMap.merge()
}.let { infoBundle ->
@@ -283,6 +296,20 @@
}
}
+ private fun List<CaptureConfig>.hasInvalidSurface(): Boolean {
+ forEach { captureConfig ->
+ if (captureConfig.surfaces.isEmpty()) {
+ return true
+ }
+ captureConfig.surfaces.forEach {
+ if (useCaseGraphConfig.surfaceToStreamMap[it] == null) {
+ return true
+ }
+ }
+ }
+ return false
+ }
+
/**
* The merge order is the same as the [UseCaseCameraRequestControl.Type] declaration order.
*
@@ -311,52 +338,23 @@
}
}
- private fun InfoBundle.updateCameraStateAsync(
- streams: Set<StreamId>? = null,
- ): Deferred<Unit> {
- return threads.sequentialScope.async {
- val implConfig = options.build().apply {
- // TODO(wenhungteng@): Camera-pipe will provide a way to let clients override some
- // of the 3A parameters, we may need to use that way instead of using
- // CameraGraph.Session#update3A to control the 3A state.
- update3A()
+ private fun InfoBundle.updateCameraStateAsync(streams: Set<StreamId>? = null): Deferred<Unit> {
+ capturePipeline.template =
+ if (template != null && template!!.value != TEMPLATE_TYPE_NONE) {
+ template!!.value
+ } else {
+ DEFAULT_REQUEST_TEMPLATE
}
- capturePipeline.template =
- if (template != null && template!!.value != TEMPLATE_TYPE_NONE) {
- template!!.value
- } else {
- DEFAULT_REQUEST_TEMPLATE
- }
-
- state.updateAsync(
- parameters = implConfig.toParameters(),
- appendParameters = false,
- internalParameters = mapOf(CAMERAX_TAG_BUNDLE to toTagBundle()),
- appendInternalParameters = false,
- streams = streams,
- template = template,
- listeners = listeners,
- ).join()
- }
- }
-
- private suspend fun Camera2ImplConfig.update3A() {
- val aeMode = getCaptureRequestOption(CaptureRequest.CONTROL_AE_MODE)?.let {
- AeMode.fromIntOrNull(it)
- }
- val afMode = getCaptureRequestOption(CaptureRequest.CONTROL_AF_MODE)?.let {
- AfMode.fromIntOrNull(it)
- }
- val awbMode = getCaptureRequestOption(CaptureRequest.CONTROL_AWB_MODE)?.let {
- AwbMode.fromIntOrNull(it)
- }
-
- if (aeMode != null || afMode != null || awbMode != null) {
- graph.acquireSession().use {
- it.update3A(aeMode = aeMode, afMode = afMode, awbMode = awbMode)
- }
- }
+ return state.updateAsync(
+ parameters = options.build().toParameters(),
+ appendParameters = false,
+ internalParameters = mapOf(CAMERAX_TAG_BUNDLE to toTagBundle()),
+ appendInternalParameters = false,
+ streams = streams,
+ template = template,
+ listeners = listeners,
+ )
}
@Module
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraState.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraState.kt
index ddf68c2..4207fcb 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraState.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraState.kt
@@ -22,6 +22,10 @@
import android.hardware.camera2.CaptureRequest
import androidx.annotation.GuardedBy
import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.AeMode
+import androidx.camera.camera2.pipe.AfMode
+import androidx.camera.camera2.pipe.AwbMode
+import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.FrameInfo
import androidx.camera.camera2.pipe.FrameNumber
import androidx.camera.camera2.pipe.Metadata
@@ -37,7 +41,6 @@
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
/**
@@ -90,6 +93,19 @@
private val requestListener = RequestListener()
+ /**
+ * Updates the camera state by applying the provided parameters to a repeating request and
+ * returns a [Deferred] signal that is completed only when a capture request with equal or
+ * larger request number is completed or failed.
+ *
+ * In case the corresponding capture request of a signal is aborted, it is not completed right
+ * then. This is because a quick succession of update requests may lead to the previous request
+ * being aborted while the request parameters should still be applied unless it was changed in
+ * the new request. If the new request has a value change for some parameter, it is the
+ * responsibility of the caller to keep track of that and take necessary action.
+ *
+ * @return A [Deferred] signal to represent if the update operation has been completed.
+ */
fun updateAsync(
parameters: Map<CaptureRequest.Key<*>, Any>? = null,
appendParameters: Boolean = true,
@@ -213,7 +229,6 @@
*/
fun tryStartRepeating() = submitLatest()
- @OptIn(ExperimentalCoroutinesApi::class)
private fun submitLatest() {
// Update the cameraGraph with the most recent set of values.
// Since acquireSession is a suspending function, it's possible that subsequent updates
@@ -252,8 +267,12 @@
if (request == null) {
it.stopRepeating()
} else {
+ it.update3A(request.parameters)
+
result?.let { result ->
- updateSignals.add(RequestSignal(submittedRequestCounter.value, result))
+ synchronized(lock) {
+ updateSignals.add(RequestSignal(submittedRequestCounter.value, result))
+ }
}
Log.debug { "Update RepeatingRequest: $request" }
it.startRepeating(request)
@@ -270,6 +289,26 @@
}
}
+ private suspend fun CameraGraph.Session.update3A(parameters: Map<CaptureRequest.Key<*>, Any>?) {
+ val aeMode = parameters.getIntOrNull(CaptureRequest.CONTROL_AE_MODE)?.let {
+ AeMode.fromIntOrNull(it)
+ }
+ val afMode = parameters.getIntOrNull(CaptureRequest.CONTROL_AF_MODE)?.let {
+ AfMode.fromIntOrNull(it)
+ }
+ val awbMode = parameters.getIntOrNull(CaptureRequest.CONTROL_AWB_MODE)?.let {
+ AwbMode.fromIntOrNull(it)
+ }
+
+ if (aeMode != null || afMode != null || awbMode != null) {
+ update3A(aeMode = aeMode, afMode = afMode, awbMode = awbMode).join()
+ }
+ }
+
+ private fun Map<CaptureRequest.Key<*>, Any>?.getIntOrNull(
+ key: CaptureRequest.Key<*>
+ ): Int? = this?.get(key) as? Int
+
inner class RequestListener() : Request.Listener {
override fun onTotalCaptureResult(
requestMetadata: RequestMetadata,
@@ -295,11 +334,6 @@
completeExceptionally(requestMetadata, captureFailure)
}
- override fun onRequestSequenceAborted(requestMetadata: RequestMetadata) {
- super.onRequestSequenceAborted(requestMetadata)
- completeExceptionally(requestMetadata)
- }
-
private fun completeExceptionally(
requestMetadata: RequestMetadata,
captureFailure: CaptureFailure? = null
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
index a289f28..a8f3c76 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
@@ -16,6 +16,7 @@
package androidx.camera.camera2.pipe.integration.impl
+import android.content.Context
import android.media.MediaCodec
import android.os.Build
import androidx.annotation.GuardedBy
@@ -23,6 +24,8 @@
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.core.Log
import androidx.camera.camera2.pipe.integration.adapter.CameraStateAdapter
+import androidx.camera.camera2.pipe.integration.adapter.EncoderProfilesProviderAdapter
+import androidx.camera.camera2.pipe.integration.adapter.SupportedSurfaceCombination
import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
import androidx.camera.camera2.pipe.integration.config.CameraConfig
import androidx.camera.camera2.pipe.integration.config.CameraScope
@@ -32,6 +35,7 @@
import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop
import androidx.camera.core.UseCase
import androidx.camera.core.impl.CameraInternal
+import androidx.camera.core.impl.CameraMode
import androidx.camera.core.impl.DeferrableSurface
import androidx.camera.core.impl.SessionConfig.ValidatingBuilder
import javax.inject.Inject
@@ -78,6 +82,7 @@
private val cameraQuirks: CameraQuirks,
private val cameraGraphFlags: CameraGraph.Flags,
private val cameraInternal: Provider<CameraInternal>,
+ context: Context,
cameraProperties: CameraProperties,
displayInfoManager: DisplayInfoManager,
) {
@@ -99,6 +104,14 @@
).build()
}
+ private val supportedSurfaceCombination by lazy {
+ SupportedSurfaceCombination(
+ context,
+ cameraProperties.metadata,
+ EncoderProfilesProviderAdapter(cameraConfig.cameraId.value)
+ )
+ }
+
@Volatile
private var _activeComponent: UseCaseCameraComponent? = null
val camera: UseCaseCamera?
@@ -311,12 +324,13 @@
@GuardedBy("lock")
private fun shouldAddRepeatingUseCase(runningUseCases: Set<UseCase>): Boolean {
val meteringRepeatingEnabled = attachedUseCases.contains(meteringRepeating)
-
- val coreLibraryUseCases = runningUseCases.filterNot { it is MeteringRepeating }
- val onlyVideoCapture = coreLibraryUseCases.onlyVideoCapture()
- val requireMeteringRepeating = coreLibraryUseCases.requireMeteringRepeating()
-
- return !meteringRepeatingEnabled && (onlyVideoCapture || requireMeteringRepeating)
+ if (!meteringRepeatingEnabled) {
+ val activeSurfaces = runningUseCases.withoutMetering().surfaceCount()
+ return activeSurfaces > 0 && with(attachedUseCases.withoutMetering()) {
+ (onlyVideoCapture() || requireMeteringRepeating()) && supportMeteringCombination()
+ }
+ }
+ return false
}
@GuardedBy("lock")
@@ -330,12 +344,13 @@
@GuardedBy("lock")
private fun shouldRemoveRepeatingUseCase(runningUseCases: Set<UseCase>): Boolean {
val meteringRepeatingEnabled = runningUseCases.contains(meteringRepeating)
-
- val coreLibraryUseCases = runningUseCases.filterNot { it is MeteringRepeating }
- val onlyVideoCapture = coreLibraryUseCases.onlyVideoCapture()
- val requireMeteringRepeating = coreLibraryUseCases.requireMeteringRepeating()
-
- return meteringRepeatingEnabled && !onlyVideoCapture && !requireMeteringRepeating
+ if (meteringRepeatingEnabled) {
+ val activeSurfaces = runningUseCases.withoutMetering().surfaceCount()
+ return activeSurfaces == 0 || with(attachedUseCases.withoutMetering()) {
+ !(onlyVideoCapture() || requireMeteringRepeating()) || !supportMeteringCombination()
+ }
+ }
+ return false
}
@GuardedBy("lock")
@@ -353,6 +368,39 @@
}
}
+ private fun Collection<UseCase>.supportMeteringCombination(): Boolean {
+ val useCases = this.toMutableList().apply { add(meteringRepeating) }
+ if (meteringRepeating.attachedSurfaceResolution == null) {
+ meteringRepeating.setupSession()
+ }
+ return isCombinationSupported(useCases).also {
+ Log.debug { "Combination of $useCases is supported: $it" }
+ }
+ }
+
+ private fun isCombinationSupported(currentUseCases: Collection<UseCase>): Boolean {
+ val surfaceConfigs = currentUseCases.map { useCase ->
+ // TODO: Test with correct Camera Mode when concurrent mode / ultra high resolution is
+ // implemented.
+ supportedSurfaceCombination.transformSurfaceConfig(
+ CameraMode.DEFAULT,
+ useCase.imageFormat,
+ useCase.attachedSurfaceResolution!!
+ )
+ }
+
+ return supportedSurfaceCombination.checkSupported(CameraMode.DEFAULT, surfaceConfigs)
+ }
+
+ private fun Collection<UseCase>.surfaceCount(): Int =
+ ValidatingBuilder().let { validatingBuilder ->
+ forEach { useCase -> validatingBuilder.add(useCase.sessionConfig) }
+ return validatingBuilder.build().surfaces.size
+ }
+
+ private fun Collection<UseCase>.withoutMetering(): Collection<UseCase> =
+ filterNot { it is MeteringRepeating }
+
private fun Collection<UseCase>.requireMeteringRepeating(): Boolean {
return isNotEmpty() && checkSurfaces { repeatingSurfaces, sessionSurfaces ->
// There is no repeating UseCases
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt
index 2ca7aeb..cb4c9fe 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt
@@ -56,14 +56,8 @@
private var _useCaseCamera: UseCaseCamera? = null
override var useCaseCamera
- /**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY)
get() = _useCaseCamera
- /**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY)
set(value) {
_useCaseCamera = value
@@ -74,9 +68,6 @@
}
}
- /**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY)
override fun reset() {
// Clear the current task, but don't clear the CaptureRequestOptions. Camera2CameraControl
@@ -197,8 +188,6 @@
/**
* This is the workaround to prevent constructor from being added to public API.
- *
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@JvmStatic
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraInfo.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraInfo.kt
index 3094fc4..fb6d1dd 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraInfo.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraInfo.kt
@@ -99,8 +99,6 @@
/**
* This is the workaround to prevent constructor from being added to public API.
- *
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@JvmStatic
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/CaptureRequestOptions.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/CaptureRequestOptions.kt
index 2cf815d..687bf4c 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/CaptureRequestOptions.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/CaptureRequestOptions.kt
@@ -43,11 +43,7 @@
) :
ReadableConfig {
- /**
- * @hide
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY)
- constructor(config: Config) : this(config, false)
+ internal constructor(config: Config) : this(config, false)
/**
* Returns a value for the given [CaptureRequest.Key] or null if it hasn't been set.
@@ -72,11 +68,8 @@
* @param ValueT The type of the value.
* @return The stored value or `valueIfMissing` if the value does not exist in this
* configuration.
- *
- * @hide
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY)
- fun <ValueT> getCaptureRequestOption(
+ internal fun <ValueT> getCaptureRequestOption(
key: CaptureRequest.Key<ValueT>,
valueIfMissing: ValueT?
): ValueT? {
@@ -88,8 +81,6 @@
/**
* Returns the [Config] object associated with this [CaptureRequestOptions].
- *
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
override fun getConfig(): Config {
@@ -112,7 +103,6 @@
*
* @param config An immutable configuration to pre-populate this builder.
* @return The new Builder.
- * @hide
*/
@JvmStatic
@RestrictTo(RestrictTo.Scope.LIBRARY)
@@ -137,8 +127,6 @@
/**
* {@inheritDoc}
- *
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
override fun getMutableConfig(): MutableConfig {
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
index ddb53b2..dbb6baf 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
@@ -16,17 +16,22 @@
package androidx.camera.camera2.pipe.integration.adapter
+import android.hardware.camera2.CameraCharacteristics
import android.os.Build
import android.util.Range
import android.util.Size
import androidx.camera.camera2.pipe.integration.impl.ZoomControl
import androidx.camera.camera2.pipe.integration.testing.FakeCameraInfoAdapterCreator.createCameraInfoAdapter
import androidx.camera.camera2.pipe.integration.testing.FakeCameraInfoAdapterCreator.useCaseThreads
+import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
import androidx.camera.camera2.pipe.integration.testing.FakeZoomCompat
+import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
+import androidx.camera.core.CameraInfo
import androidx.camera.core.FocusMeteringAction
import androidx.camera.core.SurfaceOrientedMeteringPointFactory
import androidx.camera.core.ZoomState
+import androidx.camera.core.impl.CameraInfoInternal
import androidx.camera.core.impl.ImageFormatConstants
import androidx.testutils.MainDispatcherRule
import com.google.common.truth.Truth.assertThat
@@ -138,4 +143,38 @@
.that(currentZoomState)
.isEqualTo(zoomControl.defaultZoomState)
}
+
+ @Test
+ fun cameraInfo_getImplementationType_legacy() {
+ val cameraInfo: CameraInfoInternal = createCameraInfoAdapter(
+ cameraProperties = FakeCameraProperties(
+ FakeCameraMetadata(
+ characteristics = mapOf(
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL to
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
+ )
+ )
+ )
+ )
+ assertThat(cameraInfo.implementationType).isEqualTo(
+ CameraInfo.IMPLEMENTATION_TYPE_CAMERA2_LEGACY
+ )
+ }
+
+ @Test
+ fun cameraInfo_getImplementationType_noneLegacy() {
+ val cameraInfo: CameraInfoInternal = createCameraInfoAdapter(
+ cameraProperties = FakeCameraProperties(
+ FakeCameraMetadata(
+ characteristics = mapOf(
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL to
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
+ )
+ )
+ )
+ )
+ assertThat(cameraInfo.implementationType).isEqualTo(
+ CameraInfo.IMPLEMENTATION_TYPE_CAMERA2
+ )
+ }
}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapterTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapterTest.kt
index 05e8e70..bd0ea0a 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapterTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapterTest.kt
@@ -194,7 +194,11 @@
CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO
).setCaptureRequestOption<Int>(
CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH
- ).setPhysicalCameraId(physicalCameraId)
+ ).apply {
+ if (Build.VERSION.SDK_INT >= 28) {
+ setPhysicalCameraId(physicalCameraId)
+ }
+ }
val useCaseConfig = imageCaptureConfigBuilder.useCaseConfig
val priorityAfMode = useCaseConfig.getCaptureRequestOptionPriority(
CaptureRequest.CONTROL_AF_MODE
@@ -222,10 +226,11 @@
CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF
)
).isEqualTo(CaptureRequest.FLASH_MODE_TORCH)
- assertThat(
- config.getPhysicalCameraId(null)
- ).isEqualTo(physicalCameraId)
-
+ if (Build.VERSION.SDK_INT >= 28) {
+ assertThat(
+ config.getPhysicalCameraId(null)
+ ).isEqualTo(physicalCameraId)
+ }
// Make sures the priority of Camera2Interop is preserved after unpacking.
assertThat(config.getCaptureRequestOptionPriority(CaptureRequest.CONTROL_AF_MODE))
.isEqualTo(priorityAfMode)
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
index b51e10f..d3a2e92 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.camera2.pipe.integration.adapter
import android.graphics.Rect
@@ -27,6 +29,7 @@
import android.os.Build
import android.util.Rational
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.CameraId
import androidx.camera.camera2.pipe.Lock3ABehavior
@@ -34,9 +37,7 @@
import androidx.camera.camera2.pipe.integration.compat.StreamConfigurationMapCompat
import androidx.camera.camera2.pipe.integration.compat.ZoomCompat
import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
-import androidx.camera.camera2.pipe.integration.compat.workaround.AeFpsRange
import androidx.camera.camera2.pipe.integration.compat.workaround.MeteringRegionCorrection
-import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpAutoFlashAEModeDisabler
import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpMeteringRegionCorrection
import androidx.camera.camera2.pipe.integration.compat.workaround.OutputSizesCorrector
import androidx.camera.camera2.pipe.integration.impl.CameraProperties
@@ -46,6 +47,7 @@
import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
+import androidx.camera.camera2.pipe.integration.testing.FakeState3AControlCreator
import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraRequestControl
import androidx.camera.camera2.pipe.integration.testing.FakeZoomCompat
import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
@@ -1582,22 +1584,8 @@
cameraId: String = CAMERA_ID_0,
properties: CameraProperties = cameraPropertiesMap[cameraId]!!,
useCaseCamera: UseCaseCamera = fakeUseCaseCamera,
- ) = State3AControl(
+ ) = FakeState3AControlCreator.createState3AControl(
properties,
- NoOpAutoFlashAEModeDisabler,
- AeFpsRange(
- CameraQuirks(
- FakeCameraMetadata(),
- StreamConfigurationMapCompat(
- StreamConfigurationMapBuilder.newBuilder().build(),
- OutputSizesCorrector(
- FakeCameraMetadata(),
- StreamConfigurationMapBuilder.newBuilder().build()
- )
- )
- )
- )
- ).apply {
- this.useCaseCamera = useCaseCamera
- }
+ useCaseCamera
+ )
}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt
index 87a97d4..7305db3 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.camera2.pipe.integration.adapter
import android.graphics.SurfaceTexture
@@ -21,6 +23,7 @@
import android.media.MediaCodec
import android.os.Build
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.integration.impl.STREAM_USE_CASE_OPTION
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageCapture
@@ -282,4 +285,4 @@
testSurface.release()
surfaceTexture.release()
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombinationTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombinationTest.kt
index c758dc4..8066f64 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombinationTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombinationTest.kt
@@ -1865,9 +1865,12 @@
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP to mockMap,
).also { characteristicsMap ->
mockMaximumResolutionMap?.let {
- characteristicsMap[
- CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION] =
+ if (Build.VERSION.SDK_INT >= 31) {
+ characteristicsMap[
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION
+ ] =
mockMaximumResolutionMap
+ }
}
}
@@ -1898,7 +1901,10 @@
).thenReturn(supportedSizes)
// This is setup for high resolution output sizes
highResolutionSupportedSizes?.let {
- whenever(mockMap.getHighResolutionOutputSizes(ArgumentMatchers.anyInt())).thenReturn(it)
+ if (Build.VERSION.SDK_INT >= 23) {
+ whenever(mockMap.getHighResolutionOutputSizes(ArgumentMatchers.anyInt()))
+ .thenReturn(it)
+ }
}
shadowCharacteristics.set(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP, mockMap)
mockMaximumResolutionMap?.let {
@@ -1906,17 +1912,21 @@
.thenReturn(maximumResolutionSupportedSizes)
whenever(mockMaximumResolutionMap.getOutputSizes(SurfaceTexture::class.java))
.thenReturn(maximumResolutionSupportedSizes)
- whenever(
- mockMaximumResolutionMap.getHighResolutionOutputSizes(
- ArgumentMatchers.anyInt()
+ if (Build.VERSION.SDK_INT >= 23) {
+ whenever(
+ mockMaximumResolutionMap.getHighResolutionOutputSizes(
+ ArgumentMatchers.anyInt()
+ )
+ ).thenReturn(
+ maximumResolutionHighResolutionSupportedSizes
)
- ).thenReturn(
- maximumResolutionHighResolutionSupportedSizes
- )
- shadowCharacteristics.set(
- CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION,
- mockMaximumResolutionMap
- )
+ }
+ if (Build.VERSION.SDK_INT >= 31) {
+ shadowCharacteristics.set(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION,
+ mockMaximumResolutionMap
+ )
+ }
}
@LensFacing val lensFacingEnum = CameraUtil.getLensFacingEnumFromInt(
CameraCharacteristics.LENS_FACING_BACK
@@ -2021,4 +2031,4 @@
)
return builder.build()
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/OutputSizesCorrectorTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/OutputSizesCorrectorTest.kt
index 31411ee..8311cc8 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/OutputSizesCorrectorTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/OutputSizesCorrectorTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.camera2.pipe.integration.compat
import android.graphics.ImageFormat
@@ -21,6 +23,7 @@
import android.hardware.camera2.CameraCharacteristics
import android.os.Build
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraId
import androidx.camera.camera2.pipe.integration.compat.workaround.OutputSizesCorrector
import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
@@ -240,4 +243,4 @@
map
)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/ZoomCompatTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/ZoomCompatTest.kt
index a194ad5..c6b3b8d4 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/ZoomCompatTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/ZoomCompatTest.kt
@@ -74,7 +74,10 @@
override fun <T> get(key: CameraCharacteristics.Key<T>): T? {
println("throwingCameraMetadata get: key = $key")
- if (key == CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE) {
+ if (
+ Build.VERSION.SDK_INT >= 30 &&
+ key == CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE
+ ) {
throw AssertionError()
}
TODO("Not yet implemented")
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirks.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirks.kt
index 90c8f11..4bd2f69 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirks.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirks.kt
@@ -15,6 +15,7 @@
*/
package androidx.camera.camera2.pipe.integration.compat.quirk
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.integration.compat.quirk.DeviceQuirksLoader.loadQuirks
import androidx.camera.core.impl.Quirk
@@ -29,6 +30,7 @@
* quirks in every test that uses a device workaround, this class internally reloads the quirks
* every time a device workaround is needed.
*/
+@RequiresApi(21)
object DeviceQuirks {
/**
* Retrieves a specific device [Quirk] instance given its type.
@@ -66,4 +68,4 @@
}
return list
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedSurfaceCombinationsQuirkTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedSurfaceCombinationsQuirkTest.kt
index 88b54d5..e48b3fb 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedSurfaceCombinationsQuirkTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedSurfaceCombinationsQuirkTest.kt
@@ -66,9 +66,9 @@
// Checks the combination is supported by the list retrieved from the
// ExtraSupportedSurfaceCombinationsContainer.
for (extraSurfaceCombination in extraSurfaceCombinations) {
- if (extraSurfaceCombination.isSupported(
+ if (extraSurfaceCombination.getOrderedSupportedSurfaceConfigList(
expectedSupportedSurfaceCombination.surfaceConfigList
- )
+ ) != null
) {
isSupported = true
break
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/FlashAvailabilityCheckerTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/FlashAvailabilityCheckerTest.kt
index 60ddf46..132aeb3 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/FlashAvailabilityCheckerTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/FlashAvailabilityCheckerTest.kt
@@ -35,12 +35,13 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.ParameterizedRobolectricTestRunner
+import org.robolectric.annotation.Config
import org.robolectric.annotation.internal.DoNotInstrument
import org.robolectric.util.ReflectionHelpers
-// @Config() is left out since there currently aren't any API level dependencies in this workaround
@RunWith(ParameterizedRobolectricTestRunner::class)
@DoNotInstrument
+@Config(minSdk = 21)
class FlashAvailabilityCheckerTest(
private val manufacturer: String,
private val model: String,
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/ImageCaptureOptionUnpackerTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/ImageCaptureOptionUnpackerTest.kt
index bd8d503..feac8b2 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/ImageCaptureOptionUnpackerTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/ImageCaptureOptionUnpackerTest.kt
@@ -27,13 +27,14 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
import org.robolectric.annotation.internal.DoNotInstrument
import org.robolectric.shadows.ShadowBuild
import org.robolectric.util.ReflectionHelpers
-// @Config() is left out since there currently aren't any API level dependencies in this workaround
@RunWith(RobolectricTestRunner::class)
@DoNotInstrument
+@Config(minSdk = 26)
class ImageCaptureOptionUnpackerTest {
private val unpacker = CameraUseCaseAdapter.ImageCaptureOptionUnpacker.INSTANCE
@@ -292,4 +293,4 @@
API_LEVEL_26
)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/PreviewPixelHDRnetQuirkTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/PreviewPixelHDRnetQuirkTest.kt
index a04699a..08f756f 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/PreviewPixelHDRnetQuirkTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/PreviewPixelHDRnetQuirkTest.kt
@@ -44,12 +44,13 @@
import org.junit.runner.Description
import org.junit.runner.RunWith
import org.robolectric.ParameterizedRobolectricTestRunner
+import org.robolectric.annotation.Config
import org.robolectric.annotation.internal.DoNotInstrument
import org.robolectric.util.ReflectionHelpers
-// @Config() is left out since there currently aren't any API level dependencies in this workaround
@RunWith(ParameterizedRobolectricTestRunner::class)
@DoNotInstrument
+@Config(minSdk = 21)
class PreviewPixelHDRnetQuirkTest(
private val manufacturer: String,
private val device: String,
@@ -200,4 +201,4 @@
add(arrayOf(FAKE_OEM, "not_a_real_device", false))
}
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/ResolutionCorrectorTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/ResolutionCorrectorTest.kt
index ca3adf66..aa1592c 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/ResolutionCorrectorTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/ResolutionCorrectorTest.kt
@@ -14,10 +14,13 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.camera2.pipe.integration.compat.workaround
import android.os.Build
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.core.impl.SurfaceConfig
import com.google.common.truth.Truth
import org.junit.Before
@@ -118,4 +121,4 @@
)
Truth.assertThat(result).containsExactlyElementsIn(SUPPORTED_RESOLUTIONS)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/DisplayInfoManagerTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/DisplayInfoManagerTest.kt
index 02a742b..4de84a4 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/DisplayInfoManagerTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/DisplayInfoManagerTest.kt
@@ -28,6 +28,7 @@
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
+import org.robolectric.annotation.Config
import org.robolectric.annotation.internal.DoNotInstrument
import org.robolectric.shadow.api.Shadow
import org.robolectric.shadows.ShadowDisplay
@@ -37,6 +38,7 @@
@Suppress("DEPRECATION") // getRealSize
@RunWith(RobolectricCameraPipeTestRunner::class)
@DoNotInstrument
+@Config(minSdk = 21)
class DisplayInfoManagerTest {
private val displayInfoManager = DisplayInfoManager(ApplicationProvider.getApplicationContext())
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestTest.kt
new file mode 100644
index 0000000..63e023a
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestTest.kt
@@ -0,0 +1,463 @@
+/*
+ * 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.camera2.pipe.integration.impl
+
+import android.hardware.camera2.CaptureFailure
+import android.os.Build
+import androidx.camera.camera2.pipe.FrameNumber
+import androidx.camera.camera2.pipe.StreamId
+import androidx.camera.camera2.pipe.integration.adapter.CameraStateAdapter
+import androidx.camera.camera2.pipe.integration.adapter.CaptureConfigAdapter
+import androidx.camera.camera2.pipe.integration.adapter.RobolectricCameraPipeTestRunner
+import androidx.camera.camera2.pipe.integration.compat.workaround.NotUseTorchAsFlash
+import androidx.camera.camera2.pipe.integration.config.UseCaseGraphConfig
+import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraph
+import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraphSession
+import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
+import androidx.camera.camera2.pipe.integration.testing.FakeState3AControlCreator
+import androidx.camera.camera2.pipe.integration.testing.FakeSurface
+import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
+import androidx.camera.camera2.pipe.testing.FakeFrameInfo
+import androidx.camera.camera2.pipe.testing.FakeRequestMetadata
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY
+import androidx.camera.core.ImageCapture.FLASH_MODE_OFF
+import androidx.camera.core.ImageCaptureException
+import androidx.camera.core.impl.CaptureConfig
+import com.google.common.truth.Truth.assertThat
+import com.google.common.util.concurrent.ListenableFuture
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeoutException
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertThrows
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(RobolectricCameraPipeTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class StillCaptureRequestTest {
+ private val testScope = TestScope()
+ private val testDispatcher = StandardTestDispatcher(testScope.testScheduler)
+
+ private val fakeUseCaseThreads by lazy {
+ UseCaseThreads(
+ testScope,
+ testDispatcher.asExecutor(),
+ testDispatcher
+ )
+ }
+ private val fakeCameraProperties = FakeCameraProperties()
+ private val fakeSurface = FakeSurface()
+
+ private lateinit var fakeCameraGraphSession: FakeCameraGraphSession
+ private lateinit var fakeCameraGraph: FakeCameraGraph
+ private lateinit var fakeUseCaseGraphConfig: UseCaseGraphConfig
+
+ private lateinit var fakeConfigAdapter: CaptureConfigAdapter
+ private lateinit var fakeUseCaseCameraState: UseCaseCameraState
+
+ private val fakeState3AControl: State3AControl = FakeState3AControlCreator.createState3AControl(
+ useCaseCamera = FakeUseCaseCamera()
+ )
+
+ private lateinit var requestControl: UseCaseCameraRequestControl
+
+ private lateinit var fakeUseCaseCamera: UseCaseCamera
+
+ private val flashControl = FlashControl(
+ fakeState3AControl,
+ fakeUseCaseThreads,
+ )
+
+ private val stillCaptureRequestControl = StillCaptureRequestControl(
+ flashControl, fakeUseCaseThreads
+ )
+
+ private val captureConfigList = listOf(
+ CaptureConfig.Builder().apply { addSurface(fakeSurface) }.build(),
+ CaptureConfig.Builder().apply { addSurface(fakeSurface) }.build()
+ )
+
+ @Before
+ fun setUp() {
+ stillCaptureRequestControl.setNewUseCaseCamera()
+ }
+
+ @Test
+ fun captureRequestsSubmitted_whenCameraIsSet() = runTest(testDispatcher) {
+ stillCaptureRequestControl.issueCaptureRequests()
+
+ advanceUntilIdle()
+ assertThat(
+ fakeCameraGraphSession.submittedRequests.size
+ ).isEqualTo(captureConfigList.size)
+ }
+
+ @Test
+ fun captureRequestsNotSubmitted_whenCameraIsNull() = runTest(testDispatcher) {
+ stillCaptureRequestControl.useCaseCamera = null
+
+ stillCaptureRequestControl.issueCaptureRequests()
+
+ advanceUntilIdle()
+ assertThat(
+ fakeCameraGraphSession.submittedRequests.size
+ ).isEqualTo(0)
+ }
+
+ @Test
+ fun captureRequestsSubmittedAfterCameraIsAvailable_whenCameraIsNull() =
+ runTest(testDispatcher) {
+ stillCaptureRequestControl.useCaseCamera = null
+
+ stillCaptureRequestControl.issueCaptureRequests()
+ advanceUntilIdle()
+
+ // new camera is attached
+ stillCaptureRequestControl.setNewUseCaseCamera()
+
+ // the previous request should be submitted in the new camera
+ advanceUntilIdle()
+ assertThat(
+ fakeCameraGraphSession.submittedRequests.size
+ ).isEqualTo(captureConfigList.size)
+ }
+
+ @Test
+ fun captureRequestsComplete_onTotalCaptureOfAllRequests(): Unit = runTest(testDispatcher) {
+ val requestFuture = stillCaptureRequestControl.issueCaptureRequests()
+
+ advanceUntilIdle()
+ assumeTrue(fakeCameraGraphSession.submittedRequests.size == captureConfigList.size)
+
+ fakeCameraGraphSession.submittedRequests.forEach { request ->
+ request.listeners.forEach { listener ->
+ listener.onTotalCaptureResult(
+ FakeRequestMetadata(),
+ FrameNumber(0),
+ FakeFrameInfo()
+ )
+ }
+ }
+
+ advanceUntilIdle()
+ requestFuture.completes()
+ }
+
+ @Test
+ fun captureRequestsFailWithTimeout_onTotalCaptureOfSomeRequests(): Unit =
+ runTest(testDispatcher) {
+ val requestFuture = stillCaptureRequestControl.issueCaptureRequests()
+
+ advanceUntilIdle()
+ assumeTrue(fakeCameraGraphSession.submittedRequests.size == captureConfigList.size)
+
+ fakeCameraGraphSession.submittedRequests.first().let { request ->
+ request.listeners.forEach { listener ->
+ listener.onTotalCaptureResult(
+ FakeRequestMetadata(),
+ FrameNumber(0),
+ FakeFrameInfo()
+ )
+ }
+ }
+
+ advanceUntilIdle()
+ requestFuture.failsWithTimeout()
+ }
+
+ @Test
+ fun captureRequestsFailWithCaptureFailedError_onFailed(): Unit = runTest(testDispatcher) {
+ val requestFuture = stillCaptureRequestControl.issueCaptureRequests()
+
+ advanceUntilIdle()
+ assumeTrue(fakeCameraGraphSession.submittedRequests.size == captureConfigList.size)
+
+ fakeCameraGraphSession.submittedRequests.first().let { request ->
+ request.listeners.forEach { listener ->
+ listener.onFailed(
+ FakeRequestMetadata(),
+ FrameNumber(0),
+ createCaptureFailure()
+ )
+ }
+ }
+
+ advanceUntilIdle()
+ requestFuture.failsWithCaptureFailedError()
+ }
+
+ @Test
+ fun captureRequestsSubmittedToNextCamera_onAborted(): Unit = runTest(testDispatcher) {
+ stillCaptureRequestControl.issueCaptureRequests()
+
+ // waits for requests to be submitted before camera is closing
+ advanceUntilIdle()
+ assumeTrue(fakeCameraGraphSession.submittedRequests.size == captureConfigList.size)
+
+ // simulates previous camera closing and thus reporting onAborted
+ fakeCameraGraphSession.submittedRequests.first().let { request ->
+ request.listeners.forEach { listener ->
+ listener.onAborted(
+ request
+ )
+ }
+ }
+
+ // new camera is attached
+ stillCaptureRequestControl.setNewUseCaseCamera()
+
+ // the previous request should be submitted again in the new camera
+ advanceUntilIdle()
+ assertThat(
+ fakeCameraGraphSession.submittedRequests.size
+ ).isEqualTo(captureConfigList.size)
+ }
+
+ @Test
+ fun captureRequestsNotSubmittedToSameCamera_onAborted(): Unit = runTest(testDispatcher) {
+ stillCaptureRequestControl.issueCaptureRequests()
+
+ // waits for requests to be submitted before camera is simulated to be closed
+ advanceUntilIdle()
+ assumeTrue(fakeCameraGraphSession.submittedRequests.size == captureConfigList.size)
+ val submittedRequests = fakeCameraGraphSession.submittedRequests.toList()
+
+ // clear previous request submission info
+ fakeCameraGraphSession.submittedRequests.clear()
+
+ // simulates onAborted being invoked due to previous camera closing
+ submittedRequests.first().let { request ->
+ request.listeners.forEach { listener ->
+ listener.onAborted(
+ request
+ )
+ }
+ }
+
+ // since new camera has not been set, no other request should have been submitted
+ advanceUntilIdle()
+ assertThat(
+ fakeCameraGraphSession.submittedRequests.size
+ ).isEqualTo(0)
+ }
+
+ @Test
+ fun captureRequestsSubmittedToNextCamera_whenCameraIsClosed(): Unit = runTest(testDispatcher) {
+ fakeCameraGraph.close()
+
+ stillCaptureRequestControl.issueCaptureRequests()
+
+ // making sure issuing is attempted before new camera is not attached
+ advanceUntilIdle()
+
+ stillCaptureRequestControl.setNewUseCaseCamera()
+
+ // the previous request should be submitted in the new camera
+ advanceUntilIdle()
+ assertThat(
+ fakeCameraGraphSession.submittedRequests.size
+ ).isEqualTo(captureConfigList.size)
+ }
+
+ @Test
+ fun captureRequestsNotResubmitted_whenNewCameraIsSet() = runTest(testDispatcher) {
+ stillCaptureRequestControl.issueCaptureRequests()
+ advanceUntilIdle()
+
+ // simulates previous camera closing and new camera being set
+ stillCaptureRequestControl.setNewUseCaseCamera()
+
+ advanceUntilIdle()
+ assertThat(
+ fakeCameraGraphSession.submittedRequests.size
+ ).isEqualTo(0)
+ }
+
+ @Test
+ fun notSubmittedAgain_whenNewCameraIsSetAfterSuccessfullySubmittingPendingRequests() =
+ runTest(testDispatcher) {
+ stillCaptureRequestControl.issueCaptureRequests()
+
+ // waits for requests to be submitted before camera is closing
+ advanceUntilIdle()
+
+ // simulates previous camera closing
+ fakeCameraGraphSession.submittedRequests.first().let { request ->
+ request.listeners.forEach { listener ->
+ listener.onAborted(
+ request
+ )
+ }
+ }
+
+ // new camera is attached
+ stillCaptureRequestControl.setNewUseCaseCamera()
+
+ // the previous request should be submitted again in the new camera
+ advanceUntilIdle()
+
+ // new camera is attached again
+ stillCaptureRequestControl.setNewUseCaseCamera()
+
+ // since the previous request was successful, it should not be submitted again
+ assertThat(
+ fakeCameraGraphSession.submittedRequests.size
+ ).isEqualTo(0)
+ }
+
+ @Test
+ fun noPendingRequestRemaining_whenReset() = runTest(testDispatcher) {
+ // simulate adding to pending list
+ stillCaptureRequestControl.useCaseCamera = null
+ stillCaptureRequestControl.issueCaptureRequests()
+ stillCaptureRequestControl.issueCaptureRequests()
+
+ // reset after all operations are done
+ advanceUntilIdle()
+ stillCaptureRequestControl.reset()
+
+ // new camera is attached
+ stillCaptureRequestControl.setNewUseCaseCamera()
+
+ // if no new request submitted, it should imply all pending requests were cleared
+ advanceUntilIdle()
+ assertThat(
+ fakeCameraGraphSession.submittedRequests.size
+ ).isEqualTo(0)
+ }
+
+ @Test
+ fun allPendingRequestsAreCancelled_whenReset() = runTest(testDispatcher) {
+ // simulate adding to pending list
+ stillCaptureRequestControl.useCaseCamera = null
+ val requestFutures = listOf(
+ stillCaptureRequestControl.issueCaptureRequests(),
+ stillCaptureRequestControl.issueCaptureRequests()
+ )
+
+ // reset after all operations are done
+ advanceUntilIdle()
+ stillCaptureRequestControl.reset()
+
+ advanceUntilIdle()
+ requestFutures.forEach { it.failsWithCameraClosedError() }
+ }
+
+ private fun StillCaptureRequestControl.issueCaptureRequests() =
+ issueCaptureRequests(
+ captureConfigList,
+ CAPTURE_MODE_MINIMIZE_LATENCY,
+ FLASH_MODE_OFF
+ )
+
+ private fun <T> ListenableFuture<T>.completes(timeoutMs: Long = 1000) {
+ get(timeoutMs, TimeUnit.MILLISECONDS)
+ }
+
+ private fun <T> ListenableFuture<T>.failsWithTimeout(timeoutMs: Long = 1000) {
+ assertThrows(TimeoutException::class.java) {
+ get(timeoutMs, TimeUnit.MILLISECONDS)
+ }
+ }
+
+ private fun <T> ListenableFuture<T>.failsWithCaptureFailedError(timeoutMs: Long = 1000) {
+ assertThrows(ExecutionException::class.java) {
+ get(timeoutMs, TimeUnit.MILLISECONDS)
+ }.apply {
+ assertThat(cause).isInstanceOf(ImageCaptureException::class.java)
+ assertThat((cause as ImageCaptureException).imageCaptureError)
+ .isEqualTo(ImageCapture.ERROR_CAPTURE_FAILED)
+ }
+ }
+
+ private fun <T> ListenableFuture<T>.failsWithCameraClosedError(timeoutMs: Long = 1000) {
+ assertThrows(ExecutionException::class.java) {
+ get(timeoutMs, TimeUnit.MILLISECONDS)
+ }.apply {
+ assertThat(cause).isInstanceOf(ImageCaptureException::class.java)
+ assertThat((cause as ImageCaptureException).imageCaptureError)
+ .isEqualTo(ImageCapture.ERROR_CAMERA_CLOSED)
+ }
+ }
+
+ private fun createCaptureFailure(): CaptureFailure {
+ val c = Class.forName("android.hardware.camera2.CaptureFailure")
+ val constructor = c.getDeclaredConstructor()
+ constructor.isAccessible = true
+ return constructor.newInstance() as CaptureFailure
+ }
+
+ private fun initUseCaseCameraScopeObjects() {
+ fakeCameraGraphSession = FakeCameraGraphSession()
+ fakeCameraGraph = FakeCameraGraph(
+ fakeCameraGraphSession = fakeCameraGraphSession,
+ )
+ fakeUseCaseGraphConfig = UseCaseGraphConfig(
+ graph = fakeCameraGraph,
+ surfaceToStreamMap = mapOf(fakeSurface to StreamId(0)),
+ cameraStateAdapter = CameraStateAdapter(),
+ )
+ fakeConfigAdapter = CaptureConfigAdapter(
+ useCaseGraphConfig = fakeUseCaseGraphConfig,
+ cameraProperties = fakeCameraProperties,
+ threads = fakeUseCaseThreads,
+ )
+ fakeUseCaseCameraState = UseCaseCameraState(
+ useCaseGraphConfig = fakeUseCaseGraphConfig,
+ threads = fakeUseCaseThreads,
+ )
+ requestControl = UseCaseCameraRequestControlImpl(
+ capturePipeline = CapturePipelineImpl(
+ cameraProperties = fakeCameraProperties,
+ requestListener = ComboRequestListener(),
+ threads = fakeUseCaseThreads,
+ torchControl = TorchControl(
+ fakeCameraProperties,
+ fakeState3AControl,
+ fakeUseCaseThreads
+ ),
+ useCaseGraphConfig = fakeUseCaseGraphConfig,
+ useCaseCameraState = fakeUseCaseCameraState,
+ useTorchAsFlash = NotUseTorchAsFlash,
+ ),
+ configAdapter = fakeConfigAdapter,
+ state = fakeUseCaseCameraState,
+ useCaseGraphConfig = fakeUseCaseGraphConfig,
+ )
+ fakeUseCaseCamera = FakeUseCaseCamera(
+ requestControl = requestControl,
+ )
+ }
+
+ private fun StillCaptureRequestControl.setNewUseCaseCamera() {
+ initUseCaseCameraScopeObjects()
+ useCaseCamera = fakeUseCaseCamera
+ }
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControlTest.kt
index 505b310..c129403 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControlTest.kt
@@ -90,7 +90,6 @@
capturePipeline = FakeCapturePipeline(),
configAdapter = fakeConfigAdapter,
state = fakeUseCaseCameraState,
- threads = useCaseThreads,
useCaseGraphConfig = fakeUseCaseGraphConfig,
)
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraStateTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraStateTest.kt
index aa45384..a724e46 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraStateTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraStateTest.kt
@@ -28,20 +28,23 @@
import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraphSession.RequestStatus.FAILED
import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraphSession.RequestStatus.TOTAL_CAPTURE_DONE
import androidx.camera.camera2.pipe.integration.testing.FakeSurface
-import androidx.camera.core.CameraControl
import androidx.camera.core.impl.DeferrableSurface
-import com.google.common.truth.Truth.assertThat
+import androidx.testutils.MainDispatcherRule
+import com.google.common.truth.Truth.assertWithMessage
import com.google.common.util.concurrent.ListenableFuture
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.CompletableDeferred
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
@@ -50,17 +53,21 @@
@RunWith(RobolectricCameraPipeTestRunner::class)
@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
@DoNotInstrument
+@OptIn(ExperimentalCoroutinesApi::class)
class UseCaseCameraStateTest {
+ private val testScope = TestScope()
+ private val testDispatcher = StandardTestDispatcher(testScope.testScheduler)
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule(testDispatcher)
+
private val surface = FakeSurface()
private val surfaceToStreamMap: Map<DeferrableSurface, StreamId> = mapOf(surface to StreamId(0))
private val useCaseThreads by lazy {
- val dispatcher = Dispatchers.Default
- val cameraScope = CoroutineScope(Job() + dispatcher)
-
UseCaseThreads(
- cameraScope,
- dispatcher.asExecutor(),
- dispatcher
+ testScope,
+ testDispatcher.asExecutor(),
+ testDispatcher
)
}
@@ -119,7 +126,7 @@
}
@Test
- fun updateAsyncFails_whenStartRepeatingRequestIsAborted(): Unit = runBlocking {
+ fun updateAsyncIncomplete_whenStartRepeatingRequestIsAborted(): Unit = runTest {
// startRepeating is called when there is at least one stream after updateAsync call
val result = useCaseCameraState.updateAsync(
streams = setOf(StreamId(0))
@@ -128,10 +135,54 @@
// simulate startRepeating request being aborted by camera framework level
fakeCameraGraphSession.startRepeatingSignal.complete(ABORTED)
- assertFutureFails(result)
+ advanceUntilIdle()
+ assertFutureStillWaiting(result)
}
@Test
+ fun updateAsyncIncomplete_whenNewRequestSubmitted(): Unit = runTest {
+ // startRepeating is called when there is at least one stream after updateAsync call
+ val result = useCaseCameraState.updateAsync(
+ streams = setOf(StreamId(0))
+ ).asListenableFuture()
+
+ // simulate startRepeating request being aborted by camera framework level
+ fakeCameraGraphSession.startRepeatingSignal.complete(ABORTED)
+ advanceUntilIdle()
+
+ // simulate startRepeating being called again
+ fakeCameraGraphSession.startRepeatingSignal = CompletableDeferred() // reset
+ useCaseCameraState.updateAsync(
+ streams = setOf(StreamId(0))
+ )
+
+ advanceUntilIdle()
+ assertFutureStillWaiting(result)
+ }
+
+ @Test
+ fun previousUpdateAsyncCompletes_whenNewStartRepeatingRequestCompletesAfterAbort(): Unit =
+ runTest {
+ // startRepeating is called when there is at least one stream after updateAsync call
+ val result = useCaseCameraState.updateAsync(
+ streams = setOf(StreamId(0))
+ ).asListenableFuture()
+
+ // simulate startRepeating request being aborted by camera framework level
+ fakeCameraGraphSession.startRepeatingSignal.complete(ABORTED)
+ advanceUntilIdle()
+
+ // simulate startRepeating being called again
+ fakeCameraGraphSession.startRepeatingSignal = CompletableDeferred() // reset
+ useCaseCameraState.updateAsync(
+ streams = setOf(StreamId(0))
+ )
+ fakeCameraGraphSession.startRepeatingSignal.complete(TOTAL_CAPTURE_DONE) // completed
+
+ assertFutureCompletes(result)
+ }
+
+ @Test
fun previousUpdateAsyncCompletes_whenInvokedTwice(): Unit = runBlocking {
// startRepeating is called when there is at least one stream after updateAsync call
val result = useCaseCameraState.updateAsync(
@@ -158,11 +209,8 @@
}
}
- private fun <T> assertFutureFailsWithOperationCanceledException(future: ListenableFuture<T>) {
- assertThrows(ExecutionException::class.java) {
- future[3, TimeUnit.SECONDS]
- }.apply {
- assertThat(cause).isInstanceOf(CameraControl.OperationCanceledException::class.java)
- }
+ private fun <T> assertFutureStillWaiting(future: ListenableFuture<T>) {
+ assertWithMessage("Future already completed instead of waiting")
+ .that(future.isDone).isFalse()
}
}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraTest.kt
index cdf0307..20d762e 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraTest.kt
@@ -18,6 +18,7 @@
import android.hardware.camera2.CameraDevice
import android.os.Build
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraPipe
import androidx.camera.camera2.pipe.StreamId
import androidx.camera.camera2.pipe.integration.adapter.CameraStateAdapter
@@ -85,7 +86,6 @@
capturePipeline = FakeCapturePipeline(),
configAdapter = fakeConfigAdapter,
state = fakeUseCaseCameraState,
- threads = useCaseThreads,
useCaseGraphConfig = fakeUseCaseGraphConfig,
)
@@ -140,6 +140,7 @@
}
}
+@RequiresApi(21)
private class FakeTestUseCase() : FakeUseCase(
FakeUseCaseConfig.Builder().setTargetName("UseCase").useCaseConfig
) {
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
index d4488e2..b155784 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
@@ -16,6 +16,7 @@
package androidx.camera.camera2.pipe.integration.impl
+import android.hardware.camera2.CameraCharacteristics
import android.os.Build
import android.util.Size
import androidx.camera.camera2.pipe.CameraGraph
@@ -52,10 +53,15 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
+import org.robolectric.shadows.StreamConfigurationMapBuilder
@RunWith(RobolectricCameraPipeTestRunner::class)
@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
class UseCaseManagerTest {
+ private val supportedSizes = arrayOf(Size(640, 480))
+ private val streamConfigurationMap = StreamConfigurationMapBuilder.newBuilder().apply {
+ supportedSizes.forEach(::addOutputSize)
+ }.build()
private val useCaseManagerList = mutableListOf<UseCaseManager>()
private val useCaseList = mutableListOf<UseCase>()
private val useCaseThreads by lazy {
@@ -173,7 +179,7 @@
useCaseManager.activate(imageCapture)
// Act
- useCaseManager.deactivate(preview)
+ useCaseManager.detach(listOf(preview))
// Assert
val enabledUseCaseClasses = useCaseManager.camera?.runningUseCases?.map {
@@ -201,7 +207,7 @@
useCaseCameraBuilder.buildInvocationCount = 0
// Act
- useCaseManager.deactivate(preview)
+ useCaseManager.detach(listOf(preview))
// Assert
assertThat(useCaseCameraBuilder.buildInvocationCount).isEqualTo(1)
@@ -248,7 +254,9 @@
// Arrange
val useCaseManager = createUseCaseManager()
val imageCapture = createImageCapture()
- val useCase = FakeUseCase()
+ val useCase = FakeUseCase().also {
+ it.simulateActivation()
+ }
// Act
useCaseManager.activate(imageCapture)
@@ -313,12 +321,23 @@
useCaseCameraComponentBuilder: FakeUseCaseCameraComponentBuilder =
FakeUseCaseCameraComponentBuilder(),
): UseCaseManager {
+ val cameraId = CameraId("0")
+ val characteristicsMap: Map<CameraCharacteristics.Key<*>, Any?> = mapOf(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP to streamConfigurationMap,
+ )
+ val fakeCameraMetadata = FakeCameraMetadata(
+ cameraId = cameraId,
+ characteristics = characteristicsMap
+ )
val fakeCamera = FakeCamera()
return UseCaseManager(
- cameraConfig = CameraConfig(CameraId("0")),
+ cameraConfig = CameraConfig(cameraId),
builder = useCaseCameraComponentBuilder,
controls = controls as java.util.Set<UseCaseCameraControl>,
- cameraProperties = FakeCameraProperties(),
+ cameraProperties = FakeCameraProperties(
+ metadata = fakeCameraMetadata,
+ cameraId = cameraId,
+ ),
camera2CameraControl = Camera2CameraControl.create(
FakeCamera2CameraControlCompat(),
useCaseThreads,
@@ -328,10 +347,11 @@
cameraGraphFlags = CameraGraph.Flags(),
cameraInternal = { fakeCamera },
cameraQuirks = CameraQuirks(
- FakeCameraMetadata(),
- StreamConfigurationMapCompat(null, OutputSizesCorrector(FakeCameraMetadata(), null))
+ fakeCameraMetadata,
+ StreamConfigurationMapCompat(null, OutputSizesCorrector(fakeCameraMetadata, null))
),
displayInfoManager = DisplayInfoManager(ApplicationProvider.getApplicationContext()),
+ context = ApplicationProvider.getApplicationContext(),
).also {
useCaseManagerList.add(it)
}
@@ -362,6 +382,6 @@
private fun UseCase.simulateActivation() {
bindToCamera(FakeCamera("0"), null, null)
- updateSuggestedStreamSpec(StreamSpec.builder(Size(640, 480)).build())
+ updateSuggestedStreamSpec(StreamSpec.builder(supportedSizes[0]).build())
}
}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/interop/Camera2InteropTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/interop/Camera2InteropTest.kt
index c1b6b4c..3416c30 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/interop/Camera2InteropTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/interop/Camera2InteropTest.kt
@@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+@file:RequiresApi(21)
+
package androidx.camera.camera2.pipe.integration.interop
import android.hardware.camera2.CameraCaptureSession
@@ -21,6 +24,7 @@
import android.hardware.camera2.CaptureRequest
import android.os.Build
import android.util.Range
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.integration.adapter.RobolectricCameraPipeTestRunner
import androidx.camera.camera2.pipe.integration.impl.CAPTURE_REQUEST_ID_STEM
import androidx.camera.camera2.pipe.integration.impl.Camera2ImplConfig
@@ -80,6 +84,7 @@
)
}
+ @Config(minSdk = 33)
@Test
fun canExtendWithStreamUseCase() {
// Arrange
@@ -237,6 +242,7 @@
}
}
+ @Config(minSdk = 28)
@Test
fun canExtendWithPhysicalCameraId() {
// Arrange
@@ -249,4 +255,4 @@
// Assert
assertThat(config.getPhysicalCameraId(null)).isEqualTo(PHYSICAL_CAMERA_ID)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCamera2CameraControlCompat.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCamera2CameraControlCompat.kt
index 13cc26d..a638d73 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCamera2CameraControlCompat.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCamera2CameraControlCompat.kt
@@ -16,6 +16,7 @@
package androidx.camera.camera2.pipe.integration.testing
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.integration.compat.Camera2CameraControlCompat
import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
import androidx.camera.camera2.pipe.integration.interop.CaptureRequestOptions
@@ -24,6 +25,7 @@
import kotlinx.coroutines.Deferred
@OptIn(ExperimentalCamera2Interop::class)
+@RequiresApi(21)
class FakeCamera2CameraControlCompat : Camera2CameraControlCompat {
override fun addRequestOption(bundle: CaptureRequestOptions) {
// No-op
@@ -44,4 +46,4 @@
override fun applyAsync(camera: UseCaseCamera?, cancelPreviousTask: Boolean): Deferred<Void?> {
return CompletableDeferred(null)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraph.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraph.kt
index a3bbc1e..9821ced 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraph.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraph.kt
@@ -17,17 +17,21 @@
package androidx.camera.camera2.pipe.integration.testing
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.GraphState
import androidx.camera.camera2.pipe.StreamGraph
import androidx.camera.camera2.pipe.StreamId
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.flow.StateFlow
+@RequiresApi(21)
class FakeCameraGraph(
val fakeCameraGraphSession: FakeCameraGraphSession = FakeCameraGraphSession()
) : CameraGraph {
val setSurfaceResults = mutableMapOf<StreamId, Surface?>()
+ private var isClosed = false
override val streams: StreamGraph
get() = throw NotImplementedError("Not used in testing")
@@ -37,15 +41,16 @@
override var isForeground = false
override suspend fun acquireSession(): CameraGraph.Session {
+ if (isClosed) {
+ throw CancellationException()
+ }
return fakeCameraGraphSession
}
- override fun acquireSessionOrNull(): CameraGraph.Session {
- return fakeCameraGraphSession
- }
+ override fun acquireSessionOrNull() = if (isClosed) null else fakeCameraGraphSession
override fun close() {
- throw NotImplementedError("Not used in testing")
+ isClosed = true
}
override fun setSurface(stream: StreamId, surface: Surface?) {
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraphSession.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraphSession.kt
index 3b2e8df..ebc5958 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraphSession.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraphSession.kt
@@ -18,6 +18,7 @@
import android.hardware.camera2.CaptureFailure
import android.hardware.camera2.params.MeteringRectangle
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.AeMode
import androidx.camera.camera2.pipe.AfMode
import androidx.camera.camera2.pipe.AwbMode
@@ -37,11 +38,12 @@
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.runBlocking
+@RequiresApi(21)
open class FakeCameraGraphSession : CameraGraph.Session {
val repeatingRequests = mutableListOf<Request>()
var repeatingRequestSemaphore = Semaphore(0)
- val stopRepeatingSemaphore = Semaphore(0)
+ var stopRepeatingSemaphore = Semaphore(0)
enum class RequestStatus {
TOTAL_CAPTURE_DONE,
@@ -50,6 +52,8 @@
}
var startRepeatingSignal = CompletableDeferred(TOTAL_CAPTURE_DONE) // already completed
+ val submittedRequests = mutableListOf<Request>()
+
override fun abort() {
// No-op
}
@@ -101,11 +105,11 @@
}
override fun submit(request: Request) {
- throw NotImplementedError("Not used in testing")
+ submittedRequests.add(request)
}
override fun submit(requests: List<Request>) {
- // No-op
+ submittedRequests.addAll(requests)
}
override suspend fun submit3A(
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
index 3e93b84..21c789a 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
@@ -21,6 +21,7 @@
import android.hardware.camera2.params.StreamConfigurationMap
import android.util.Range
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraId
import androidx.camera.camera2.pipe.integration.adapter.CameraControlStateAdapter
import androidx.camera.camera2.pipe.integration.adapter.CameraInfoAdapter
@@ -50,6 +51,7 @@
import kotlinx.coroutines.asCoroutineDispatcher
import org.robolectric.shadows.StreamConfigurationMapBuilder
+@RequiresApi(21)
object FakeCameraInfoAdapterCreator {
private val CAMERA_ID_0 = CameraId("0")
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeEvCompCompat.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeEvCompCompat.kt
index afd3de9..75470a6 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeEvCompCompat.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeEvCompCompat.kt
@@ -18,10 +18,12 @@
import android.util.Range
import android.util.Rational
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.integration.compat.EvCompCompat
import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
import kotlinx.coroutines.Deferred
+@RequiresApi(21)
class FakeEvCompCompat constructor(
override val supported: Boolean = false,
override val range: Range<Int> = Range(0, 0),
@@ -38,4 +40,4 @@
): Deferred<Int> {
TODO("Not yet implemented")
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeMeteringPointFactory.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeMeteringPointFactory.kt
index 2ebc216..1735ab6 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeMeteringPointFactory.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeMeteringPointFactory.kt
@@ -17,10 +17,12 @@
package androidx.camera.camera2.pipe.integration.adapter
import android.graphics.PointF
+import androidx.annotation.RequiresApi
import androidx.camera.core.MeteringPointFactory
+@RequiresApi(21)
class FakeMeteringPointFactory : MeteringPointFactory() {
override fun convertPoint(x: Float, y: Float): PointF {
return PointF(x, y)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeState3AControlCreator.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeState3AControlCreator.kt
new file mode 100644
index 0000000..3b30f5d
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeState3AControlCreator.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.camera.camera2.pipe.integration.testing
+
+import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.integration.compat.StreamConfigurationMapCompat
+import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
+import androidx.camera.camera2.pipe.integration.compat.workaround.AeFpsRange
+import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpAutoFlashAEModeDisabler
+import androidx.camera.camera2.pipe.integration.compat.workaround.OutputSizesCorrector
+import androidx.camera.camera2.pipe.integration.impl.CameraProperties
+import androidx.camera.camera2.pipe.integration.impl.State3AControl
+import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
+import org.robolectric.shadows.StreamConfigurationMapBuilder
+
+@RequiresApi(21)
+object FakeState3AControlCreator {
+ fun createState3AControl(
+ properties: CameraProperties = FakeCameraProperties(),
+ useCaseCamera: UseCaseCamera = FakeUseCaseCamera(),
+ ) = State3AControl(
+ properties,
+ NoOpAutoFlashAEModeDisabler,
+ AeFpsRange(
+ CameraQuirks(
+ properties.metadata,
+ StreamConfigurationMapCompat(
+ StreamConfigurationMapBuilder.newBuilder().build(),
+ OutputSizesCorrector(
+ properties.metadata,
+ StreamConfigurationMapBuilder.newBuilder().build()
+ )
+ )
+ )
+ )
+ ).apply {
+ this.useCaseCamera = useCaseCamera
+ }
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeSurface.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeSurface.kt
index 67e6e9e..c391a58 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeSurface.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeSurface.kt
@@ -17,14 +17,16 @@
package androidx.camera.camera2.pipe.integration.testing
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.core.impl.DeferrableSurface
import androidx.camera.core.impl.utils.futures.Futures
import com.google.common.util.concurrent.ListenableFuture
+@RequiresApi(21)
class FakeSurface(
val surface: Surface? = null
) : DeferrableSurface() {
override fun provideSurface(): ListenableFuture<Surface> {
return Futures.immediateFuture(surface)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
index 20f7342..2a9a2ef 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
@@ -14,10 +14,13 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.camera2.pipe.integration.testing
import android.hardware.camera2.CaptureRequest
import android.hardware.camera2.params.MeteringRectangle
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.AeMode
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.Lock3ABehavior
diff --git a/camera/camera-camera2-pipe-testing/api/current.txt b/camera/camera-camera2-pipe-testing/api/current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-camera2-pipe-testing/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-camera2-pipe-testing/api/res-current.txt b/camera/camera-camera2-pipe-testing/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-camera2-pipe-testing/api/res-current.txt
diff --git a/camera/camera-camera2-pipe-testing/api/restricted_current.txt b/camera/camera-camera2-pipe-testing/api/restricted_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-camera2-pipe-testing/api/restricted_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-camera2-pipe-testing/build.gradle b/camera/camera-camera2-pipe-testing/build.gradle
index 1d31206..86815ad 100644
--- a/camera/camera-camera2-pipe-testing/build.gradle
+++ b/camera/camera-camera2-pipe-testing/build.gradle
@@ -16,7 +16,6 @@
import androidx.build.Publish
-import androidx.build.RunApiTasks
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
@@ -30,6 +29,7 @@
api("androidx.annotation:annotation:1.1.0")
// Classes and types that are only needed at runtime
+ implementation(libs.atomicFu)
implementation(libs.kotlinStdlib)
implementation(libs.kotlinCoroutinesGuava)
implementation(libs.kotlinCoroutinesTest)
@@ -63,7 +63,6 @@
name = "Camera2 Pipe Testing"
publish = Publish.SNAPSHOT_AND_RELEASE
mavenVersion = LibraryVersions.CAMERA_PIPE
- runApiTasks = new RunApiTasks.No("CameraPipe is an implementation detail of other libraries.")
inceptionYear = "2020"
description = "Testing components for the Camera2 Pipe Library, a library providing a " +
"consistent and reliable camera foundation that enables great camera driven " +
diff --git a/camera/camera-camera2-pipe-testing/lint.xml b/camera/camera-camera2-pipe-testing/lint.xml
deleted file mode 100644
index 0843ecf..0000000
--- a/camera/camera-camera2-pipe-testing/lint.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
- <!-- Disable NewApi lint check temporarily for unit tests.
- This file can be removed once b/200599470 is resolved. -->
- <issue id="NewApi">
- <ignore path="src/test/**" />
- </issue>
-</lint>
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraBackend.kt b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraBackend.kt
index 1e1f6a3..7300290 100644
--- a/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraBackend.kt
+++ b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraBackend.kt
@@ -50,6 +50,7 @@
get() = MutableSharedFlow()
override fun awaitCameraIds(): List<CameraId> = fakeCameraIds
+ override fun awaitConcurrentCameraIds(): Set<Set<CameraId>> = emptySet()
override fun awaitCameraMetadata(cameraId: CameraId): CameraMetadata? = fakeCameras[cameraId]
diff --git a/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraDevices.kt b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraDevices.kt
index 8352e33..268f1bd 100644
--- a/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraDevices.kt
+++ b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraDevices.kt
@@ -44,6 +44,16 @@
return cameraMetadataMap[backendId]?.map { it.camera }
}
+ override suspend fun getConcurrentCameraIds(
+ cameraBackendId: CameraBackendId?
+ ): Set<Set<CameraId>> {
+ return emptySet()
+ }
+
+ override fun awaitConcurrentCameraIds(cameraBackendId: CameraBackendId?): Set<Set<CameraId>> {
+ return emptySet()
+ }
+
override suspend fun getCameraMetadata(
cameraId: CameraId,
cameraBackendId: CameraBackendId?
diff --git a/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/package-info.java b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/package-info.java
new file mode 100644
index 0000000..36877d3
--- /dev/null
+++ b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+package androidx.camera.camera2.pipe.testing;
+
+import androidx.annotation.RestrictTo;
diff --git a/camera/camera-camera2-pipe-testing/src/test/java/androidx/camera/camera2/pipe/testing/FakeMetadataTest.kt b/camera/camera-camera2-pipe-testing/src/test/java/androidx/camera/camera2/pipe/testing/FakeMetadataTest.kt
index 11d2c2c..74f9340 100644
--- a/camera/camera-camera2-pipe-testing/src/test/java/androidx/camera/camera2/pipe/testing/FakeMetadataTest.kt
+++ b/camera/camera-camera2-pipe-testing/src/test/java/androidx/camera/camera2/pipe/testing/FakeMetadataTest.kt
@@ -25,6 +25,7 @@
import androidx.camera.camera2.pipe.FrameNumber
import androidx.camera.camera2.pipe.MetadataTransform
import androidx.camera.camera2.pipe.Request
+import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@@ -32,6 +33,7 @@
import org.robolectric.annotation.Config
@RunWith(JUnit4::class)
+@SdkSuppress(minSdkVersion = 21)
public class MetadataTest {
@Test
public fun testMetadataCanRetrieveValues() {
diff --git a/camera/camera-camera2-pipe/api/current.txt b/camera/camera-camera2-pipe/api/current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-camera2-pipe/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-camera2-pipe/api/res-current.txt b/camera/camera-camera2-pipe/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-camera2-pipe/api/res-current.txt
diff --git a/camera/camera-camera2-pipe/api/restricted_current.txt b/camera/camera-camera2-pipe/api/restricted_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-camera2-pipe/api/restricted_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-camera2-pipe/build.gradle b/camera/camera-camera2-pipe/build.gradle
index e2a6054..4338882 100644
--- a/camera/camera-camera2-pipe/build.gradle
+++ b/camera/camera-camera2-pipe/build.gradle
@@ -16,7 +16,6 @@
import androidx.build.Publish
-import androidx.build.RunApiTasks
plugins {
id("AndroidXPlugin")
@@ -25,14 +24,13 @@
id("kotlin-kapt")
}
-apply from: "dependencies.gradle"
-
dependencies {
- // NOTE: API and IMPLEMENTATION dependencies are defined in dependencies.gradle to export for
- // other modules depending on the jarjar variant of CameraPipe. All dependencies should be
- // added there rather than directly here.
- api(CAMERA_PIPE_DEPS.API)
- implementation(CAMERA_PIPE_DEPS.IMPLEMENTATION)
+ api("androidx.annotation:annotation:1.2.0")
+ api(libs.kotlinStdlib)
+ api(libs.kotlinCoroutinesAndroid)
+
+ implementation(libs.atomicFu)
+ implementation(libs.dagger)
kapt(libs.daggerCompiler)
@@ -74,7 +72,6 @@
name = "Camera2 Pipe"
publish = Publish.SNAPSHOT_AND_RELEASE
mavenVersion = LibraryVersions.CAMERA_PIPE
- runApiTasks = new RunApiTasks.No("CameraPipe is an implementation detail of other libraries.")
inceptionYear = "2020"
description = "A set of opinionated camera interfaces and implementations on top of Camera2 " +
"that will form a flexible shim layer to power Frameserver and CameraX."
diff --git a/camera/camera-camera2-pipe/dependencies.gradle b/camera/camera-camera2-pipe/dependencies.gradle
deleted file mode 100644
index e27053d..0000000
--- a/camera/camera-camera2-pipe/dependencies.gradle
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-ext {
- CAMERA_PIPE_DEPS = [
- API : [
- "androidx.annotation:annotation:1.2.0",
- libs.kotlinStdlib,
- libs.kotlinCoroutinesAndroid,
- "org.jetbrains.kotlinx:atomicfu:0.13.1"
- ],
- IMPLEMENTATION: [libs.dagger]
- ]
-}
diff --git a/camera/camera-camera2-pipe/lint.xml b/camera/camera-camera2-pipe/lint.xml
deleted file mode 100644
index 0843ecf..0000000
--- a/camera/camera-camera2-pipe/lint.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
- <!-- Disable NewApi lint check temporarily for unit tests.
- This file can be removed once b/200599470 is resolved. -->
- <issue id="NewApi">
- <ignore path="src/test/**" />
- </issue>
-</lint>
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraBackend.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraBackend.kt
index 66cbd6f..699f614 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraBackend.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraBackend.kt
@@ -15,11 +15,13 @@
*/
package androidx.camera.camera2.pipe
+import androidx.annotation.RestrictTo
import androidx.camera.camera2.pipe.graph.GraphListener
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.flow.Flow
/** This is used to uniquely identify a specific backend implementation. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class CameraBackendId(val value: String)
@@ -28,6 +30,7 @@
* cameras changes, for instance when the camera access priorities have changed or when a particular
* camera has become available.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface CameraStatusMonitor {
val cameraStatus: Flow<CameraStatus>
@@ -50,6 +53,7 @@
* The lifecycle of an individual camera is managed by [CameraController]s, which may be created via
* [CameraBackend.createCameraController].
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface CameraBackend {
val id: CameraBackendId
@@ -70,6 +74,16 @@
fun awaitCameraIds(): List<CameraId>?
/**
+ * Read out a set of [CameraId] sets that can be operated concurrently. When multiple cameras
+ * are open, the number of configurable streams, as well as their sizes, might be considerably
+ * limited.
+ */
+ suspend fun getConcurrentCameraIds(): Set<Set<CameraId>>? = awaitConcurrentCameraIds()
+
+ /** Thread-blocking version of [getConcurrentCameraIds] for compatibility. */
+ fun awaitConcurrentCameraIds(): Set<Set<CameraId>>?
+
+ /**
* Retrieve [CameraMetadata] for this backend. Backends may cache the results of these calls.
*
* This call should should always succeed if the [CameraId] is in the list of ids returned by
@@ -123,6 +137,7 @@
* returned instances is managed by [CameraPipe] unless the application asks [CameraPipe] to close
* and release previously created [CameraBackend]s.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun interface CameraBackendFactory {
/** Create a new [CameraBackend] instance based on the provided [CameraContext]. */
fun create(cameraContext: CameraContext): CameraBackend
@@ -132,6 +147,7 @@
* Api for requesting and interacting with [CameraBackend] that are available in the current
* [CameraPipe] instance.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface CameraBackends {
/**
* This provides access to the default [CameraBackend]. Accessing this property will create the
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraContext.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraContext.kt
index a4908d0..0766513 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraContext.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraContext.kt
@@ -17,6 +17,7 @@
package androidx.camera.camera2.pipe
import android.content.Context
+import androidx.annotation.RestrictTo
import androidx.camera.camera2.pipe.core.Threads
/**
@@ -26,6 +27,7 @@
* [CameraContext] is primarily used to share resources between [CameraBackend] factories and
* between [CameraController] instances.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface CameraContext {
val appContext: Context
val threads: Threads
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraController.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraController.kt
index fc864da..c8d1862 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraController.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraController.kt
@@ -17,6 +17,7 @@
package androidx.camera.camera2.pipe
import android.view.Surface
+import androidx.annotation.RestrictTo
import androidx.camera.camera2.pipe.CameraController.ControllerState.CLOSED
import androidx.camera.camera2.pipe.graph.GraphListener
@@ -35,6 +36,7 @@
*
* Once [close] is invoked, this instance should not respond to any additional events.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface CameraController {
val cameraId: CameraId
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraControls.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraControls.kt
index 556d1a6..09c9c59 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraControls.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraControls.kt
@@ -22,11 +22,13 @@
import android.hardware.camera2.CaptureResult
import android.hardware.camera2.TotalCaptureResult
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
import androidx.camera.camera2.pipe.Result3A.Status
// Public controls and enums used to interact with a CameraGraph.
/** An enum to match the CameraMetadata.CONTROL_AF_MODE_* constants. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class AfMode(val value: Int) {
companion object {
@@ -45,6 +47,7 @@
}
/** An enum to match the CameraMetadata.CONTROL_AE_MODE_* constants. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class AeMode(val value: Int) {
companion object {
@@ -64,6 +67,7 @@
}
/** An enum to match the CameraMetadata.CONTROL_AWB_MODE_* constants. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class AwbMode(val value: Int) {
companion object {
@@ -85,6 +89,7 @@
}
/** An enum to match the CameraMetadata.FLASH_MODE_* constants. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class FlashMode(val value: Int) {
companion object {
@@ -109,6 +114,7 @@
*
* #CONTROL_AE_MODE_ON
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class TorchState private constructor() {
companion object {
val ON = TorchState()
@@ -117,6 +123,7 @@
}
/** Requirement to consider prior to locking auto-exposure, auto-focus and auto-whitebalance. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class Lock3ABehavior private constructor(val value: Int) {
companion object {
@@ -154,6 +161,7 @@
* completion of the method, in that case this frameMetadata may not contain all the kay value
* pairs associated with the final result i.e. [TotalCaptureResult] of this frame.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
data class Result3A(val status: Status, val frameMetadata: FrameMetadata? = null) {
/**
* Enum to know the status of 3A operation in case the method returns before the desired
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraDevices.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraDevices.kt
index 9736e8b..59c1012 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraDevices.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraDevices.kt
@@ -20,25 +20,44 @@
package androidx.camera.camera2.pipe
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
/** Methods for querying, iterating, and selecting the Cameras that are available on the device. */
interface CameraDevices {
/**
- * Read the list of currently openable CameraIds from the provided CameraBackend, suspending if
- * needed. By default this will load the list of openable CameraIds from the default backend.
+ * Read the list of currently openable [CameraId]s from the provided CameraBackend, suspending
+ * if needed. By default this will load the list of openable [CameraId]s from the default
+ * backend.
*/
suspend fun getCameraIds(cameraBackendId: CameraBackendId? = null): List<CameraId>?
/**
- * Read the list of currently openable CameraIds from the provided CameraBackend, blocking the
- * thread if needed. By default this will load the list of openable CameraIds from the default
+ * Read the list of currently openable [CameraId]s from the provided CameraBackend, blocking the
+ * thread if needed. By default this will load the list of openable [CameraId]s from the default
* backend.
*/
fun awaitCameraIds(cameraBackendId: CameraBackendId? = null): List<CameraId>?
/**
+ * Read the set of [CameraId] sets that can be operated concurrently from the provided
+ * CameraBackend, suspending if needed. By default this will load the set of [CameraId] sets
+ * from the default backend.
+ */
+ suspend fun getConcurrentCameraIds(
+ cameraBackendId: CameraBackendId? = null
+ ): Set<Set<CameraId>>?
+
+ /**
+ * Read the set of [CameraId] sets that can be operated concurrently from the provided
+ * CameraBackend, blocking the thread if needed. By default this will load the set of [CameraId]
+ * sets from the default backend.
+ */
+ fun awaitConcurrentCameraIds(cameraBackendId: CameraBackendId? = null): Set<Set<CameraId>>?
+
+ /**
* Read metadata for a specific camera id, suspending if needed. By default, this method will
* query metadata from the default backend if one is not specified.
*/
@@ -106,6 +125,7 @@
/**
* CameraId represents a typed identifier for a camera represented as a non-blank String.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class CameraId(val value: String) {
init {
@@ -133,6 +153,7 @@
* metadata of cameras that are otherwise hidden. Metadata for hidden cameras are always returned
* last.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun CameraDevices.find(
cameraBackendId: CameraBackendId? = null,
includePhysicalCameraMetadata: Boolean = false
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraError.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraError.kt
index 6de5177..93701f4 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraError.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraError.kt
@@ -25,7 +25,9 @@
import android.hardware.camera2.CameraDevice.StateCallback
import android.os.Build
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
@RequiresApi(21)
value class CameraError private constructor(val value: Int) {
@@ -172,7 +174,9 @@
}
// TODO(b/276918807): When we have CameraProperties, handle the exception on a more granular level.
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class DoNotDisturbException(message: String) : RuntimeException(message)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
// An exception indicating that the CameraDevice.close() call has stalled.
class CameraCloseStallException(message: String) : RuntimeException(message)
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
index d9e9c27..d6a589d 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
@@ -24,9 +24,13 @@
import android.hardware.camera2.params.SessionConfiguration
import android.view.Surface
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
import androidx.camera.camera2.pipe.CameraGraph.Constants3A.DEFAULT_FRAME_LIMIT
import androidx.camera.camera2.pipe.CameraGraph.Constants3A.DEFAULT_TIME_LIMIT_NS
import androidx.camera.camera2.pipe.CameraGraph.Flags.FinalizeSessionOnCloseBehavior.Companion.OFF
+import androidx.camera.camera2.pipe.CameraGraph.OperatingMode.Companion.EXTENSION
+import androidx.camera.camera2.pipe.CameraGraph.OperatingMode.Companion.HIGH_SPEED
+import androidx.camera.camera2.pipe.CameraGraph.OperatingMode.Companion.NORMAL
import androidx.camera.camera2.pipe.GraphState.GraphStateStarting
import androidx.camera.camera2.pipe.GraphState.GraphStateStopped
import androidx.camera.camera2.pipe.GraphState.GraphStateStopping
@@ -34,6 +38,7 @@
import kotlinx.coroutines.flow.StateFlow
/** A [CameraGraph] represents the combined configuration and state of a camera. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
interface CameraGraph : AutoCloseable {
val streams: StreamGraph
@@ -110,6 +115,7 @@
* @param customCameraBackend If defined, this [customCameraBackend] will be created an used for
* _only_ this [CameraGraph]. This cannot be defined if [cameraBackendId] is defined.
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
data class Config(
val camera: CameraId,
val streams: List<CameraStream.Config>,
@@ -117,7 +123,7 @@
val input: InputStream.Config? = null,
val sessionTemplate: RequestTemplate = RequestTemplate(1),
val sessionParameters: Map<*, Any?> = emptyMap<Any, Any?>(),
- val sessionMode: OperatingMode = OperatingMode.NORMAL,
+ val sessionMode: OperatingMode = NORMAL,
val defaultTemplate: RequestTemplate = RequestTemplate(1),
val defaultParameters: Map<*, Any?> = emptyMap<Any, Any?>(),
val defaultListeners: List<Request.Listener> = listOf(),
@@ -125,9 +131,11 @@
val cameraBackendId: CameraBackendId? = null,
val customCameraBackend: CameraBackendFactory? = null,
val metadataTransform: MetadataTransform = MetadataTransform(),
- val flags: Flags = Flags()
+ val flags: Flags = Flags(),
// TODO: Internal error handling. May be better at the CameraPipe level.
) {
+ internal var sharedCameraIds: List<CameraId> = emptyList()
+
init {
check(cameraBackendId == null || customCameraBackend == null) {
"Setting both cameraBackendId and customCameraBackend is not supported."
@@ -140,10 +148,10 @@
* camera2. These flags should default to the ideal behavior and should be overridden on
* specific devices to be faster or to work around bad behavior.
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
data class Flags(
val configureBlankSessionOnStop: Boolean = false,
val abortCapturesOnStop: Boolean = false,
- val allowMultipleActiveCameras: Boolean = false,
/**
* A quirk that waits for the last repeating capture request to start before stopping the
@@ -184,6 +192,17 @@
* - API levels: All
*/
val quirkCloseCaptureSessionOnDisconnect: Boolean = false,
+
+ /**
+ * A quirk that closes the camera device when the CameraGraph is closed. This is needed on
+ * devices where not closing the camera device before creating a new capture session can
+ * lead to crashes.
+ *
+ * - Bug(s): b/282871038
+ * - Device(s): Exynos7870 platforms.
+ * - API levels: All
+ */
+ val quirkCloseCameraDeviceOnClose: Boolean = false,
) {
@JvmInline
@@ -264,6 +283,7 @@
* While this object is thread-safe, it should not shared or held for long periods of time.
* Example: A [Session] should *not* be held during video recording.
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface Session : AutoCloseable {
/**
* Causes the CameraGraph to start or update the current repeating request with the provided
@@ -439,6 +459,7 @@
* [GraphStateStarting], and [CameraGraph.stop] puts the graph into [GraphStateStopping]. Remaining
* states are produced by the underlying camera as a result of these start/stop calls.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
abstract class GraphState internal constructor() {
/**
* When the [CameraGraph] is starting. This means we're in the process of opening a (virtual)
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraMetadata.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraMetadata.kt
index 24cbc65..c8c4d47 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraMetadata.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraMetadata.kt
@@ -22,6 +22,7 @@
import android.hardware.camera2.CaptureRequest
import android.hardware.camera2.CaptureResult
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
/**
* [CameraMetadata] is a compatibility wrapper around [CameraCharacteristics].
@@ -32,6 +33,7 @@
* directly. This allows code to get reasonable behavior for all properties across all OS levels and
* makes behavior that depends on [CameraMetadata] easier to test and reason about.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface CameraMetadata : Metadata, UnsafeWrapper {
operator fun <T> get(key: CameraCharacteristics.Key<T>): T?
fun <T> getOrDefault(key: CameraCharacteristics.Key<T>, default: T): T
@@ -49,88 +51,90 @@
suspend fun getPhysicalMetadata(cameraId: CameraId): CameraMetadata
fun awaitPhysicalMetadata(cameraId: CameraId): CameraMetadata
-}
-/**
- * Extension properties for querying the available capabilities of a camera device across all API
- * levels.
- */
-var EMPTY_INT_ARRAY = IntArray(0)
+ companion object {
+ /**
+ * Extension properties for querying the available capabilities of a camera device across
+ * all API levels.
+ */
+ var EMPTY_INT_ARRAY = IntArray(0)
-const val CAPABILITIES_MANUAL_SENSOR = 1
-const val CAPABILITIES_MANUAL_POST_PROCESSING = 2
-const val CAPABILITIES_RAW = 3
-const val CAPABILITIES_PRIVATE_REPROCESSING = 4
-const val CAPABILITIES_READ_SENSOR_SETTINGS = 5
-const val CAPABILITIES_BURST_CAPTURE = 6
-const val CAPABILITIES_YUV_REPROCESSING = 7
-const val CAPABILITIES_DEPTH_OUTPUT = 8
-const val CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO = 9
-const val CAPABILITIES_MOTION_TRACKING = 10
-const val CAPABILITIES_LOGICAL_MULTI_CAMERA = 11
-const val CAPABILITIES_MONOCHROME = 12
-const val CAPABILITIES_SECURE_IMAGE_DATA = 13
-const val CAPABILITIES_SYSTEM_CAMERA = 14
-const val CAPABILITIES_OFFLINE_REPROCESSING = 15
+ const val CAPABILITIES_MANUAL_SENSOR = 1
+ const val CAPABILITIES_MANUAL_POST_PROCESSING = 2
+ const val CAPABILITIES_RAW = 3
+ const val CAPABILITIES_PRIVATE_REPROCESSING = 4
+ const val CAPABILITIES_READ_SENSOR_SETTINGS = 5
+ const val CAPABILITIES_BURST_CAPTURE = 6
+ const val CAPABILITIES_YUV_REPROCESSING = 7
+ const val CAPABILITIES_DEPTH_OUTPUT = 8
+ const val CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO = 9
+ const val CAPABILITIES_MOTION_TRACKING = 10
+ const val CAPABILITIES_LOGICAL_MULTI_CAMERA = 11
+ const val CAPABILITIES_MONOCHROME = 12
+ const val CAPABILITIES_SECURE_IMAGE_DATA = 13
+ const val CAPABILITIES_SYSTEM_CAMERA = 14
+ const val CAPABILITIES_OFFLINE_REPROCESSING = 15
-val CameraMetadata.availableCapabilities: IntArray
- get() = this[CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES] ?: EMPTY_INT_ARRAY
+ val CameraMetadata.availableCapabilities: IntArray
+ get() = this[CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES] ?: EMPTY_INT_ARRAY
-val CameraMetadata.supportsManualSensor: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_MANUAL_SENSOR)
+ val CameraMetadata.supportsManualSensor: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_MANUAL_SENSOR)
-val CameraMetadata.supportsManualPostProcessing: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_MANUAL_POST_PROCESSING)
+ val CameraMetadata.supportsManualPostProcessing: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_MANUAL_POST_PROCESSING)
-val CameraMetadata.supportsRaw: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_RAW)
+ val CameraMetadata.supportsRaw: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_RAW)
-val CameraMetadata.supportsPrivateReprocessing: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_PRIVATE_REPROCESSING)
+ val CameraMetadata.supportsPrivateReprocessing: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_PRIVATE_REPROCESSING)
-val CameraMetadata.supportsSensorSettings: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_READ_SENSOR_SETTINGS)
+ val CameraMetadata.supportsSensorSettings: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_READ_SENSOR_SETTINGS)
-val CameraMetadata.supportsBurstCapture: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_BURST_CAPTURE)
+ val CameraMetadata.supportsBurstCapture: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_BURST_CAPTURE)
-val CameraMetadata.supportsYuvReprocessing: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_YUV_REPROCESSING)
+ val CameraMetadata.supportsYuvReprocessing: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_YUV_REPROCESSING)
-val CameraMetadata.supportsDepthOutput: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_DEPTH_OUTPUT)
+ val CameraMetadata.supportsDepthOutput: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_DEPTH_OUTPUT)
-val CameraMetadata.supportsHighSpeedVideo: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO)
+ val CameraMetadata.supportsHighSpeedVideo: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO)
-val CameraMetadata.supportsMotionTracking: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_MOTION_TRACKING)
+ val CameraMetadata.supportsMotionTracking: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_MOTION_TRACKING)
-val CameraMetadata.supportsLogicalMultiCamera: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_LOGICAL_MULTI_CAMERA)
+ val CameraMetadata.supportsLogicalMultiCamera: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_LOGICAL_MULTI_CAMERA)
-val CameraMetadata.supportsMonochrome: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_MONOCHROME)
+ val CameraMetadata.supportsMonochrome: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_MONOCHROME)
-val CameraMetadata.supportsSecureImageData: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_SECURE_IMAGE_DATA)
+ val CameraMetadata.supportsSecureImageData: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_SECURE_IMAGE_DATA)
-val CameraMetadata.supportsSystemCamera: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_SYSTEM_CAMERA)
+ val CameraMetadata.supportsSystemCamera: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_SYSTEM_CAMERA)
-val CameraMetadata.supportsOfflineReprocessing: Boolean
- get() = this.availableCapabilities.contains(CAPABILITIES_OFFLINE_REPROCESSING)
+ val CameraMetadata.supportsOfflineReprocessing: Boolean
+ get() = this.availableCapabilities.contains(CAPABILITIES_OFFLINE_REPROCESSING)
-val CameraMetadata.supportsAutoFocusTrigger: Boolean
- get() {
- val minFocusDistance = this[CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE]
- if (minFocusDistance != null) {
- return minFocusDistance > 0
- }
- val availableAfModes =
- this[CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES] ?: return false
- return availableAfModes.contains(CaptureRequest.CONTROL_AF_MODE_AUTO) ||
- availableAfModes.contains(CaptureRequest.CONTROL_AF_MODE_MACRO) ||
- availableAfModes.contains(CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) ||
- availableAfModes.contains(CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO)
+ val CameraMetadata.supportsAutoFocusTrigger: Boolean
+ get() {
+ val minFocusDistance = this[CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE]
+ if (minFocusDistance != null) {
+ return minFocusDistance > 0
+ }
+ val availableAfModes =
+ this[CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES] ?: return false
+ return availableAfModes.contains(CaptureRequest.CONTROL_AF_MODE_AUTO) ||
+ availableAfModes.contains(CaptureRequest.CONTROL_AF_MODE_MACRO) ||
+ availableAfModes.contains(CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) ||
+ availableAfModes.contains(CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO)
+ }
}
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraPipe.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraPipe.kt
index d90a1bc..1f5535d 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraPipe.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraPipe.kt
@@ -24,6 +24,7 @@
import android.hardware.camera2.CameraDevice
import android.os.HandlerThread
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
import androidx.camera.camera2.pipe.config.CameraGraphConfigModule
import androidx.camera.camera2.pipe.config.CameraPipeComponent
import androidx.camera.camera2.pipe.config.CameraPipeConfigModule
@@ -49,6 +50,7 @@
* [android.hardware.camera2.CameraDevice] and [android.hardware.camera2.CameraCaptureSession] via
* the [CameraGraph] interface.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class CameraPipe(config: Config) {
private val debugId = cameraPipeIds.incrementAndGet()
private val component: CameraPipeComponent =
@@ -69,6 +71,39 @@
.cameraGraph()
}
+ /**
+ * This creates a list of [CameraGraph]s that can be used to interact with multiple cameras on
+ * the device concurrently. Device-specific constraints may apply, such as the set of cameras
+ * that can be operated concurrently, or the combination of sizes we're allowed to configure.
+ */
+ fun createCameraGraphs(concurrentConfigs: List<CameraGraph.Config>): List<CameraGraph> {
+ check(concurrentConfigs.isNotEmpty())
+ if (concurrentConfigs.size == 1) {
+ return listOf(create(concurrentConfigs.first()))
+ }
+ check(concurrentConfigs.all {
+ it.cameraBackendId == concurrentConfigs.first().cameraBackendId
+ }) {
+ "All concurrent CameraGraph configs should have the same camera backend ID!"
+ }
+ val allCameraIds = concurrentConfigs.map { it.camera }
+ check(allCameraIds.size == allCameraIds.toSet().size) {
+ "All camera IDs specified should be distinct!"
+ }
+ val configs = concurrentConfigs.map { config ->
+ config.apply {
+ sharedCameraIds = allCameraIds.filter { it != config.camera }
+ }
+ }
+ return configs.map {
+ component
+ .cameraGraphComponentBuilder()
+ .cameraGraphConfigModule(CameraGraphConfigModule(it))
+ .build()
+ .cameraGraph()
+ }
+ }
+
/** This provides access to information about the available cameras on the device. */
fun cameras(): CameraDevices {
return component.cameras()
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraSurfaceManager.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraSurfaceManager.kt
index d1fc183..51dc922 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraSurfaceManager.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraSurfaceManager.kt
@@ -19,11 +19,10 @@
import android.view.Surface
import androidx.annotation.GuardedBy
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
import androidx.camera.camera2.pipe.CameraSurfaceManager.SurfaceListener
import androidx.camera.camera2.pipe.CameraSurfaceManager.SurfaceToken
import androidx.camera.camera2.pipe.core.Log
-import javax.inject.Inject
-import javax.inject.Singleton
import kotlinx.atomicfu.atomic
/**
@@ -43,9 +42,9 @@
* If the same [Surface] is used in a subsequent [CameraGraph], it will be issued a different token.
* Essentially each token means a single use on a [Surface].
*/
-@Singleton
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-class CameraSurfaceManager @Inject constructor() {
+class CameraSurfaceManager {
private val lock = Any()
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CaptureSequence.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CaptureSequence.kt
index 144ccc2..1c545d5 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CaptureSequence.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CaptureSequence.kt
@@ -16,12 +16,15 @@
package androidx.camera.camera2.pipe
+import androidx.annotation.RestrictTo
+
/**
* An ordered list of [TCaptureRequest] objects, listeners, and associated metadata that will be
* submitted and captured together when submitted to the camera.
*
* A CaptureSequence should be created from a [CaptureSequenceProcessor].
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface CaptureSequence<out TCaptureRequest> {
val cameraId: CameraId
val repeating: Boolean
@@ -39,6 +42,7 @@
}
/** Utility functions for interacting with [CaptureSequence] callbacks and listeners. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
object CaptureSequences {
/**
* Efficient, inlined utility function for invoking a call on each of the listeners defined on a
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CaptureSequenceProcessor.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CaptureSequenceProcessor.kt
index facca9b..402b141 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CaptureSequenceProcessor.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CaptureSequenceProcessor.kt
@@ -16,7 +16,10 @@
package androidx.camera.camera2.pipe
+import androidx.annotation.RestrictTo
+
/** Create and submit [CaptureSequence]s to an active camera instance. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface CaptureSequenceProcessor<
out TCaptureRequest, TCaptureSequence : CaptureSequence<TCaptureRequest>> {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Frames.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Frames.kt
index 5409f4f..bdbf8d7 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Frames.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Frames.kt
@@ -21,16 +21,19 @@
import android.hardware.camera2.CaptureResult
import android.hardware.camera2.TotalCaptureResult
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
/**
* A [FrameNumber] is the identifier that represents a specific exposure by the Camera. FrameNumbers
* increase within a specific CameraCaptureSession, and are not created until the HAL begins
* processing a request.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class FrameNumber(val value: Long)
/** [FrameInfo] is a wrapper around [TotalCaptureResult]. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface FrameInfo : UnsafeWrapper {
val metadata: FrameMetadata
@@ -46,6 +49,7 @@
}
/** [FrameMetadata] is a wrapper around [CaptureResult]. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface FrameMetadata : Metadata, UnsafeWrapper {
operator fun <T> get(key: CaptureResult.Key<T>): T?
fun <T> getOrDefault(key: CaptureResult.Key<T>, default: T): T
@@ -67,6 +71,7 @@
* [Request.Listener.onComplete] method to be delayed so that the transform can be run on future
* metadata.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
data class MetadataTransform(
/**
* This defines the number of historical [TotalCaptureResult] objects this transform is allowed
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Metadata.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Metadata.kt
index 57d8d16..dd42328 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Metadata.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Metadata.kt
@@ -19,6 +19,7 @@
package androidx.camera.camera2.pipe
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
/**
* A map-like interface used to describe or interact with metadata from CameraPipe and Camera2.
@@ -28,11 +29,13 @@
*
* These interfaces are read-only.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface Metadata {
operator fun <T> get(key: Key<T>): T?
fun <T> getOrDefault(key: Key<T>, default: T): T
/** Metadata keys provide values or controls that are provided or computed by CameraPipe. */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class Key<T> private constructor(private val name: String) {
companion object {
@JvmStatic
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/RequestProcessor.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/RequestProcessor.kt
index 6b26be9..c4e5f10 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/RequestProcessor.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/RequestProcessor.kt
@@ -17,6 +17,7 @@
package androidx.camera.camera2.pipe
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
/**
* An instance of a [RequestProcessor] exists for the duration of a CameraCaptureSession and must be
@@ -34,6 +35,7 @@
* - Callbacks are expected to be invoked at *very* high frequency.
* - One RequestProcessor instance per CameraCaptureSession
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Deprecated("Use CaptureSequence and CaptureSequenceProcessor instead.")
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
interface RequestProcessor {
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 6781c8d..359e98d 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
@@ -24,11 +24,13 @@
import android.hardware.camera2.CaptureRequest
import android.view.Surface
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
/**
* A [RequestNumber] is an artificial identifier that is created for each request that is submitted
* to the Camera.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class RequestNumber(val value: Long)
@@ -49,6 +51,7 @@
*
* @param streams The list of streams to submit. Each request *must* have 1 or more valid streams.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
data class Request(
val streams: List<StreamId>,
val parameters: Map<CaptureRequest.Key<*>, Any> = emptyMap(),
@@ -239,6 +242,7 @@
* A [RequestTemplate] indicates which preset set list of parameters will be applied to a request by
* default. These values are defined by camera2.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class RequestTemplate(val value: Int) {
val name: String
@@ -263,6 +267,7 @@
* [CameraGraph]. This class will report the actual keys / values that were sent to camera2 (if
* different) from the request that was used to create the Camera2 [CaptureRequest].
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface RequestMetadata : Metadata, UnsafeWrapper {
operator fun <T> get(key: CaptureRequest.Key<T>): T?
fun <T> getOrDefault(key: CaptureRequest.Key<T>, default: T): T
@@ -298,17 +303,22 @@
* operate based on a real-time clock, while audio/visual systems commonly operate based on a
* monotonic clock.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class CameraTimestamp(val value: Long)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun <T> Request.getOrDefault(key: Metadata.Key<T>, default: T): T = this[key] ?: default
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun <T> Request.getOrDefault(key: CaptureRequest.Key<T>, default: T): T =
this[key] ?: default
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun Request.formatForLogs(): String = "Request($streams)@${Integer.toHexString(hashCode())}"
/** Utility function to help deal with the unsafe nature of the typed Key/Value pairs. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun CaptureRequest.Builder.writeParameters(parameters: Map<*, Any?>) {
for ((key, value) in parameters) {
writeParameter(key, value)
@@ -316,6 +326,7 @@
}
/** Utility function to help deal with the unsafe nature of the typed Key/Value pairs. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun CaptureRequest.Builder.writeParameter(key: Any?, value: Any?) {
if (key != null && key is CaptureRequest.Key<*>) {
@Suppress("UNCHECKED_CAST") this.set(key as CaptureRequest.Key<Any>, value)
@@ -326,6 +337,7 @@
* Utility function to put all metadata in the current map through an unchecked cast. The unchecked
* cast is necessary since CameraGraph.Config uses Map<*, Any?> as the standard type for parameters.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun MutableMap<Any, Any?>.putAllMetadata(metadata: Map<*, Any?>) {
@Suppress("UNCHECKED_CAST") this.putAll(metadata as Map<Any, Any?>)
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/StreamFormat.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/StreamFormat.kt
index 77a6337..d6c9fb8 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/StreamFormat.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/StreamFormat.kt
@@ -17,6 +17,7 @@
package androidx.camera.camera2.pipe
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
/**
* Platform-independent Android ImageFormats and their associated values.
@@ -25,6 +26,7 @@
* not listed. // TODO: Consider adding data-space as a separate property, or finding a way to work
* it in.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
@JvmInline
value class StreamFormat(val value: Int) {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/StreamGraph.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/StreamGraph.kt
index dbff74d..3373421 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/StreamGraph.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/StreamGraph.kt
@@ -17,12 +17,14 @@
package androidx.camera.camera2.pipe
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
/**
* This defines a fixed set of inputs and outputs for a single [CameraGraph] instance.
*
* [CameraStream]s can be used to build [Request]s that are sent to a [CameraGraph].
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
interface StreamGraph {
val streams: List<CameraStream>
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Streams.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Streams.kt
index a8a64f4..8acb30d 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Streams.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Streams.kt
@@ -21,6 +21,7 @@
import android.hardware.camera2.params.OutputConfiguration
import android.util.Size
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
import androidx.camera.camera2.pipe.OutputStream.DynamicRangeProfile.Companion.STANDARD
import androidx.camera.camera2.pipe.OutputStream.MirrorMode.Companion.MIRROR_MODE_AUTO
import androidx.camera.camera2.pipe.OutputStream.StreamUseCase.Companion.DEFAULT
@@ -66,6 +67,7 @@
* \-> OutputConfig-2 -> OutputStream-2
* ```
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class CameraStream
internal constructor(val id: StreamId, val outputs: List<OutputStream>) {
override fun toString(): String = id.toString()
@@ -118,6 +120,7 @@
/**
* This identifies a single surface that is used to tell the camera to produce one or more outputs.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class StreamId(val value: Int) {
override fun toString(): String = "Stream-$value"
@@ -129,6 +132,7 @@
* the underlying HAL on the device may produce different sized images for the same request. This
* represents one of those potential outputs.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface OutputStream {
// Every output comes from one, and exactly one, CameraStream
val stream: CameraStream
@@ -408,12 +412,14 @@
}
/** This identifies a single output. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class OutputId(val value: Int) {
override fun toString(): String = "Output-$value"
}
/** Configuration for defining the properties of a Camera2 InputStream for reprocessing requests. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface InputStream {
val id: InputId
val format: StreamFormat
@@ -423,6 +429,7 @@
}
/** This identifies a single input. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class InputId(val value: Int) {
override fun toString(): String = "Input-$value"
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/UnsafeWrapper.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/UnsafeWrapper.kt
index 2fc9a6b..4702c3c 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/UnsafeWrapper.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/UnsafeWrapper.kt
@@ -17,6 +17,7 @@
package androidx.camera.camera2.pipe
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
import kotlin.reflect.KClass
/**
@@ -27,6 +28,7 @@
* be useful for compatibility and testing, but is extremely risky if the state or lifetime of the
* of the object is managed by CameraPipe.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
interface UnsafeWrapper {
/**
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt
index 33c87c3..20bdb3d 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt
@@ -292,6 +292,15 @@
}
}
+@RequiresApi(Build.VERSION_CODES.R)
+internal object Api30Compat {
+ @JvmStatic
+ @DoNotInline
+ fun getConcurrentCameraIds(cameraManager: CameraManager): Set<Set<String>> {
+ return cameraManager.concurrentCameraIds
+ }
+}
+
@RequiresApi(Build.VERSION_CODES.S)
internal object Api31Compat {
@JvmStatic
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2Backend.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2Backend.kt
index f78fd57..36d8450 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2Backend.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2Backend.kt
@@ -53,14 +53,16 @@
override val cameraStatus: Flow<CameraStatus>
get() = camera2CameraStatusMonitor.cameraStatus
- override suspend fun getCameraIds(): List<CameraId>? = camera2DeviceCache.getCameraIds()
+ override suspend fun getCameraIds(): List<CameraId> = camera2DeviceCache.getCameraIds()
override fun awaitCameraIds(): List<CameraId>? = camera2DeviceCache.awaitCameraIds()
+ override fun awaitConcurrentCameraIds(): Set<Set<CameraId>>? =
+ camera2DeviceCache.awaitConcurrentCameraIds()
- override suspend fun getCameraMetadata(cameraId: CameraId): CameraMetadata? =
+ override suspend fun getCameraMetadata(cameraId: CameraId): CameraMetadata =
camera2MetadataCache.getCameraMetadata(cameraId)
- override fun awaitCameraMetadata(cameraId: CameraId): CameraMetadata? =
+ override fun awaitCameraMetadata(cameraId: CameraId): CameraMetadata =
camera2MetadataCache.awaitCameraMetadata(cameraId)
override fun disconnectAllAsync(): Deferred<Unit> {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt
index 73ce419..4f19a5e5 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt
@@ -35,7 +35,9 @@
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
+import kotlinx.coroutines.async
import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
/**
* This represents the core state loop for a CameraGraph instance.
@@ -97,7 +99,7 @@
lastCameraError = null
val camera = virtualCameraManager.open(
config.camera,
- config.flags.allowMultipleActiveCameras,
+ config.sharedCameraIds,
graphListener,
) { _ -> isForeground }
@@ -146,10 +148,7 @@
controllerState = ControllerState.STOPPING
Log.debug { "Stopping Camera2CameraController" }
- scope.launch {
- session?.disconnect()
- camera?.disconnect()
- }
+ disconnectSessionAndCamera(session, camera)
}
override fun tryRestart(cameraStatus: CameraStatus): Unit = synchronized(lock) {
@@ -196,9 +195,10 @@
currentCameraStateJob?.cancel()
currentCameraStateJob = null
- scope.launch {
- session?.disconnect()
- camera?.disconnect()
+ disconnectSessionAndCamera(session, camera)
+ if (config.flags.quirkCloseCameraDeviceOnClose) {
+ Log.debug { "Quirk: Closing all camera devices" }
+ virtualCameraManager.closeAll()
}
}
@@ -272,4 +272,14 @@
controllerState = ControllerState.STOPPED
}
}
+
+ private fun disconnectSessionAndCamera(session: CaptureSessionState?, camera: VirtualCamera?) {
+ val deferred = scope.async {
+ session?.disconnect()
+ camera?.disconnect()
+ }
+ if (config.flags.quirkCloseCaptureSessionOnDisconnect) {
+ runBlocking { deferred.await() }
+ }
+ }
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCache.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCache.kt
index bfaf688..afd9a12 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCache.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCache.kt
@@ -18,6 +18,7 @@
import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraManager
+import android.os.Build
import androidx.annotation.GuardedBy
import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraId
@@ -42,6 +43,9 @@
@GuardedBy("lock")
private var openableCameras: List<CameraId>? = null
+ @GuardedBy("lock")
+ private var concurrentCameras: Set<Set<CameraId>>? = null
+
suspend fun getCameraIds(): List<CameraId> {
val cameras = synchronized(lock) { openableCameras }
if (!cameras.isNullOrEmpty()) {
@@ -93,4 +97,49 @@
}
return cameraIdArray.map { CameraId(it) }
}
+
+ suspend fun getConcurrentCameraIds(): Set<Set<CameraId>> {
+ val cameras = synchronized(lock) { concurrentCameras }
+ if (!cameras.isNullOrEmpty()) {
+ return cameras
+ }
+
+ // Suspend and query the list of concurrent Cameras on the ioDispatcher
+ return withContext(threads.backgroundDispatcher) {
+ Debug.trace("readConcurrentCameraIds") {
+ val cameraIds = awaitConcurrentCameraIds()
+
+ if (!cameraIds.isNullOrEmpty()) {
+ synchronized(lock) { concurrentCameras = cameraIds }
+ return@trace cameraIds
+ }
+
+ return@trace emptySet()
+ }
+ }
+ }
+
+ fun awaitConcurrentCameraIds(): Set<Set<CameraId>>? {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ return emptySet()
+ }
+ val cameras = synchronized(lock) { concurrentCameras }
+ if (!cameras.isNullOrEmpty()) {
+ return cameras
+ }
+
+ val cameraManager = cameraManager.get()
+ val cameraIdsSet =
+ try {
+ val idSetSet = Api30Compat.getConcurrentCameraIds(cameraManager)
+ Log.debug { "Loaded ConcurrentCameraIdsSet $idSetSet" }
+ idSetSet
+ } catch (e: CameraAccessException) {
+ Log.warn(e) { "Failed to query CameraManager#getConcurrentStreamingCameraIds" }
+ return null
+ }
+ return cameraIdsSet.map {
+ it.map { cameraIdString -> CameraId(cameraIdString) }.toSet()
+ }.toSet()
+ }
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCloser.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCloser.kt
index 0f34b05..c63ea2b 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCloser.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCloser.kt
@@ -85,15 +85,15 @@
}
}
Log.debug { "Closing $cameraDevice" }
- Threading.runBlockingWithTimeout(threads.backgroundDispatcher, 2000L) {
+ Threading.runBlockingWithTimeout(threads.backgroundDispatcher, 5000L) {
cameraDevice.closeWithTrace()
}
if (camera2Quirks.shouldWaitForCameraDeviceOnClosed(cameraId)) {
Log.debug { "Waiting for camera device to be completely closed" }
- if (androidCameraState.awaitCameraDeviceClosed(timeoutMillis = 2000)) {
+ if (androidCameraState.awaitCameraDeviceClosed(timeoutMillis = 5000)) {
Log.debug { "Camera device is closed" }
} else {
- Log.warn { "Failed to wait for camera device to close after 2000ms" }
+ Log.warn { "Failed to wait for camera device to close after 5000ms" }
}
}
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactory.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactory.kt
index 360d596..c13f8c6 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactory.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactory.kt
@@ -207,6 +207,7 @@
)
if (outputs.all.isEmpty()) {
Log.warn { "Failed to create OutputConfigurations for $graphConfig" }
+ captureSessionState.onSessionFinalized()
return emptyMap()
}
@@ -270,6 +271,7 @@
)
if (outputs.all.isEmpty()) {
Log.warn { "Failed to create OutputConfigurations for $graphConfig" }
+ captureSessionState.onSessionFinalized()
return emptyMap()
}
@@ -431,6 +433,7 @@
)
if (outputs.all.isEmpty()) {
Log.warn { "Failed to create OutputConfigurations for $graphConfig" }
+ captureSessionState.onSessionFinalized()
return emptyMap()
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCamera.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCamera.kt
index 25380b7..05cc5eb 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCamera.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCamera.kt
@@ -41,9 +41,8 @@
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import kotlinx.atomicfu.atomic
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -120,7 +119,8 @@
internal class VirtualCameraState(
val cameraId: CameraId,
- val graphListener: GraphListener
+ val graphListener: GraphListener,
+ val scope: CoroutineScope,
) : VirtualCamera {
private val debugId = virtualCameraDebugIds.incrementAndGet()
private val lock = Any()
@@ -153,11 +153,11 @@
check(_stateFlow.tryEmit(_lastState))
}
- internal suspend fun connect(state: Flow<CameraState>, wakelockToken: Token?) = coroutineScope {
+ internal suspend fun connect(state: Flow<CameraState>, wakelockToken: Token?) {
synchronized(lock) {
if (closed) {
wakelockToken?.release()
- return@coroutineScope
+ return
}
// Here we generally relay what we receive from AndroidCameraState's state flow, except
@@ -175,12 +175,9 @@
// recently).
//
// Relevant bug: b/269619541
- job = launch {
+ job = scope.launch {
state.collect {
synchronized(lock) {
- if (closed) {
- this.cancel()
- }
if (it is CameraStateOpen) {
val virtualAndroidCamera = VirtualAndroidCameraDevice(
it.cameraDevice as AndroidCameraDevice
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCameraManager.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCameraManager.kt
index c4906ae..7a8560f 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCameraManager.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCameraManager.kt
@@ -41,7 +41,7 @@
internal data class RequestOpen(
val virtualCamera: VirtualCameraState,
- val share: Boolean = false,
+ val sharedCameraIds: List<CameraId>,
val graphListener: GraphListener,
val isForegroundObserver: (Unit) -> Boolean,
) : CameraRequest()
@@ -70,6 +70,7 @@
// TODO: Consider rewriting this as a MutableSharedFlow
private val requestQueue: Channel<CameraRequest> = Channel(requestQueueDepth)
private val activeCameras: MutableSet<ActiveCamera> = mutableSetOf()
+ private val pendingRequestOpens = mutableListOf<RequestOpen>()
init {
threads.globalScope.launch(CoroutineName("CXCP-VirtualCameraManager")) { requestLoop() }
@@ -77,12 +78,19 @@
internal fun open(
cameraId: CameraId,
- share: Boolean = false,
+ sharedCameraIds: List<CameraId>,
graphListener: GraphListener,
isForegroundObserver: (Unit) -> Boolean,
): VirtualCamera {
- val result = VirtualCameraState(cameraId, graphListener)
- offerChecked(RequestOpen(result, share, graphListener, isForegroundObserver))
+ val result = VirtualCameraState(cameraId, graphListener, threads.globalScope)
+ offerChecked(
+ RequestOpen(
+ result,
+ sharedCameraIds,
+ graphListener,
+ isForegroundObserver
+ )
+ )
return result
}
@@ -111,6 +119,9 @@
if (activeCameras.contains(closeRequest.activeCamera)) {
activeCameras.remove(closeRequest.activeCamera)
}
+ pendingRequestOpens.removeAll {
+ it.virtualCamera.cameraId == closeRequest.activeCamera.cameraId
+ }
launch { closeRequest.activeCamera.close() }
closeRequest.activeCamera.awaitClosed()
@@ -136,6 +147,7 @@
camera.awaitClosed()
}
activeCameras.clear()
+ pendingRequestOpens.clear()
continue
}
@@ -157,16 +169,20 @@
// needed. Since close may block, we will re-evaluate the next request after the
// desired cameras are closed since new requests may have arrived.
val cameraIdToOpen = request.virtualCamera.cameraId
- val camerasToClose =
- if (request.share) {
- emptyList()
- } else {
- activeCameras.filter { it.cameraId != cameraIdToOpen }
- }
+ val camerasToClose = if (request.sharedCameraIds.isEmpty()) {
+ activeCameras.filter { it.cameraId != cameraIdToOpen }
+ } else {
+ val allCameraIds =
+ (request.sharedCameraIds + request.virtualCamera.cameraId).toSet()
+ activeCameras.filter { it.allCameraIds != allCameraIds }
+ }
if (camerasToClose.isNotEmpty()) {
// Shutdown of cameras should always happen first (and suspend until complete)
activeCameras.removeAll(camerasToClose)
+ pendingRequestOpens.removeAll { requestOpen ->
+ camerasToClose.any { it.cameraId == requestOpen.virtualCamera.cameraId }
+ }
for (camera in camerasToClose) {
// TODO: This should be a dispatcher instead of scope.launch
@@ -190,6 +206,7 @@
val openResult =
openCameraWithRetry(
cameraIdToOpen,
+ request.sharedCameraIds,
request.isForegroundObserver,
scope = this
)
@@ -204,13 +221,32 @@
}
// Stage 4: Attach camera(s)
- realCamera.connectTo(request.virtualCamera)
+ if (request.sharedCameraIds.isNotEmpty()) {
+ // Both sharedCameraIds and activeCameras are small collections. Looping over them
+ // in what equates to nested for-loops are actually going to be more efficient than
+ // say, replacing activeCameras with a hashmap.
+ if (request.sharedCameraIds.all { cameraId ->
+ activeCameras.any { it.cameraId == cameraId }
+ }) {
+ // If the camera of the request and the cameras it is shared with have been
+ // opened, we can connect the ActiveCameras.
+ realCamera.connectTo(request.virtualCamera)
+ connectPendingRequestOpens(request.sharedCameraIds)
+ } else {
+ // Else, save the request in the pending request queue, and connect the request
+ // once other cameras are opened.
+ pendingRequestOpens.add(request)
+ }
+ } else {
+ realCamera.connectTo(request.virtualCamera)
+ }
requests.remove(request)
}
}
private suspend fun openCameraWithRetry(
cameraId: CameraId,
+ sharedCameraIds: List<CameraId>,
isForegroundObserver: (Unit) -> Boolean,
scope: CoroutineScope
): OpenVirtualCameraResult {
@@ -227,11 +263,35 @@
activeCamera =
ActiveCamera(
androidCameraState = result.cameraState,
- scope = scope, channel = requestQueue
+ allCameraIds = (sharedCameraIds + cameraId).toSet(),
+ scope = scope,
+ channel = requestQueue
)
)
}
+ private suspend fun connectPendingRequestOpens(cameraIds: List<CameraId>) {
+ val requestOpensToRemove = mutableListOf<RequestOpen>()
+ val requestOpens = pendingRequestOpens.filter {
+ cameraIds.contains(it.virtualCamera.cameraId)
+ }
+ for (request in requestOpens) {
+ // If the request is shared with this pending request, then we should be
+ // able to connect this pending request too, since we don't allow
+ // overlapping.
+ val allCameraIds =
+ listOf(request.virtualCamera.cameraId) + request.sharedCameraIds
+ check(allCameraIds.all { cameraId -> activeCameras.any { it.cameraId == cameraId } })
+
+ val realCamera =
+ activeCameras.find { it.cameraId == request.virtualCamera.cameraId }
+ checkNotNull(realCamera)
+ realCamera.connectTo(request.virtualCamera)
+ requestOpensToRemove.add(request)
+ }
+ pendingRequestOpens.removeAll(requestOpensToRemove)
+ }
+
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
private suspend fun readRequestQueue(requests: MutableList<CameraRequest>) {
if (requests.isEmpty()) {
@@ -247,6 +307,7 @@
internal class ActiveCamera(
private val androidCameraState: AndroidCameraState,
+ internal val allCameraIds: Set<CameraId>,
scope: CoroutineScope,
channel: SendChannel<CameraRequest>
) {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/package-info.java b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/package-info.java
new file mode 100644
index 0000000..6bac9e7
--- /dev/null
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+package androidx.camera.camera2.pipe.compat;
+
+import androidx.annotation.RestrictTo;
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt
index 28bd09a..0d5c122 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt
@@ -161,5 +161,9 @@
}
return CameraBackendsImpl(defaultBackendId, allBackends, cameraPipeContext, threads)
}
+
+ @Singleton
+ @Provides
+ fun provideCameraSurfaceManager() = CameraSurfaceManager()
}
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraGraphComponent.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraGraphComponent.kt
index 6ca0561..0759f3e 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraGraphComponent.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraGraphComponent.kt
@@ -72,6 +72,10 @@
throwUnsupportedOperationException()
}
+ override fun awaitConcurrentCameraIds(): Set<Set<CameraId>>? {
+ throwUnsupportedOperationException()
+ }
+
override fun awaitCameraMetadata(cameraId: CameraId): CameraMetadata? {
throwUnsupportedOperationException()
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraPipeComponent.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraPipeComponent.kt
index 6068c13..dd289b8c 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraPipeComponent.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraPipeComponent.kt
@@ -17,12 +17,25 @@
package androidx.camera.camera2.pipe.config
import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraSurfaceManager
import dagger.Component
+import dagger.Module
+import dagger.Provides
import javax.inject.Singleton
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
@Singleton
-@Component(modules = [ThreadConfigModule::class])
+@Component(modules = [ExternalCameraPipeModules::class, ThreadConfigModule::class])
internal interface ExternalCameraPipeComponent {
fun cameraGraphBuilder(): ExternalCameraGraphComponent.Builder
-}
\ No newline at end of file
+}
+
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+@Module
+internal abstract class ExternalCameraPipeModules {
+ companion object {
+ @Singleton
+ @Provides
+ fun provideCameraSurfaceManager() = CameraSurfaceManager()
+ }
+}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/package-info.java b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/package-info.java
new file mode 100644
index 0000000..6b32ff3
--- /dev/null
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+package androidx.camera.camera2.pipe.config;
+
+import androidx.annotation.RestrictTo;
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/core/Debug.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/core/Debug.kt
index 3a516b2..dc7f25a 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/core/Debug.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/core/Debug.kt
@@ -94,6 +94,8 @@
graphConfig: CameraGraph.Config,
cameraGraph: CameraGraph
): String {
+ val sharedCameraIds = graphConfig.sharedCameraIds.joinToString()
+
val lensFacing =
when (metadata[LENS_FACING]) {
CameraCharacteristics.LENS_FACING_FRONT -> "Front"
@@ -123,6 +125,9 @@
return StringBuilder()
.apply {
append("$cameraGraph (Camera ${graphConfig.camera.value})\n")
+ if (sharedCameraIds.isNotEmpty()) {
+ append(" Shared: $sharedCameraIds\n")
+ }
append(" Facing: $lensFacing ($cameraType)\n")
append(" Mode: $operatingMode\n")
append("Outputs:\n")
@@ -130,8 +135,8 @@
stream.outputs.forEachIndexed { i, output ->
append(" ")
val streamId = if (i == 0) output.stream.id.toString() else ""
- append(streamId.padEnd(10, ' '))
- append(output.id.toString().padEnd(10, ' '))
+ append(streamId.padEnd(12, ' '))
+ append(output.id.toString().padEnd(12, ' '))
append(output.size.toString().padEnd(12, ' '))
append(output.format.name.padEnd(16, ' '))
output.mirrorMode?.let { append(" [$it]") }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/core/package-info.java b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/core/package-info.java
new file mode 100644
index 0000000..4f1ca2c
--- /dev/null
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/core/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+package androidx.camera.camera2.pipe.core;
+
+import androidx.annotation.RestrictTo;
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt
index 9d3c45c..a8d071a 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt
@@ -36,13 +36,13 @@
import androidx.camera.camera2.pipe.CameraGraph.Constants3A.DEFAULT_FRAME_LIMIT
import androidx.camera.camera2.pipe.CameraGraph.Constants3A.DEFAULT_TIME_LIMIT_NS
import androidx.camera.camera2.pipe.CameraMetadata
+import androidx.camera.camera2.pipe.CameraMetadata.Companion.supportsAutoFocusTrigger
import androidx.camera.camera2.pipe.FlashMode
import androidx.camera.camera2.pipe.Lock3ABehavior
import androidx.camera.camera2.pipe.Result3A
import androidx.camera.camera2.pipe.Result3A.Status
import androidx.camera.camera2.pipe.TorchState
import androidx.camera.camera2.pipe.core.Log.debug
-import androidx.camera.camera2.pipe.supportsAutoFocusTrigger
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.cancel
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/GraphProcessor.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/GraphProcessor.kt
index d368299..f000f4f 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/GraphProcessor.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/GraphProcessor.kt
@@ -341,8 +341,10 @@
}
}
- override fun hasRepeatingRequest() = synchronized(lock) {
- currentRepeatingRequest != null || repeatingQueue.isNotEmpty()
+ override fun hasRepeatingRequest() = synchronized(tryStartRepeatingExecutionLock) {
+ synchronized(lock) {
+ currentRepeatingRequest != null || repeatingQueue.isNotEmpty()
+ }
}
override fun invalidate() {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/package-info.java b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/package-info.java
new file mode 100644
index 0000000..bcea922
--- /dev/null
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+package androidx.camera.camera2.pipe.graph;
+
+import androidx.annotation.RestrictTo;
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/CameraDevicesImpl.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/CameraDevicesImpl.kt
index 6e9cedfb..6f0b2bd 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/CameraDevicesImpl.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/CameraDevicesImpl.kt
@@ -82,6 +82,18 @@
return cameraIds
}
+ override suspend fun getConcurrentCameraIds(
+ cameraBackendId: CameraBackendId?
+ ): Set<Set<CameraId>>? {
+ val cameraBackend = getCameraBackend(cameraBackendId)
+ return cameraBackend.getConcurrentCameraIds()
+ }
+
+ override fun awaitConcurrentCameraIds(cameraBackendId: CameraBackendId?): Set<Set<CameraId>>? {
+ val cameraBackend = getCameraBackend(cameraBackendId)
+ return cameraBackend.awaitConcurrentCameraIds()
+ }
+
override suspend fun getCameraMetadata(
cameraId: CameraId,
cameraBackendId: CameraBackendId?
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/package-info.java b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/package-info.java
new file mode 100644
index 0000000..d3f8309
--- /dev/null
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+package androidx.camera.camera2.pipe.internal;
+
+import androidx.annotation.RestrictTo;
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/StreamFormatTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/StreamFormatTest.kt
index a0483ef..901fa50 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/StreamFormatTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/StreamFormatTest.kt
@@ -16,12 +16,14 @@
package androidx.camera.camera2.pipe
+import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
+@SdkSuppress(minSdkVersion = 21)
internal class StreamFormatTest {
@Test
fun streamFormatsAreEqual() {
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactoryTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactoryTest.kt
index 1236721..7cafd66 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactoryTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactoryTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+
package androidx.camera.camera2.pipe.compat
import android.content.Context
@@ -22,6 +24,7 @@
import android.os.Looper
import android.util.Size
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.CameraGraph.Flags.FinalizeSessionOnCloseBehavior
import androidx.camera.camera2.pipe.CameraId
@@ -206,4 +209,4 @@
return fakeCamera.metadata
}
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/VirtualCameraTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/VirtualCameraTest.kt
index 1e8283b..a77eec4 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/VirtualCameraTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/VirtualCameraTest.kt
@@ -72,7 +72,7 @@
fun virtualCameraStateCanBeDisconnected() = runTest {
// This test asserts that the virtual camera starts in an unopened state and is changed to
// "Closed" when disconnect is invoked on the VirtualCamera.
- val virtualCamera = VirtualCameraState(cameraId, graphListener)
+ val virtualCamera = VirtualCameraState(cameraId, graphListener, this)
assertThat(virtualCamera.value).isInstanceOf(CameraStateUnopened::class.java)
virtualCamera.disconnect()
@@ -96,7 +96,7 @@
// This test asserts that when a virtual camera is connected to a flow of CameraState
// changes that it receives those changes and can be subsequently disconnected, which stops
// additional events from being passed to the virtual camera instance.
- val virtualCamera = VirtualCameraState(cameraId, graphListener)
+ val virtualCamera = VirtualCameraState(cameraId, graphListener, this)
val cameraState =
flowOf(
CameraStateOpen(
@@ -131,7 +131,7 @@
fun virtualCameraStateRespondsToClose() = runTest {
// This tests that a listener attached to the virtualCamera.state property will receive all
// of the events, starting from CameraStateUnopened.
- val virtualCamera = VirtualCameraState(cameraId, graphListener)
+ val virtualCamera = VirtualCameraState(cameraId, graphListener, this)
val androidCameraDevice = AndroidCameraDevice(
testCamera.metadata,
testCamera.cameraDevice,
@@ -181,7 +181,7 @@
@Test
fun virtualAndroidCameraDeviceRejectsCallsWhenVirtualCameraStateIsDisconnected() = runTest {
- val virtualCamera = VirtualCameraState(cameraId, graphListener)
+ val virtualCamera = VirtualCameraState(cameraId, graphListener, this)
val cameraState =
flowOf(
CameraStateOpen(
@@ -218,7 +218,7 @@
@Test
fun virtualAndroidCameraDeviceFinalizesSessionWhenVirtualCameraStateIsDisconnected() = runTest {
- val virtualCamera = VirtualCameraState(cameraId, graphListener)
+ val virtualCamera = VirtualCameraState(cameraId, graphListener, this)
val cameraState =
flowOf(
CameraStateOpen(
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/ThreadingTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/ThreadingTest.kt
index 3890397..32a38f2 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/ThreadingTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/ThreadingTest.kt
@@ -16,6 +16,7 @@
package androidx.camera.camera2.pipe.core
+import androidx.test.filters.SdkSuppress
import androidx.testutils.assertThrows
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.CountDownLatch
@@ -27,6 +28,7 @@
import org.junit.Test
@OptIn(ExperimentalCoroutinesApi::class)
+@SdkSuppress(minSdkVersion = 21)
class ThreadingTest {
@Test
fun runBlockingWithTimeoutThrowsOnTimeout() = runTest {
@@ -48,4 +50,4 @@
}
assertThat(result).isNull()
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/TokenLockTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/TokenLockTest.kt
index 51dadf2..15a7a1d 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/TokenLockTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/TokenLockTest.kt
@@ -16,6 +16,7 @@
package androidx.camera.camera2.pipe.core
+import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineStart
@@ -29,6 +30,7 @@
import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
+@SdkSuppress(minSdkVersion = 21)
internal class TokenLockTest {
@Test
fun testTokenLockReportsNoAvailableCapacityWhenClosed() {
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/WakeLockTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/WakeLockTest.kt
index 97b8ee5..c253098 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/WakeLockTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/core/WakeLockTest.kt
@@ -16,6 +16,7 @@
package androidx.camera.camera2.pipe.core
+import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -27,6 +28,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(JUnit4::class)
+@SdkSuppress(minSdkVersion = 21)
internal class WakeLockTest {
@Test
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/GraphTestContext.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/GraphTestContext.kt
index 93d4a6e..5562c70 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/GraphTestContext.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/GraphTestContext.kt
@@ -18,11 +18,13 @@
import android.graphics.SurfaceTexture
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.Request
import androidx.camera.camera2.pipe.StreamId
import androidx.camera.camera2.pipe.testing.FakeCaptureSequenceProcessor
import androidx.camera.camera2.pipe.testing.FakeGraphProcessor
+@RequiresApi(21)
internal class GraphTestContext : AutoCloseable {
val streamId = StreamId(0)
val surfaceMap = mapOf(streamId to Surface(SurfaceTexture(1)))
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraController.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraController.kt
index 863ef6a..4954c1b 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraController.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraController.kt
@@ -17,11 +17,13 @@
package androidx.camera.camera2.pipe.testing
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraController
import androidx.camera.camera2.pipe.CameraId
import androidx.camera.camera2.pipe.CameraStatusMonitor
import androidx.camera.camera2.pipe.StreamId
+@RequiresApi(21)
internal class FakeCameraController : CameraController {
var started = false
var closed = false
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraDeviceWrapper.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraDeviceWrapper.kt
index 7a0093d..f46885f 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraDeviceWrapper.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraDeviceWrapper.kt
@@ -23,6 +23,7 @@
import android.os.Build
import android.os.Handler
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraId
import androidx.camera.camera2.pipe.RequestTemplate
import androidx.camera.camera2.pipe.compat.Api23Compat
@@ -35,6 +36,7 @@
import kotlin.reflect.KClass
/** Fake implementation of [CameraDeviceWrapper] for tests. */
+@RequiresApi(21)
internal class FakeCameraDeviceWrapper(val fakeCamera: RobolectricCameras.FakeCamera) :
CameraDeviceWrapper {
override val cameraId: CameraId
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraMetadataProvider.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraMetadataProvider.kt
index dc613b6..686adee 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraMetadataProvider.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraMetadataProvider.kt
@@ -16,11 +16,13 @@
package androidx.camera.camera2.pipe.testing
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraId
import androidx.camera.camera2.pipe.CameraMetadata
import androidx.camera.camera2.pipe.compat.Camera2MetadataProvider
/** Utility class for providing fake metadata for tests. */
+@RequiresApi(21)
class FakeCameraMetadataProvider(
private val fakeMetadata: Map<CameraId, CameraMetadata> = emptyMap()
) : Camera2MetadataProvider {
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphConfigs.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphConfigs.kt
index 44d3246..8373cb11 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphConfigs.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphConfigs.kt
@@ -19,6 +19,7 @@
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CaptureRequest
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.CameraId
import androidx.camera.camera2.pipe.CameraStream
@@ -29,6 +30,7 @@
* Fake CameraGraph configuration that can be used for more complicated tests that need a realistic
* configuration for tests.
*/
+@RequiresApi(21)
internal object FakeGraphConfigs {
private val camera1 = CameraId("TestCamera-1")
private val camera2 = CameraId("TestCamera-2")
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphProcessor.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphProcessor.kt
index 0541e1d..b32c80d 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphProcessor.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphProcessor.kt
@@ -16,6 +16,7 @@
package androidx.camera.camera2.pipe.testing
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.GraphState
import androidx.camera.camera2.pipe.GraphState.GraphStateError
import androidx.camera.camera2.pipe.GraphState.GraphStateStarted
@@ -33,6 +34,7 @@
import kotlinx.coroutines.flow.update
/** Fake implementation of a [GraphProcessor] for tests. */
+@RequiresApi(21)
internal class FakeGraphProcessor(
val graphState3A: GraphState3A = GraphState3A(),
val defaultParameters: Map<*, Any?> = emptyMap<Any, Any?>(),
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/RobolectricCameras.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/RobolectricCameras.kt
index cf5cbba..6769c1b 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/RobolectricCameras.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/RobolectricCameras.kt
@@ -28,6 +28,7 @@
import android.os.Build
import android.os.Handler
import android.os.Looper
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraId
import androidx.camera.camera2.pipe.CameraMetadata
import androidx.camera.camera2.pipe.compat.Camera2CameraMetadata
@@ -45,6 +46,7 @@
import org.robolectric.shadows.ShadowCameraManager
/** Utility class for creating, configuring, and interacting with Robolectric's [CameraManager]. */
+@RequiresApi(21)
public object RobolectricCameras {
private val cameraIds = atomic(0)
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/UpdateCounting3AStateListener.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/UpdateCounting3AStateListener.kt
index eb81f6b..d8bf188 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/UpdateCounting3AStateListener.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/UpdateCounting3AStateListener.kt
@@ -16,6 +16,7 @@
package androidx.camera.camera2.pipe.testing
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.FrameMetadata
import androidx.camera.camera2.pipe.RequestNumber
import androidx.camera.camera2.pipe.graph.Result3AStateListener
@@ -24,6 +25,7 @@
* Wrapper on Result3AStateListenerImpl to keep track of the number of times the update method is
* called.
*/
+@RequiresApi(21)
internal class UpdateCounting3AStateListener(private val listener: Result3AStateListener) :
Result3AStateListener {
var updateCount = 0
diff --git a/camera/camera-camera2/build.gradle b/camera/camera-camera2/build.gradle
index b4ad3b0..b1a28d7 100644
--- a/camera/camera-camera2/build.gradle
+++ b/camera/camera-camera2/build.gradle
@@ -87,6 +87,10 @@
namespace "androidx.camera.camera2"
}
+tasks.withType(Test).configureEach { test ->
+ test.maxParallelForks(2)
+}
+
androidx {
name = "Camera2"
publish = Publish.SNAPSHOT_AND_RELEASE
diff --git a/camera/camera-camera2/lint-baseline.xml b/camera/camera-camera2/lint-baseline.xml
index 9481101..82170fb 100644
--- a/camera/camera-camera2/lint-baseline.xml
+++ b/camera/camera-camera2/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-beta03" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.0.0-beta03">
+<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">
<issue
id="BanThreadSleep"
@@ -102,24 +102,6 @@
<issue
id="UnsafeOptInUsageError"
- message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.core.ExperimentalZeroShutterLag' or '@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)'"
- errorLine1=" captureMode == ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/internal/Camera2UseCaseConfigFactory.java"/>
- </issue>
-
- <issue
- id="UnsafeOptInUsageError"
- message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.core.ExperimentalZeroShutterLag' or '@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)'"
- errorLine1=" captureMode == ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/camera2/internal/Camera2UseCaseConfigFactory.java"/>
- </issue>
-
- <issue
- id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.camera2.interop.ExperimentalCamera2Interop' or '@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)'"
errorLine1=" Camera2ImplConfig.Builder camera2ConfigBuilder = new Camera2ImplConfig.Builder();"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
diff --git a/camera/camera-camera2/lint.xml b/camera/camera-camera2/lint.xml
deleted file mode 100644
index 0843ecf..0000000
--- a/camera/camera-camera2/lint.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
- <!-- Disable NewApi lint check temporarily for unit tests.
- This file can be removed once b/200599470 is resolved. -->
- <issue id="NewApi">
- <ignore path="src/test/**" />
- </issue>
-</lint>
\ No newline at end of file
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerDeviceTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerDeviceTest.kt
index cfded9e..36a2bec 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerDeviceTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerDeviceTest.kt
@@ -316,7 +316,11 @@
)
extraConfigurationQuirk.get(cameraId, hardwareLevel).forEach { surfaceCombination ->
- if (surfaceCombination.isSupported(surfaceCombinationYuvPrivYuv.surfaceConfigList)) {
+ if (surfaceCombination.getOrderedSupportedSurfaceConfigList(
+ surfaceCombinationYuvPrivYuv.surfaceConfigList
+ )
+ != null
+ ) {
return true
}
}
@@ -351,7 +355,10 @@
)
extraConfigurationQuirk.get(cameraId, hardwareLevel).forEach { surfaceCombination ->
- if (surfaceCombination.isSupported(surfaceCombinationYuvYuvYuv.surfaceConfigList)) {
+ if (surfaceCombination.getOrderedSupportedSurfaceConfigList(
+ surfaceCombinationYuvYuvYuv.surfaceConfigList
+ ) != null
+ ) {
return true
}
}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
index e820f5c7..d95e46a0 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
@@ -1212,7 +1212,8 @@
Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
mUseCaseAttachState.getAttachedSessionConfigs(),
- streamUseCaseMap, mCameraCharacteristicsCompat, true);
+ mUseCaseAttachState.getAttachedUseCaseConfigs(),
+ streamUseCaseMap);
mCaptureSession.setStreamUseCaseMap(streamUseCaseMap);
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java
index 1213e14..d18bd1b 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java
@@ -17,6 +17,8 @@
package androidx.camera.camera2.internal;
import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraMetadata;
+import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
@@ -691,124 +693,140 @@
/**
* Returns the entire supported stream combinations for devices with Stream Use Case capability
*/
+ @RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
@NonNull
public static List<SurfaceCombination> getStreamUseCaseSupportedCombinationList() {
List<SurfaceCombination> combinationList = new ArrayList<>();
- // (PRIV, s1440p)
+ // (PRIV, s1440p, PREVIEW_VIDEO_STILL)
SurfaceCombination surfaceCombination1 = new SurfaceCombination();
surfaceCombination1.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.s1440p));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.s1440p,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL));
combinationList.add(surfaceCombination1);
- // (YUV, s1440p)
+ // (YUV, s1440p, PREVIEW_VIDEO_STILL)
SurfaceCombination surfaceCombination2 = new SurfaceCombination();
surfaceCombination2.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.YUV, ConfigSize.s1440p));
+ SurfaceConfig.create(ConfigType.YUV, ConfigSize.s1440p,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL));
combinationList.add(surfaceCombination2);
- // (PRIV, RECORD)
+ // (PRIV, RECORD, VIDEO_RECORD)
SurfaceCombination surfaceCombination3 = new SurfaceCombination();
surfaceCombination3.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.RECORD));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
combinationList.add(surfaceCombination3);
- // (YUV, RECORD)
+ // (YUV, RECORD, VIDEO_RECORD)
SurfaceCombination surfaceCombination4 = new SurfaceCombination();
surfaceCombination4.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.YUV, ConfigSize.RECORD));
+ SurfaceConfig.create(ConfigType.YUV, ConfigSize.RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
combinationList.add(surfaceCombination4);
- // (JPEG, MAXIMUM)
+ // (JPEG, MAXIMUM, STILL_CAPTURE)
SurfaceCombination surfaceCombination5 = new SurfaceCombination();
surfaceCombination5.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.JPEG, ConfigSize.MAXIMUM));
+ SurfaceConfig.create(ConfigType.JPEG, ConfigSize.MAXIMUM,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE));
combinationList.add(surfaceCombination5);
- // (YUV, MAXIMUM)
+ // (YUV, MAXIMUM, STILL_CAPTURE)
SurfaceCombination surfaceCombination6 = new SurfaceCombination();
surfaceCombination6.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.YUV, ConfigSize.MAXIMUM));
+ SurfaceConfig.create(ConfigType.YUV, ConfigSize.MAXIMUM,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE));
combinationList.add(surfaceCombination6);
- // (PRIV, PREVIEW) + (JPEG, MAXIMUM)
+ // (PRIV, PREVIEW, PREVIEW) + (JPEG, MAXIMUM, STILL_CAPTURE)
SurfaceCombination surfaceCombination7 = new SurfaceCombination();
surfaceCombination7.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
surfaceCombination7.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.JPEG, ConfigSize.MAXIMUM));
+ SurfaceConfig.create(ConfigType.JPEG, ConfigSize.MAXIMUM,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE));
combinationList.add(surfaceCombination7);
- // (PRIV, PREVIEW) + (YUV, MAXIMUM)
+ // (PRIV, PREVIEW, PREVIEW) + (YUV, MAXIMUM, STILL_CAPTURE)
SurfaceCombination surfaceCombination8 = new SurfaceCombination();
surfaceCombination8.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
surfaceCombination8.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.YUV, ConfigSize.MAXIMUM));
+ SurfaceConfig.create(ConfigType.YUV, ConfigSize.MAXIMUM,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE));
combinationList.add(surfaceCombination8);
- // (PRIV, PREVIEW) + (PRIV, RECORD)
+ // (PRIV, PREVIEW, PREVIEW) + (PRIV, RECORD, VIDEO_RECORD)
SurfaceCombination surfaceCombination9 = new SurfaceCombination();
surfaceCombination9.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
surfaceCombination9.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.RECORD));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
combinationList.add(surfaceCombination9);
- // (PRIV, PREVIEW) + (YUV, RECORD)
+ // (PRIV, PREVIEW, PREVIEW) + (YUV, RECORD, VIDEO_RECORD)
SurfaceCombination surfaceCombination10 = new SurfaceCombination();
surfaceCombination10.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
surfaceCombination10.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.YUV, ConfigSize.RECORD));
+ SurfaceConfig.create(ConfigType.YUV, ConfigSize.RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
combinationList.add(surfaceCombination10);
- // (PRIV, PREVIEW) + (YUV, PREVIEW)
+ // (PRIV, PREVIEW, PREVIEW) + (YUV, PREVIEW, PREVIEW)
SurfaceCombination surfaceCombination11 = new SurfaceCombination();
surfaceCombination11.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
surfaceCombination11.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.YUV, ConfigSize.PREVIEW));
+ SurfaceConfig.create(ConfigType.YUV, ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
combinationList.add(surfaceCombination11);
- // (PRIV, PREVIEW) + (PRIV, RECORD) + (JPEG, RECORD)
+ // (PRIV, PREVIEW, PREVIEW) + (PRIV, RECORD, VIDEO_RECORD) + (JPEG, RECORD, STILL_CAPTURE)
SurfaceCombination surfaceCombination12 = new SurfaceCombination();
surfaceCombination12.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
surfaceCombination12.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.RECORD));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.RECORD,
+ CameraMetadata.CONTROL_CAPTURE_INTENT_VIDEO_RECORD));
surfaceCombination12.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.JPEG, ConfigSize.RECORD));
+ SurfaceConfig.create(ConfigType.JPEG, ConfigSize.RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE));
combinationList.add(surfaceCombination12);
- // (PRIV, PREVIEW) + (PRIV, RECORD) + (JPEG, RECORD)
+ // (PRIV, PREVIEW, PREVIEW) + (YUV, RECORD, VIDEO_RECORD) + (JPEG, RECORD, STILL_CAPTURE)
SurfaceCombination surfaceCombination13 = new SurfaceCombination();
surfaceCombination13.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
surfaceCombination13.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.RECORD));
+ SurfaceConfig.create(ConfigType.YUV, ConfigSize.RECORD,
+ CameraMetadata.CONTROL_CAPTURE_INTENT_VIDEO_RECORD));
surfaceCombination13.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.JPEG, ConfigSize.RECORD));
+ SurfaceConfig.create(ConfigType.JPEG, ConfigSize.RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE));
combinationList.add(surfaceCombination13);
- // (PRIV, PREVIEW) + (YUV, RECORD) + (JPEG, RECORD)
+ // (PRIV, PREVIEW, PREVIEW) + (YUV, PREVIEW, PREVIEW) + (JPEG, MAXIMUM, STILL_CAPTURE)
SurfaceCombination surfaceCombination14 = new SurfaceCombination();
surfaceCombination14.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+ SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
surfaceCombination14.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.YUV, ConfigSize.RECORD));
+ SurfaceConfig.create(ConfigType.YUV, ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
surfaceCombination14.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.JPEG, ConfigSize.RECORD));
- combinationList.add(surfaceCombination14);
-
- // (PRIV, PREVIEW) + (YUV, PREVIEW) + (JPEG, MAXIMUM)
- SurfaceCombination surfaceCombination15 = new SurfaceCombination();
- surfaceCombination15.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
- surfaceCombination15.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.YUV, ConfigSize.PREVIEW));
- surfaceCombination15.addSurfaceConfig(
- SurfaceConfig.create(ConfigType.JPEG, ConfigSize.MAXIMUM));
+ SurfaceConfig.create(ConfigType.JPEG, ConfigSize.MAXIMUM,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE));
combinationList.add(surfaceCombination14);
return combinationList;
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/MeteringRepeatingSession.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/MeteringRepeatingSession.java
index 11782c2..31c646e 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/MeteringRepeatingSession.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/MeteringRepeatingSession.java
@@ -36,6 +36,7 @@
import androidx.camera.core.impl.MutableOptionsBundle;
import androidx.camera.core.impl.SessionConfig;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.impl.utils.futures.FutureCallback;
import androidx.camera.core.impl.utils.futures.Futures;
@@ -178,6 +179,12 @@
public Config getConfig() {
return mConfig;
}
+
+ @NonNull
+ @Override
+ public UseCaseConfigFactory.CaptureType getCaptureType() {
+ return UseCaseConfigFactory.CaptureType.METERING_REPEATING;
+ }
}
@NonNull
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/StreamUseCaseUtil.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/StreamUseCaseUtil.java
index 82bfaf2..8e25308 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/StreamUseCaseUtil.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/StreamUseCaseUtil.java
@@ -19,7 +19,6 @@
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraMetadata;
-import android.media.MediaCodec;
import android.os.Build;
import androidx.annotation.NonNull;
@@ -30,10 +29,8 @@
import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
import androidx.camera.core.DynamicRange;
-import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
-import androidx.camera.core.Preview;
-import androidx.camera.core.UseCase;
+import androidx.camera.core.Logger;
import androidx.camera.core.impl.AttachedSurfaceInfo;
import androidx.camera.core.impl.CameraMode;
import androidx.camera.core.impl.Config;
@@ -42,13 +39,15 @@
import androidx.camera.core.impl.MutableOptionsBundle;
import androidx.camera.core.impl.SessionConfig;
import androidx.camera.core.impl.StreamSpec;
+import androidx.camera.core.impl.SurfaceConfig;
import androidx.camera.core.impl.UseCaseConfig;
import androidx.camera.core.impl.UseCaseConfigFactory;
-import androidx.camera.core.streamsharing.StreamSharing;
+import androidx.camera.core.streamsharing.StreamSharingConfig;
import androidx.core.util.Preconditions;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -61,14 +60,60 @@
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
public final class StreamUseCaseUtil {
+ private static final String TAG = "Camera2CameraImpl";
+
public static final Config.Option<Long> STREAM_USE_CASE_STREAM_SPEC_OPTION =
Config.Option.create("camera2.streamSpec.streamUseCase", long.class);
- private StreamUseCaseUtil() {
+ private static final Map<Long, Set<UseCaseConfigFactory.CaptureType>>
+ STREAM_USE_CASE_TO_ELIGIBLE_CAPTURE_TYPES_MAP = new HashMap<>();
+ private static final Map<Long, Set<UseCaseConfigFactory.CaptureType>>
+ STREAM_USE_CASE_TO_ELIGIBLE_STREAM_SHARING_CHILDREN_TYPES_MAP = new HashMap<>();
+
+ static {
+ if (Build.VERSION.SDK_INT >= 33) {
+ Set<UseCaseConfigFactory.CaptureType> captureTypes = new HashSet<>();
+ captureTypes.add(UseCaseConfigFactory.CaptureType.PREVIEW);
+ STREAM_USE_CASE_TO_ELIGIBLE_CAPTURE_TYPES_MAP.put(
+ Long.valueOf(
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL),
+ captureTypes);
+ captureTypes = new HashSet<>();
+ captureTypes.add(UseCaseConfigFactory.CaptureType.PREVIEW);
+ captureTypes.add(UseCaseConfigFactory.CaptureType.IMAGE_ANALYSIS);
+ STREAM_USE_CASE_TO_ELIGIBLE_CAPTURE_TYPES_MAP.put(
+ Long.valueOf(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW),
+ captureTypes);
+ captureTypes = new HashSet<>();
+ captureTypes.add(UseCaseConfigFactory.CaptureType.IMAGE_CAPTURE);
+ STREAM_USE_CASE_TO_ELIGIBLE_CAPTURE_TYPES_MAP.put(
+ Long.valueOf(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE),
+ captureTypes);
+ captureTypes = new HashSet<>();
+ captureTypes.add(UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE);
+ STREAM_USE_CASE_TO_ELIGIBLE_CAPTURE_TYPES_MAP.put(
+ Long.valueOf(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD),
+ captureTypes);
+
+ captureTypes = new HashSet<>();
+ captureTypes.add(UseCaseConfigFactory.CaptureType.PREVIEW);
+ captureTypes.add(UseCaseConfigFactory.CaptureType.IMAGE_CAPTURE);
+ captureTypes.add(UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE);
+ STREAM_USE_CASE_TO_ELIGIBLE_STREAM_SHARING_CHILDREN_TYPES_MAP.put(Long.valueOf(
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL),
+ captureTypes);
+ captureTypes = new HashSet<>();
+ captureTypes.add(UseCaseConfigFactory.CaptureType.PREVIEW);
+ captureTypes.add(UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE);
+ STREAM_USE_CASE_TO_ELIGIBLE_STREAM_SHARING_CHILDREN_TYPES_MAP.put(Long.valueOf(
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD),
+ captureTypes);
+ }
}
- private static Map<Class<?>, Long> sUseCaseToStreamUseCaseMapping;
+ private StreamUseCaseUtil() {
+ }
/**
* Populates the mapping between surfaces of a capture session and the Stream Use Case of their
@@ -80,96 +125,46 @@
@OptIn(markerClass = ExperimentalCamera2Interop.class)
public static void populateSurfaceToStreamUseCaseMapping(
@NonNull Collection<SessionConfig> sessionConfigs,
- @NonNull Map<DeferrableSurface, Long> streamUseCaseMap,
- @NonNull CameraCharacteristicsCompat cameraCharacteristicsCompat,
- boolean shouldSetStreamUseCaseByDefault) {
- if (Build.VERSION.SDK_INT < 33) {
- return;
- }
-
- if (cameraCharacteristicsCompat.get(
- CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES) == null) {
- return;
- }
-
- Set<Long> supportedStreamUseCases = new HashSet<>();
- for (long useCase : cameraCharacteristicsCompat.get(
- CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES)) {
- supportedStreamUseCases.add(useCase);
- }
-
+ @NonNull Collection<UseCaseConfig<?>> useCaseConfigs,
+ @NonNull Map<DeferrableSurface, Long> streamUseCaseMap) {
+ int position = 0;
+ boolean hasStreamUseCase = false;
+ ArrayList<UseCaseConfig<?>> useCaseConfigArrayList = new ArrayList<>(useCaseConfigs);
for (SessionConfig sessionConfig : sessionConfigs) {
- if (sessionConfig.getTemplateType()
- == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG
- ) {
- // If is ZSL, do not populate anything.
- streamUseCaseMap.clear();
+ if (sessionConfig.getImplementationOptions().containsOption(
+ STREAM_USE_CASE_STREAM_SPEC_OPTION)
+ && sessionConfig.getSurfaces().size() != 1) {
+ Logger.e(TAG, String.format("SessionConfig has stream use case but also contains "
+ + "%d surfaces, abort populateSurfaceToStreamUseCaseMapping().",
+ sessionConfig.getSurfaces().size()));
return;
}
- for (DeferrableSurface surface : sessionConfig.getSurfaces()) {
- if (sessionConfig.getImplementationOptions().containsOption(
- Camera2ImplConfig.STREAM_USE_CASE_OPTION)
- && putStreamUseCaseToMappingIfAvailable(
- streamUseCaseMap,
- surface,
- sessionConfig.getImplementationOptions().retrieveOption(
- Camera2ImplConfig.STREAM_USE_CASE_OPTION),
- supportedStreamUseCases)) {
- continue;
- }
-
- if (shouldSetStreamUseCaseByDefault) {
- // TODO(b/266879290) This is currently gated out because of camera device
- // crashing due to unsupported stream useCase combinations.
- Long streamUseCase = getUseCaseToStreamUseCaseMapping()
- .get(surface.getContainerClass());
- putStreamUseCaseToMappingIfAvailable(streamUseCaseMap,
- surface,
- streamUseCase,
- supportedStreamUseCases);
- }
+ if (sessionConfig.getImplementationOptions().containsOption(
+ STREAM_USE_CASE_STREAM_SPEC_OPTION)) {
+ hasStreamUseCase = true;
+ break;
}
}
- }
- private static boolean putStreamUseCaseToMappingIfAvailable(
- Map<DeferrableSurface, Long> streamUseCaseMap,
- DeferrableSurface surface,
- @Nullable Long streamUseCase,
- Set<Long> availableStreamUseCases) {
- if (streamUseCase == null) {
- return false;
+ if (hasStreamUseCase) {
+ for (SessionConfig sessionConfig : sessionConfigs) {
+ if (useCaseConfigArrayList.get(position).getCaptureType()
+ == UseCaseConfigFactory.CaptureType.METERING_REPEATING) {
+ // MeteringRepeating is attached after the StreamUseCase population logic and
+ // therefore won't have the StreamUseCase option. It should always have
+ // SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW
+ streamUseCaseMap.put(sessionConfig.getSurfaces().get(0),
+ Long.valueOf(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
+
+ } else if (sessionConfig.getImplementationOptions().containsOption(
+ STREAM_USE_CASE_STREAM_SPEC_OPTION)) {
+ streamUseCaseMap.put(sessionConfig.getSurfaces().get(0),
+ sessionConfig.getImplementationOptions().retrieveOption(
+ STREAM_USE_CASE_STREAM_SPEC_OPTION));
+ }
+ position++;
+ }
}
-
- if (!availableStreamUseCases.contains(streamUseCase)) {
- return false;
- }
-
- streamUseCaseMap.put(surface, streamUseCase);
- return true;
- }
-
- /**
- * Returns the mapping between the container class of a surface and the StreamUseCase
- * associated with that class. Refer to {@link UseCase} for the potential UseCase as the
- * container class for a given surface.
- */
- @RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
- private static Map<Class<?>, Long> getUseCaseToStreamUseCaseMapping() {
- if (sUseCaseToStreamUseCaseMapping == null) {
- sUseCaseToStreamUseCaseMapping = new HashMap<>();
- sUseCaseToStreamUseCaseMapping.put(ImageAnalysis.class,
- Long.valueOf(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
- sUseCaseToStreamUseCaseMapping.put(Preview.class,
- Long.valueOf(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
- sUseCaseToStreamUseCaseMapping.put(ImageCapture.class,
- Long.valueOf(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE));
- sUseCaseToStreamUseCaseMapping.put(MediaCodec.class,
- Long.valueOf(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
- sUseCaseToStreamUseCaseMapping.put(StreamSharing.class,
- Long.valueOf(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
- }
- return sUseCaseToStreamUseCaseMapping;
}
/**
@@ -231,8 +226,8 @@
/**
* Return true if the given feature settings is appropriate for stream use case usage.
*/
- public static boolean shouldUseStreamUseCase(@NonNull
- SupportedSurfaceCombination.FeatureSettings featureSettings) {
+ public static boolean shouldUseStreamUseCase(
+ @NonNull SupportedSurfaceCombination.FeatureSettings featureSettings) {
return featureSettings.getCameraMode() == CameraMode.DEFAULT
&& featureSettings.getRequiredMaxBitDepth() == DynamicRange.BIT_DEPTH_8_BIT;
}
@@ -270,9 +265,12 @@
Preconditions.checkNotNull(Preconditions.checkNotNull(
suggestedStreamSpecMap.get(useCaseConfig)).getImplementationOptions());
}
- Set<Long> availableStreamUseCaseSet = new HashSet<>();
long[] availableStreamUseCases = characteristicsCompat.get(
CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES);
+ if (availableStreamUseCases == null || availableStreamUseCases.length == 0) {
+ return false;
+ }
+ Set<Long> availableStreamUseCaseSet = new HashSet<>();
for (Long availableStreamUseCase : availableStreamUseCases) {
availableStreamUseCaseSet.add(availableStreamUseCase);
}
@@ -286,16 +284,8 @@
oldImplementationOptions.retrieveOption(
Camera2ImplConfig.STREAM_USE_CASE_OPTION));
if (newImplementationOptions != null) {
- StreamSpec.Builder newStreamSpecBuilder =
- StreamSpec.builder(attachedSurfaceInfo.getSize())
- .setDynamicRange(attachedSurfaceInfo.getDynamicRange())
- .setImplementationOptions(newImplementationOptions);
- if (attachedSurfaceInfo.getTargetFrameRate() != null) {
- newStreamSpecBuilder.setExpectedFrameRateRange(
- attachedSurfaceInfo.getTargetFrameRate());
- }
attachedSurfaceStreamSpecMap.put(attachedSurfaceInfo,
- newStreamSpecBuilder.build());
+ attachedSurfaceInfo.toStreamSpec(newImplementationOptions));
}
}
for (UseCaseConfig<?> newUseCaseConfig : newUseCaseConfigs) {
@@ -318,6 +308,173 @@
}
/**
+ * Return true if the stream use cases in the given surface configurations are available for
+ * the device.
+ */
+ public static boolean areStreamUseCasesAvailableForSurfaceConfigs(
+ @NonNull CameraCharacteristicsCompat characteristicsCompat,
+ @NonNull List<SurfaceConfig> surfaceConfigs) {
+ if (Build.VERSION.SDK_INT < 33) {
+ return false;
+ }
+ long[] availableStreamUseCases = characteristicsCompat.get(
+ CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES);
+ if (availableStreamUseCases == null || availableStreamUseCases.length == 0) {
+ return false;
+ }
+ Set<Long> availableStreamUseCaseSet = new HashSet<>();
+ for (Long availableStreamUseCase : availableStreamUseCases) {
+ availableStreamUseCaseSet.add(availableStreamUseCase);
+ }
+ for (SurfaceConfig surfaceConfig : surfaceConfigs) {
+ if (!availableStreamUseCaseSet.contains(surfaceConfig.getStreamUseCase())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return true if the given capture type and stream use case are a eligible pair. If the
+ * given captureType is STREAM_SHARING, checks the streamSharingTypes, which are the capture
+ * types of the children, are eligible with the stream use case.
+ */
+ private static boolean isEligibleCaptureType(UseCaseConfigFactory.CaptureType captureType,
+ long streamUseCase, List<UseCaseConfigFactory.CaptureType> streamSharingTypes) {
+ if (Build.VERSION.SDK_INT < 33) {
+ return false;
+ }
+ if (captureType == UseCaseConfigFactory.CaptureType.STREAM_SHARING) {
+ if (!STREAM_USE_CASE_TO_ELIGIBLE_STREAM_SHARING_CHILDREN_TYPES_MAP.containsKey(
+ streamUseCase)) {
+ return false;
+ }
+ Set<UseCaseConfigFactory.CaptureType> captureTypes =
+ STREAM_USE_CASE_TO_ELIGIBLE_STREAM_SHARING_CHILDREN_TYPES_MAP.get(
+ streamUseCase);
+ if (streamSharingTypes.size() != captureTypes.size()) {
+ return false;
+ }
+ for (UseCaseConfigFactory.CaptureType childType : streamSharingTypes) {
+ if (!captureTypes.contains(childType)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return STREAM_USE_CASE_TO_ELIGIBLE_CAPTURE_TYPES_MAP.containsKey(streamUseCase)
+ && STREAM_USE_CASE_TO_ELIGIBLE_CAPTURE_TYPES_MAP.get(streamUseCase).contains(
+ captureType);
+ }
+ }
+
+ /**
+ * Return true if the stream use cases contained in surfaceConfigsWithStreamUseCases all have
+ * eligible capture type pairing with the use cases that these surfaceConfigs are constructed
+ * from.
+ *
+ * @param surfaceConfigIndexAttachedSurfaceInfoMap mapping between an surfaceConfig's index
+ * in the list and the attachedSurfaceInfo it
+ * is constructed from
+ * @param surfaceConfigIndexUseCaseConfigMap mapping between an surfaceConfig's index
+ * * in the list and the useCaseConfig it is
+ * constructed from
+ * @param surfaceConfigsWithStreamUseCase the supported surfaceConfigs that contains
+ * accurate streamUseCases
+ */
+ public static boolean areCaptureTypesEligible(
+ @NonNull Map<Integer, AttachedSurfaceInfo> surfaceConfigIndexAttachedSurfaceInfoMap,
+ @NonNull Map<Integer, UseCaseConfig<?>> surfaceConfigIndexUseCaseConfigMap,
+ @NonNull List<SurfaceConfig> surfaceConfigsWithStreamUseCase) {
+ for (int i = 0; i < surfaceConfigsWithStreamUseCase.size(); i++) {
+ // Verify that the use case has the eligible capture type the given stream use case.
+ long streamUseCase = surfaceConfigsWithStreamUseCase.get(i).getStreamUseCase();
+ if (surfaceConfigIndexAttachedSurfaceInfoMap.containsKey(i)) {
+ AttachedSurfaceInfo attachedSurfaceInfo =
+ surfaceConfigIndexAttachedSurfaceInfoMap.get(i);
+ if (!isEligibleCaptureType(attachedSurfaceInfo.getCaptureTypes().size() == 1
+ ? attachedSurfaceInfo.getCaptureTypes().get(0) :
+ UseCaseConfigFactory.CaptureType.STREAM_SHARING, streamUseCase,
+ attachedSurfaceInfo.getCaptureTypes())) {
+ return false;
+ }
+ } else if (surfaceConfigIndexUseCaseConfigMap.containsKey(i)) {
+ UseCaseConfig<?> newUseCaseConfig =
+ surfaceConfigIndexUseCaseConfigMap.get(i);
+ if (!isEligibleCaptureType(newUseCaseConfig.getCaptureType(), streamUseCase,
+ newUseCaseConfig.getCaptureType()
+ == UseCaseConfigFactory.CaptureType.STREAM_SHARING
+ ? ((StreamSharingConfig) newUseCaseConfig).getCaptureTypes()
+ : Collections.emptyList())) {
+ return false;
+ }
+ } else {
+ throw new AssertionError("SurfaceConfig does not map to any use case");
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @param suggestedStreamSpecMap mapping between useCaseConfig and its
+ * streamSpecs
+ * @param attachedSurfaceStreamSpecMap mapping between attachedSurfaceInfo and its
+ * streamSpecs that contains streamUseCases.
+ * All streamSpecs in this map has
+ * streamUseCases
+ * @param surfaceConfigIndexAttachedSurfaceInfoMap mapping between an surfaceConfig's index
+ * in the list and the
+ * attachedSurfaceInfo it
+ * is constructed from
+ *@param surfaceConfigIndexUseCaseConfigMap mapping between an surfaceConfig's
+ * index in the list and the useCaseConfig
+ * it is constructed from
+ * @param surfaceConfigsWithStreamUseCase the supported surfaceConfigs that contains
+ * accurate streamUseCases
+ */
+ public static void populateStreamUseCaseStreamSpecOptionWithSupportedSurfaceConfigs(
+ @NonNull Map<UseCaseConfig<?>, StreamSpec> suggestedStreamSpecMap,
+ @NonNull Map<AttachedSurfaceInfo, StreamSpec> attachedSurfaceStreamSpecMap,
+ @NonNull Map<Integer, AttachedSurfaceInfo> surfaceConfigIndexAttachedSurfaceInfoMap,
+ @NonNull Map<Integer, UseCaseConfig<?>> surfaceConfigIndexUseCaseConfigMap,
+ @NonNull List<SurfaceConfig> surfaceConfigsWithStreamUseCase) {
+ // Populate StreamSpecs with stream use cases.
+ for (int i = 0; i < surfaceConfigsWithStreamUseCase.size(); i++) {
+ long streamUseCase = surfaceConfigsWithStreamUseCase.get(i).getStreamUseCase();
+ if (surfaceConfigIndexAttachedSurfaceInfoMap.containsKey(i)) {
+ AttachedSurfaceInfo attachedSurfaceInfo =
+ surfaceConfigIndexAttachedSurfaceInfoMap.get(i);
+ Config oldImplementationOptions = attachedSurfaceInfo.getImplementationOptions();
+ Config newImplementationOptions =
+ getUpdatedImplementationOptionsWithUseCaseStreamSpecOption(
+ oldImplementationOptions, streamUseCase);
+ if (newImplementationOptions != null) {
+ attachedSurfaceStreamSpecMap.put(attachedSurfaceInfo,
+ attachedSurfaceInfo.toStreamSpec(newImplementationOptions));
+ }
+ } else if (surfaceConfigIndexUseCaseConfigMap.containsKey(i)) {
+ UseCaseConfig<?> newUseCaseConfig =
+ surfaceConfigIndexUseCaseConfigMap.get(i);
+ StreamSpec oldStreamSpec = suggestedStreamSpecMap.get(newUseCaseConfig);
+ Config oldImplementationOptions = oldStreamSpec.getImplementationOptions();
+ Config newImplementationOptions =
+ getUpdatedImplementationOptionsWithUseCaseStreamSpecOption(
+ oldImplementationOptions, streamUseCase);
+ if (newImplementationOptions != null) {
+ StreamSpec newStreamSpec =
+ oldStreamSpec.toBuilder().setImplementationOptions(
+ newImplementationOptions).build();
+ suggestedStreamSpecMap.put(newUseCaseConfig, newStreamSpec);
+ }
+
+ } else {
+ throw new AssertionError("SurfaceConfig does not map to any use case");
+ }
+ }
+
+ }
+
+ /**
* Given an old options, return a new option with stream use case stream spec option inserted
*/
@Nullable
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
index bb83079..5b16360 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
@@ -216,7 +216,8 @@
for (SurfaceCombination surfaceCombination : getSurfaceCombinationsByFeatureSettings(
featureSettings)) {
- isSupported = surfaceCombination.isSupported(surfaceConfigList);
+ isSupported = surfaceCombination.getOrderedSupportedSurfaceConfigList(surfaceConfigList)
+ != null;
if (isSupported) {
break;
@@ -227,7 +228,7 @@
}
@Nullable
- SurfaceCombination getSupportedStreamUseCaseSurfaceCombination(
+ List<SurfaceConfig> getOrderedSupportedStreamUseCaseSurfaceConfigList(
@NonNull FeatureSettings featureSettings,
List<SurfaceConfig> surfaceConfigList) {
if (!StreamUseCaseUtil.shouldUseStreamUseCase(featureSettings)) {
@@ -237,9 +238,12 @@
for (SurfaceCombination surfaceCombination : mSurfaceCombinationsStreamUseCase) {
// Stream use case table doesn't support sublist. SurfaceCombination and
// SurfaceConfig list need to be EXACT match.
- if (surfaceCombination.getSurfaceConfigList().size() == surfaceConfigList.size()
- && surfaceCombination.isSupported(surfaceConfigList)) {
- return surfaceCombination;
+ if (surfaceCombination.getSurfaceConfigList().size() == surfaceConfigList.size()) {
+ List<SurfaceConfig> orderedSurfaceConfigList =
+ surfaceCombination.getOrderedSupportedSurfaceConfigList(surfaceConfigList);
+ if (orderedSurfaceConfigList != null) {
+ return orderedSurfaceConfigList;
+ }
}
}
return null;
@@ -576,14 +580,14 @@
boolean containsZsl = StreamUseCaseUtil.containsZslUseCase(attachedSurfaces,
newUseCaseConfigs);
- SurfaceCombination surfaceCombinationForStreamUseCase =
+ List<SurfaceConfig> orderedSurfaceConfigListForStreamUseCase =
mIsStreamUseCaseSupported && !containsZsl
- ? getSupportedStreamUseCaseSurfaceCombination(featureSettings,
+ ? getOrderedSupportedStreamUseCaseSurfaceConfigList(featureSettings,
surfaceConfigs) : null;
boolean isSurfaceCombinationSupported = checkSupported(featureSettings, surfaceConfigs);
- if (surfaceCombinationForStreamUseCase == null && !isSurfaceCombinationSupported) {
+ if (orderedSurfaceConfigListForStreamUseCase == null && !isSurfaceCombinationSupported) {
throw new IllegalArgumentException(
"No supported surface combination is found for camera device - Id : "
+ mCameraId + ". May be attempting to bind too many use cases. "
@@ -631,30 +635,57 @@
Map<AttachedSurfaceInfo, StreamSpec> attachedSurfaceStreamSpecMap = new HashMap<>();
Map<UseCaseConfig<?>, StreamSpec> suggestedStreamSpecMap = new HashMap<>();
+ // The two maps are used to keep track of the attachedSurfaceInfo or useCaseConfigs the
+ // surfaceConfigs are made from. They are populated in getSurfaceConfigListAndFpsCeiling ().
+ // The keys are the position of their corresponding surfaceConfigs in the list. We can
+ // them map streamUseCases in orderedSurfaceConfigListForStreamUseCase, which is in the
+ // same order as surfaceConfigs list, to the original useCases to determine the
+ // captureTypes are correct.
+ Map<Integer, AttachedSurfaceInfo> surfaceConfigIndexAttachedSurfaceInfoMap =
+ new HashMap<>();
+ Map<Integer, UseCaseConfig<?>> surfaceConfigIndexUseCaseConfigMap =
+ new HashMap<>();
List<Size> savedSizes = null;
int savedConfigMaxFps = Integer.MAX_VALUE;
List<Size> savedSizesForStreamUseCase = null;
int savedConfigMaxFpsForStreamUseCase = Integer.MAX_VALUE;
- if (surfaceCombinationForStreamUseCase != null) {
+ if (orderedSurfaceConfigListForStreamUseCase != null) {
// Check if any possible size arrangement is supported for stream use case.
for (List<Size> possibleSizeList : allPossibleSizeArrangements) {
- List<SurfaceConfig> surfaceConfigList = getSurfaceConfigListAndFpsCeiling(
+ surfaceConfigs = getSurfaceConfigListAndFpsCeiling(
cameraMode,
attachedSurfaces, possibleSizeList, newUseCaseConfigs,
- useCasesPriorityOrder, existingSurfaceFrameRateCeiling).first;
- surfaceCombinationForStreamUseCase =
- getSupportedStreamUseCaseSurfaceCombination(featureSettings,
- surfaceConfigList);
- if (surfaceCombinationForStreamUseCase != null) {
- break;
+ useCasesPriorityOrder, existingSurfaceFrameRateCeiling,
+ surfaceConfigIndexAttachedSurfaceInfoMap,
+ surfaceConfigIndexUseCaseConfigMap).first;
+ orderedSurfaceConfigListForStreamUseCase =
+ getOrderedSupportedStreamUseCaseSurfaceConfigList(featureSettings,
+ surfaceConfigs);
+ if (orderedSurfaceConfigListForStreamUseCase != null
+ && !StreamUseCaseUtil.areCaptureTypesEligible(
+ surfaceConfigIndexAttachedSurfaceInfoMap,
+ surfaceConfigIndexUseCaseConfigMap,
+ orderedSurfaceConfigListForStreamUseCase)) {
+ orderedSurfaceConfigListForStreamUseCase = null;
}
+ if (orderedSurfaceConfigListForStreamUseCase != null) {
+ if (StreamUseCaseUtil.areStreamUseCasesAvailableForSurfaceConfigs(
+ mCharacteristics, orderedSurfaceConfigListForStreamUseCase)) {
+ break;
+ } else {
+ orderedSurfaceConfigListForStreamUseCase = null;
+ }
+ }
+ surfaceConfigIndexAttachedSurfaceInfoMap.clear();
+ surfaceConfigIndexUseCaseConfigMap.clear();
}
// We can terminate early if surface combination is not supported and none of the
// possible size arrangement supports stream use case either.
- if (surfaceCombinationForStreamUseCase == null && !isSurfaceCombinationSupported) {
+ if (orderedSurfaceConfigListForStreamUseCase == null
+ && !isSurfaceCombinationSupported) {
throw new IllegalArgumentException(
"No supported surface combination is found for camera device - Id : "
+ mCameraId + ". May be attempting to bind too many use cases. "
@@ -672,7 +703,7 @@
Pair<List<SurfaceConfig>, Integer> resultPair =
getSurfaceConfigListAndFpsCeiling(cameraMode,
attachedSurfaces, possibleSizeList, newUseCaseConfigs,
- useCasesPriorityOrder, existingSurfaceFrameRateCeiling);
+ useCasesPriorityOrder, existingSurfaceFrameRateCeiling, null, null);
List<SurfaceConfig> surfaceConfigList = resultPair.first;
int currentConfigFramerateCeiling = resultPair.second;
boolean isConfigFrameRateAcceptable = true;
@@ -717,8 +748,9 @@
// use case table, keep an independent tracking on the saved sizes and max FPS. Only
// use stream use case if the save sizes for the normal case and for stream use case
// are the same.
- if (surfaceCombinationForStreamUseCase != null && !supportedSizesForStreamUseCaseFound
- && getSupportedStreamUseCaseSurfaceCombination(
+ if (orderedSurfaceConfigListForStreamUseCase != null
+ && !supportedSizesForStreamUseCaseFound
+ && getOrderedSupportedStreamUseCaseSurfaceConfigList(
featureSettings, surfaceConfigList) != null) {
if (savedConfigMaxFpsForStreamUseCase == Integer.MAX_VALUE) {
savedConfigMaxFpsForStreamUseCase = currentConfigFramerateCeiling;
@@ -771,7 +803,7 @@
}
// Only perform stream use case operations if the saved max FPS and sizes are the same
- if (surfaceCombinationForStreamUseCase != null
+ if (orderedSurfaceConfigListForStreamUseCase != null
&& savedConfigMaxFps == savedConfigMaxFpsForStreamUseCase
&& savedSizes.size() == savedSizesForStreamUseCase.size()) {
boolean hasDifferenceSavedSizes = false;
@@ -787,12 +819,15 @@
mCharacteristics, attachedSurfaces, suggestedStreamSpecMap,
attachedSurfaceStreamSpecMap);
if (!hasStreamUseCaseOverride) {
- // TODO(b/280335430): Use surfaceCombinationForStreamUseCase to populate the
- // streamSpec maps
+ StreamUseCaseUtil
+ .populateStreamUseCaseStreamSpecOptionWithSupportedSurfaceConfigs(
+ suggestedStreamSpecMap, attachedSurfaceStreamSpecMap,
+ surfaceConfigIndexAttachedSurfaceInfoMap,
+ surfaceConfigIndexUseCaseConfigMap,
+ orderedSurfaceConfigListForStreamUseCase);
}
}
}
-
return new Pair<>(suggestedStreamSpecMap, attachedSurfaceStreamSpecMap);
}
@@ -801,10 +836,16 @@
List<AttachedSurfaceInfo> attachedSurfaces,
List<Size> possibleSizeList, List<UseCaseConfig<?>> newUseCaseConfigs,
List<Integer> useCasesPriorityOrder,
- int currentConfigFramerateCeiling) {
+ int currentConfigFramerateCeiling,
+ @Nullable Map<Integer, AttachedSurfaceInfo> surfaceConfigIndexAttachedSurfaceInfoMap,
+ @Nullable Map<Integer, UseCaseConfig<?>> surfaceConfigIndexUseCaseConfigMap) {
List<SurfaceConfig> surfaceConfigList = new ArrayList<>();
for (AttachedSurfaceInfo attachedSurfaceInfo : attachedSurfaces) {
surfaceConfigList.add(attachedSurfaceInfo.getSurfaceConfig());
+ if (surfaceConfigIndexAttachedSurfaceInfoMap != null) {
+ surfaceConfigIndexAttachedSurfaceInfoMap.put(surfaceConfigList.size() - 1,
+ attachedSurfaceInfo);
+ }
}
// Attach SurfaceConfig of new use cases
@@ -814,12 +855,15 @@
newUseCaseConfigs.get(useCasesPriorityOrder.get(i));
int imageFormat = newUseCase.getInputFormat();
// add new use case/size config to list of surfaces
- surfaceConfigList.add(
- SurfaceConfig.transformSurfaceConfig(
- cameraMode,
- imageFormat,
- size,
- getUpdatedSurfaceSizeDefinitionByFormat(imageFormat)));
+ SurfaceConfig surfaceConfig = SurfaceConfig.transformSurfaceConfig(
+ cameraMode,
+ imageFormat,
+ size,
+ getUpdatedSurfaceSizeDefinitionByFormat(imageFormat));
+ surfaceConfigList.add(surfaceConfig);
+ if (surfaceConfigIndexUseCaseConfigMap != null) {
+ surfaceConfigIndexUseCaseConfigMap.put(surfaceConfigList.size() - 1, newUseCase);
+ }
// get the maximum fps of the new surface and update the maximum fps of the
// proposed configuration
currentConfigFramerateCeiling = getUpdatedMaximumFps(
@@ -1058,8 +1102,10 @@
}
private void generateStreamUseCaseSupportedCombinationList() {
- mSurfaceCombinationsStreamUseCase.addAll(
- GuaranteedConfigurationsUtil.getStreamUseCaseSupportedCombinationList());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ mSurfaceCombinationsStreamUseCase.addAll(
+ GuaranteedConfigurationsUtil.getStreamUseCaseSupportedCombinationList());
+ }
}
private void checkCustomization() {
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
index 2707bd14..a0447b4 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
@@ -118,6 +118,8 @@
new Range<>(30, 30),
new Range<>(60, 60)
};
+
+ @RequiresApi(33)
private static final DynamicRangeProfiles CAMERA0_DYNAMIC_RANGE_PROFILES =
new DynamicRangeProfiles(new long[]{DynamicRangeProfiles.HLG10, 0, 0});
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt
index 1fd51f95..3ba7c5a 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt
@@ -30,6 +30,7 @@
import android.media.ImageWriter
import android.os.Build
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.impl.Camera2ImplConfig
import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat
import androidx.camera.camera2.internal.compat.quirk.AutoFlashUnderExposedQuirk
@@ -561,6 +562,7 @@
}
}
+ @Config(minSdk = 23)
@Test
fun submitZslCaptureRequests_withZslTemplate_templateZeroShutterLagSent(): Unit = runBlocking {
// Arrange.
@@ -595,6 +597,7 @@
}
}
+ @Config(minSdk = 23)
@Test
fun submitZslCaptureRequests_withZslDisabledByFlashMode_templateStillPictureSent():
Unit = runBlocking {
@@ -626,6 +629,7 @@
}
}
+ @Config(minSdk = 23)
@Test
fun submitZslCaptureRequests_withZslDisabledByUseCaseConfig_templateStillPictureSent():
Unit = runBlocking {
@@ -657,6 +661,7 @@
}
}
+ @Config(minSdk = 23)
@Test
fun submitZslCaptureRequests_withNoTemplate_templateStillPictureSent(): Unit = runBlocking {
// Arrange.
@@ -1230,6 +1235,7 @@
)
}
+ @RequiresApi(23)
private fun initCameraControlWithZsl(
isZslDisabledByFlashMode: Boolean,
isZslDisabledByUserCaseConfig: Boolean
@@ -1263,4 +1269,4 @@
return cameraControl
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/DynamicRangeTestCases.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/DynamicRangeTestCases.kt
index 2a3f032..d3212b9 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/DynamicRangeTestCases.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/DynamicRangeTestCases.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(33)
+
package androidx.camera.camera2.internal
import android.hardware.camera2.params.DynamicRangeProfiles
@@ -23,6 +25,7 @@
import android.hardware.camera2.params.DynamicRangeProfiles.HDR10_PLUS
import android.hardware.camera2.params.DynamicRangeProfiles.HLG10
import android.hardware.camera2.params.DynamicRangeProfiles.STANDARD
+import androidx.annotation.RequiresApi
val HLG10_UNCONSTRAINED by lazy {
DynamicRangeProfiles(longArrayOf(HLG10, 0, 0))
@@ -138,4 +141,4 @@
const val LATENCY_NONE = 0L
private const val LATENCY_NON_ZERO = 3L
-private const val CONSTRAINTS_NONE = 0L
\ No newline at end of file
+private const val CONSTRAINTS_NONE = 0L
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.kt
index ee861a4..cee3266 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.camera2.internal
import android.content.Context
@@ -28,6 +30,7 @@
import android.util.Pair
import android.util.Rational
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.impl.Camera2ImplConfig
import androidx.camera.camera2.internal.Camera2CameraControlImpl.CaptureResultListener
import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java
index 7439f09..b2e194c 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java
@@ -19,6 +19,7 @@
import static android.os.Build.VERSION.SDK_INT;
import static androidx.camera.camera2.internal.StreamUseCaseUtil.STREAM_USE_CASE_STREAM_SPEC_OPTION;
+import static androidx.camera.core.DynamicRange.BIT_DEPTH_10_BIT;
import static androidx.camera.core.ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY;
import static androidx.camera.core.ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG;
@@ -27,9 +28,7 @@
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraMetadata;
-import android.media.MediaCodec;
import android.os.Build;
import android.view.Surface;
@@ -37,9 +36,8 @@
import androidx.camera.camera2.impl.Camera2ImplConfig;
import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
import androidx.camera.core.DynamicRange;
-import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
-import androidx.camera.core.Preview;
+import androidx.camera.core.UseCase;
import androidx.camera.core.impl.AttachedSurfaceInfo;
import androidx.camera.core.impl.CameraMode;
import androidx.camera.core.impl.DeferrableSurface;
@@ -53,10 +51,11 @@
import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.internal.utils.SizeUtil;
import androidx.camera.core.streamsharing.StreamSharing;
+import androidx.camera.testing.fakes.FakeCamera;
import androidx.camera.testing.fakes.FakeUseCase;
import androidx.camera.testing.fakes.FakeUseCaseConfig;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
import androidx.concurrent.futures.ResolvableFuture;
-import androidx.test.filters.SdkSuppress;
import com.google.common.util.concurrent.ListenableFuture;
@@ -65,19 +64,22 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
import org.robolectric.annotation.internal.DoNotInstrument;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowCameraCharacteristics;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+@Config(minSdk = 33)
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
public class StreamUseCaseTest {
-
private CameraCharacteristics mCameraCharacteristics;
private static final String CAMERA_ID_0 = "0";
private static final Long TEST_STREAM_USE_CASE_OPTION_VALUE = Long.valueOf(
@@ -85,7 +87,18 @@
private static final @ImageCapture.CaptureMode int TEST_OPTION_IMAGE_CAPTURE_MODE_VALUE =
CAPTURE_MODE_MAXIMIZE_QUALITY;
- DeferrableSurface mMockSurface = new DeferrableSurface() {
+ DeferrableSurface mMockSurface1 = new DeferrableSurface() {
+ private final ListenableFuture<Surface> mSurfaceFuture = ResolvableFuture.create();
+
+ @NonNull
+ @Override
+ protected ListenableFuture<Surface> provideSurface() {
+ // Return a never complete future.
+ return mSurfaceFuture;
+ }
+ };
+
+ DeferrableSurface mMockSurface2 = new DeferrableSurface() {
private final ListenableFuture<Surface> mSurfaceFuture = ResolvableFuture.create();
@NonNull
@@ -103,210 +116,64 @@
@After
public void tearDown() {
- mMockSurface.close();
+ mMockSurface1.close();
+ mMockSurface2.close();
}
- @SdkSuppress(maxSdkVersion = 32, minSdkVersion = 21)
@Test
- public void getStreamUseCaseFromOsNotSupported() {
+ public void populateSurfaceToStreamUseCaseMapping_singlePreview() {
Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(Preview.class);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- new ArrayList<>(), streamUseCaseMap, getCameraCharacteristicsCompat(), true);
- assertTrue(streamUseCaseMap.isEmpty());
- }
-
- @SdkSuppress(minSdkVersion = 33)
- @Test
- public void getStreamUseCaseFromUseCaseEmptyUseCase() {
- Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- new ArrayList<>(), streamUseCaseMap, getCameraCharacteristicsCompat(), true);
- assertTrue(streamUseCaseMap.isEmpty());
- }
-
- @SdkSuppress(minSdkVersion = 33)
- @Test
- public void getStreamUseCaseFromUseCaseNoPreview() {
- Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(FakeUseCase.class);
+ MutableOptionsBundle optionsBundle = MutableOptionsBundle.create();
+ optionsBundle.insertOption(STREAM_USE_CASE_STREAM_SPEC_OPTION,
+ Long.valueOf(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
SessionConfig sessionConfig =
new SessionConfig.Builder()
- .addSurface(mMockSurface).build();
+ .addSurface(mMockSurface1)
+ .addImplementationOptions(new Camera2ImplConfig(optionsBundle)).build();
+ UseCaseConfig<?> useCaseConfig = getFakeUseCaseConfigWithOptions(true, false, false,
+ UseCaseConfigFactory.CaptureType.PREVIEW, ImageFormat.PRIVATE);
ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
sessionConfigs.add(sessionConfig);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
- assertTrue(streamUseCaseMap.isEmpty());
+ ArrayList<UseCaseConfig<?>> useCaseConfigs = new ArrayList<>();
+ useCaseConfigs.add(useCaseConfig);
+ StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(sessionConfigs, useCaseConfigs,
+ streamUseCaseMap);
+ assertTrue(streamUseCaseMap.get(mMockSurface1) == Long.valueOf(
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
}
@Test
- public void getStreamUseCaseFromUseCaseStreamSharing() {
+ public void populateSurfaceToStreamUseCaseMapping_imageCaptureAndMeteringRepeat() {
Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(StreamSharing.class);
- SessionConfig sessionConfig =
+ MutableOptionsBundle optionsBundle = MutableOptionsBundle.create();
+ optionsBundle.insertOption(STREAM_USE_CASE_STREAM_SPEC_OPTION,
+ Long.valueOf(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE));
+ SessionConfig imageCaptureSessionConfig =
new SessionConfig.Builder()
- .addSurface(mMockSurface).build();
+ .addSurface(mMockSurface1)
+ .addImplementationOptions(new Camera2ImplConfig(optionsBundle)).build();
+ SessionConfig meteringRepeatingSessionConfig =
+ new SessionConfig.Builder()
+ .addSurface(mMockSurface2).build();
+ UseCaseConfig<?> imageCaptureConfig = getFakeUseCaseConfigWithOptions(true, false, false,
+ UseCaseConfigFactory.CaptureType.IMAGE_CAPTURE, ImageFormat.YUV_420_888);
+ UseCaseConfig<?> meteringRepeatingConfig = getFakeUseCaseConfigWithOptions(true, false,
+ false, UseCaseConfigFactory.CaptureType.METERING_REPEATING, ImageFormat.PRIVATE);
ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
- sessionConfigs.add(sessionConfig);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
- assertTrue(streamUseCaseMap.get(mMockSurface)
- == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD);
+ sessionConfigs.add(imageCaptureSessionConfig);
+ sessionConfigs.add(meteringRepeatingSessionConfig);
+ ArrayList<UseCaseConfig<?>> useCaseConfigs = new ArrayList<>();
+ useCaseConfigs.add(imageCaptureConfig);
+ useCaseConfigs.add(meteringRepeatingConfig);
+ StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(sessionConfigs, useCaseConfigs,
+ streamUseCaseMap);
+ assertTrue(streamUseCaseMap.get(mMockSurface1) == Long.valueOf(
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE));
+ assertTrue(streamUseCaseMap.get(mMockSurface2) == Long.valueOf(
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
}
@Test
- public void getStreamUseCaseFromUseCasePreview() {
- Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(Preview.class);
- SessionConfig sessionConfig =
- new SessionConfig.Builder()
- .addSurface(mMockSurface).build();
- ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
- sessionConfigs.add(sessionConfig);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
- assertTrue(streamUseCaseMap.get(mMockSurface)
- == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW);
- }
-
- @SdkSuppress(minSdkVersion = 33)
- @Test
- public void getStreamUseCaseFromUseCaseZSL() {
- Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(Preview.class);
- SessionConfig sessionConfig =
- new SessionConfig.Builder()
- .addSurface(mMockSurface)
- .setTemplateType(
- CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG).build();
- ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
- sessionConfigs.add(sessionConfig);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
- assertTrue(streamUseCaseMap.isEmpty());
- }
-
- @SdkSuppress(minSdkVersion = 33)
- @Test
- public void getStreamUseCaseFromUseCaseImageAnalysis() {
- Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(ImageAnalysis.class);
- SessionConfig sessionConfig =
- new SessionConfig.Builder()
- .addSurface(mMockSurface).build();
- ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
- sessionConfigs.add(sessionConfig);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
- assertTrue(streamUseCaseMap.get(mMockSurface)
- == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW);
- }
-
- @SdkSuppress(minSdkVersion = 33)
- @Test
- public void getStreamUseCaseFromUseCaseConfigsImageCapture() {
- Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(ImageCapture.class);
- SessionConfig sessionConfig =
- new SessionConfig.Builder()
- .addSurface(mMockSurface).build();
- ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
- sessionConfigs.add(sessionConfig);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
- assertTrue(streamUseCaseMap.get(mMockSurface)
- == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE);
- }
-
- @SdkSuppress(minSdkVersion = 33)
- @Test
- public void getStreamUseCaseFromUseCaseConfigsVideoCapture() {
- Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(MediaCodec.class);
- SessionConfig sessionConfig =
- new SessionConfig.Builder()
- .addSurface(mMockSurface).build();
- ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
- sessionConfigs.add(sessionConfig);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
- assertTrue(streamUseCaseMap.get(mMockSurface)
- == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD);
- }
-
- @SdkSuppress(minSdkVersion = 33)
- @Test
- public void getStreamUseCaseWithNullAvailableUseCases() {
- Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(FakeUseCase.class);
- SessionConfig sessionConfig =
- new SessionConfig.Builder()
- .addSurface(mMockSurface).build();
- ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
- sessionConfigs.add(sessionConfig);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- sessionConfigs, streamUseCaseMap,
- CameraCharacteristicsCompat.toCameraCharacteristicsCompat(mCameraCharacteristics,
- CAMERA_ID_0), true);
- assertTrue(streamUseCaseMap.isEmpty());
- }
-
- @SdkSuppress(minSdkVersion = 33)
- @Test
- public void getStreamUseCaseWithEmptyAvailableUseCases() {
- Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(Preview.class);
- SessionConfig sessionConfig =
- new SessionConfig.Builder()
- .addSurface(mMockSurface).build();
- ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
- sessionConfigs.add(sessionConfig);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- sessionConfigs,
- streamUseCaseMap,
- getCameraCharacteristicsCompatWithEmptyUseCases(),
- true);
- assertTrue(streamUseCaseMap.isEmpty());
- }
-
- @Test
- public void getStreamUseCaseFromCamera2Interop() {
- Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(Preview.class);
- MutableOptionsBundle testStreamUseCaseConfig = MutableOptionsBundle.create();
- testStreamUseCaseConfig.insertOption(Camera2ImplConfig.STREAM_USE_CASE_OPTION, 3L);
- SessionConfig sessionConfig =
- new SessionConfig.Builder()
- .addSurface(mMockSurface).addImplementationOptions(
- testStreamUseCaseConfig).build();
- ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
- sessionConfigs.add(sessionConfig);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
- assertTrue(streamUseCaseMap.get(mMockSurface) == 3L);
- }
-
- @Test
- public void getUnsupportedStreamUseCaseFromCamera2Interop() {
- Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
- mMockSurface.setContainerClass(Preview.class);
- MutableOptionsBundle testStreamUseCaseConfig = MutableOptionsBundle.create();
- testStreamUseCaseConfig.insertOption(Camera2ImplConfig.STREAM_USE_CASE_OPTION, -1L);
- SessionConfig sessionConfig =
- new SessionConfig.Builder()
- .addSurface(mMockSurface).addImplementationOptions(
- testStreamUseCaseConfig).build();
- ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
- sessionConfigs.add(sessionConfig);
- StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
- sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
- assertTrue(streamUseCaseMap.get(mMockSurface)
- == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW);
- }
-
- @SdkSuppress(minSdkVersion = 33)
- @Test
public void getStreamSpecImplementationOptions() {
Camera2ImplConfig result =
StreamUseCaseUtil.getStreamSpecImplementationOptions(
@@ -321,14 +188,12 @@
== ImageFormat.PRIVATE);
}
- @SdkSuppress(minSdkVersion = 33)
@Test
public void isStreamUseCaseSupported_streamUseCaseNotAvailable() {
assertFalse(StreamUseCaseUtil.isStreamUseCaseSupported(
getCameraCharacteristicsCompat(true)));
}
- @SdkSuppress(minSdkVersion = 33)
@Test
public void shouldUseStreamUseCase_cameraModeNotSupported() {
assertFalse(StreamUseCaseUtil.shouldUseStreamUseCase(
@@ -336,15 +201,13 @@
DynamicRange.BIT_DEPTH_8_BIT)));
}
- @SdkSuppress(minSdkVersion = 33)
@Test
public void shouldUseStreamUseCase_bitDepthNotSupported() {
assertFalse(StreamUseCaseUtil.shouldUseStreamUseCase(
SupportedSurfaceCombination.FeatureSettings.of(CameraMode.DEFAULT,
- DynamicRange.BIT_DEPTH_10_BIT)));
+ BIT_DEPTH_10_BIT)));
}
- @SdkSuppress(minSdkVersion = 33)
@Test
public void containsZslUseCase_isZslUseCase() {
UseCaseConfig<?> useCaseConfig = getFakeUseCaseConfigWithOptions(true, false, true,
@@ -354,7 +217,6 @@
assertTrue(StreamUseCaseUtil.containsZslUseCase(new ArrayList<>(), useCaseConfigList));
}
- @SdkSuppress(minSdkVersion = 33)
@Test
public void containsZslUseCase_isZslUseCase_ZslDisabled() {
UseCaseConfig<?> useCaseConfig = getFakeUseCaseConfigWithOptions(true, true, true,
@@ -364,7 +226,6 @@
assertFalse(StreamUseCaseUtil.containsZslUseCase(new ArrayList<>(), useCaseConfigList));
}
- @SdkSuppress(minSdkVersion = 33)
@Test
public void containsZslUseCase_isZslSurface() {
List<AttachedSurfaceInfo> attachedSurfaces = new ArrayList<>();
@@ -373,7 +234,6 @@
assertTrue(StreamUseCaseUtil.containsZslUseCase(attachedSurfaces, new ArrayList<>()));
}
- @SdkSuppress(minSdkVersion = 33)
@Test
public void containsZslUseCase_isZslSurface_ZslDisabled() {
List<AttachedSurfaceInfo> attachedSurfaces = new ArrayList<>();
@@ -382,7 +242,6 @@
assertFalse(StreamUseCaseUtil.containsZslUseCase(attachedSurfaces, new ArrayList<>()));
}
- @SdkSuppress(minSdkVersion = 33)
@Test
public void populateStreamUseCaseStreamSpecOption_camera2InteropOverride_singleNewUseCase() {
Map<UseCaseConfig<?>, StreamSpec> suggestedStreamSpecMap = new HashMap<>();
@@ -398,7 +257,6 @@
STREAM_USE_CASE_STREAM_SPEC_OPTION) == TEST_STREAM_USE_CASE_OPTION_VALUE);
}
- @SdkSuppress(minSdkVersion = 33)
@Test
public void populateStreamUseCaseStreamSpecOption_camera2InteropOverride_singleSurface() {
List<AttachedSurfaceInfo> attachedSurfaces = new ArrayList<>();
@@ -414,7 +272,6 @@
STREAM_USE_CASE_STREAM_SPEC_OPTION) == TEST_STREAM_USE_CASE_OPTION_VALUE);
}
- @SdkSuppress(minSdkVersion = 33)
@Test
public void populateStreamUseCaseStreamSpecOption_camera2InteropOverride_useCaseAndSurface() {
Map<UseCaseConfig<?>, StreamSpec> suggestedStreamSpecMap = new HashMap<>();
@@ -455,6 +312,276 @@
);
}
+ @Test
+ public void areStreamUseCasesAvailableForSurfaceConfigs_success() {
+ List<SurfaceConfig> surfaceConfigList = new ArrayList<>();
+ surfaceConfigList.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
+ assertTrue(StreamUseCaseUtil.areStreamUseCasesAvailableForSurfaceConfigs(
+ getCameraCharacteristicsCompat(false), surfaceConfigList));
+
+ }
+
+ @Test
+ public void areStreamUseCasesAvailableForSurfaceConfigs_fail() {
+ List<SurfaceConfig> surfaceConfigList = new ArrayList<>();
+ surfaceConfigList.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
+ assertFalse(StreamUseCaseUtil.areStreamUseCasesAvailableForSurfaceConfigs(
+ getCameraCharacteristicsCompat(true), surfaceConfigList));
+
+ }
+
+ @Test
+ public void areCaptureTypesEligible_success() {
+ List<SurfaceConfig> surfaceConfigsWithStreamUseCase = new ArrayList<>();
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
+ List<SurfaceConfig> originalSurfaceConfigs = new ArrayList<>();
+ originalSurfaceConfigs.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW));
+ originalSurfaceConfigs.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.RECORD));
+ Map<Integer, AttachedSurfaceInfo> surfaceConfigAttachedSurfaceInfoMap =
+ new HashMap<>();
+ surfaceConfigAttachedSurfaceInfoMap.put(0,
+ getFakeAttachedSurfaceInfo(false, false, false,
+ UseCaseConfigFactory.CaptureType.PREVIEW, ImageFormat.PRIVATE));
+ @NonNull Map<Integer, UseCaseConfig<?>> surfaceConfigUseCaseConfigMap =
+ new HashMap<>();
+ surfaceConfigUseCaseConfigMap.put(1,
+ getFakeUseCaseConfigWithOptions(false, false, false,
+ UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE, ImageFormat.PRIVATE));
+
+ assertTrue(StreamUseCaseUtil.areCaptureTypesEligible(surfaceConfigAttachedSurfaceInfoMap,
+ surfaceConfigUseCaseConfigMap, surfaceConfigsWithStreamUseCase));
+ }
+
+ @Test
+ public void areCaptureTypesEligible_fail() {
+ List<SurfaceConfig> surfaceConfigsWithStreamUseCase = new ArrayList<>();
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
+ List<SurfaceConfig> originalSurfaceConfigs = new ArrayList<>();
+ originalSurfaceConfigs.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW));
+ originalSurfaceConfigs.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.RECORD));
+ Map<Integer, AttachedSurfaceInfo> surfaceConfigAttachedSurfaceInfoMap =
+ new HashMap<>();
+ surfaceConfigAttachedSurfaceInfoMap.put(0,
+ getFakeAttachedSurfaceInfo(false, false, false,
+ UseCaseConfigFactory.CaptureType.PREVIEW, ImageFormat.PRIVATE));
+ @NonNull Map<Integer, UseCaseConfig<?>> surfaceConfigUseCaseConfigMap =
+ new HashMap<>();
+ surfaceConfigUseCaseConfigMap.put(1,
+ getFakeUseCaseConfigWithOptions(false, false, false,
+ UseCaseConfigFactory.CaptureType.PREVIEW, ImageFormat.PRIVATE));
+
+ assertFalse(StreamUseCaseUtil.areCaptureTypesEligible(surfaceConfigAttachedSurfaceInfoMap,
+ surfaceConfigUseCaseConfigMap, surfaceConfigsWithStreamUseCase));
+ }
+
+ @Test(expected = AssertionError.class)
+ public void areCaptureTypesEligible_mappingError() {
+ List<SurfaceConfig> surfaceConfigsWithStreamUseCase = new ArrayList<>();
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
+ List<SurfaceConfig> originalSurfaceConfigs = new ArrayList<>();
+ originalSurfaceConfigs.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW));
+ originalSurfaceConfigs.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.RECORD));
+ Map<Integer, AttachedSurfaceInfo> surfaceConfigAttachedSurfaceInfoMap =
+ new HashMap<>();
+ @NonNull Map<Integer, UseCaseConfig<?>> surfaceConfigUseCaseConfigMap =
+ new HashMap<>();
+ surfaceConfigUseCaseConfigMap.put(1,
+ getFakeUseCaseConfigWithOptions(false, false, false,
+ UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE, ImageFormat.PRIVATE));
+
+ StreamUseCaseUtil.areCaptureTypesEligible(surfaceConfigAttachedSurfaceInfoMap,
+ surfaceConfigUseCaseConfigMap, surfaceConfigsWithStreamUseCase);
+ }
+
+ @Test
+ public void areCaptureTypesEligible_streamSharing_previewVideoStill_success() {
+ List<SurfaceConfig> surfaceConfigsWithStreamUseCase = new ArrayList<>();
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL));
+ UseCaseConfigFactory useCaseConfigFactory = new FakeUseCaseConfigFactory();
+ Set<UseCase> children = new HashSet<>();
+ children.add(new FakeUseCase(new FakeUseCaseConfig.Builder().getUseCaseConfig(),
+ UseCaseConfigFactory.CaptureType.PREVIEW));
+ children.add(new FakeUseCase(new FakeUseCaseConfig.Builder().getUseCaseConfig(),
+ UseCaseConfigFactory.CaptureType.IMAGE_CAPTURE));
+ children.add(new FakeUseCase(new FakeUseCaseConfig.Builder().getUseCaseConfig(),
+ UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE));
+ StreamSharing streamSharing = new StreamSharing(new FakeCamera(), children,
+ useCaseConfigFactory);
+ Map<Integer, AttachedSurfaceInfo> surfaceConfigAttachedSurfaceInfoMap =
+ new HashMap<>();
+ @NonNull Map<Integer, UseCaseConfig<?>> surfaceConfigUseCaseConfigMap =
+ new HashMap<>();
+ surfaceConfigUseCaseConfigMap.put(0,
+ streamSharing.getDefaultConfig(true, useCaseConfigFactory));
+
+ assertTrue(StreamUseCaseUtil.areCaptureTypesEligible(surfaceConfigAttachedSurfaceInfoMap,
+ surfaceConfigUseCaseConfigMap, surfaceConfigsWithStreamUseCase));
+ }
+
+ @Test
+ public void areCaptureTypesEligible_streamSharing_videoRecord_success() {
+ List<SurfaceConfig> surfaceConfigsWithStreamUseCase = new ArrayList<>();
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
+ Map<Integer, AttachedSurfaceInfo> surfaceConfigAttachedSurfaceInfoMap =
+ new HashMap<>();
+ @NonNull Map<Integer, UseCaseConfig<?>> surfaceConfigUseCaseConfigMap =
+ new HashMap<>();
+ List<UseCaseConfigFactory.CaptureType> captureTypes = new ArrayList<>();
+ captureTypes.add(UseCaseConfigFactory.CaptureType.PREVIEW);
+ captureTypes.add(UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE);
+ surfaceConfigAttachedSurfaceInfoMap.put(0,
+ AttachedSurfaceInfo.create(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV,
+ SurfaceConfig.ConfigSize.PREVIEW
+ ),
+ ImageFormat.PRIVATE,
+ SizeUtil.RESOLUTION_720P,
+ DynamicRange.SDR,
+ captureTypes,
+ /*implementationOptions=*/null,
+ /*targetFrameRate=*/null));
+
+ assertTrue(StreamUseCaseUtil.areCaptureTypesEligible(surfaceConfigAttachedSurfaceInfoMap,
+ surfaceConfigUseCaseConfigMap, surfaceConfigsWithStreamUseCase));
+ }
+
+ @Test
+ public void areCaptureTypesEligible_streamSharing_fail() {
+ List<SurfaceConfig> surfaceConfigsWithStreamUseCase = new ArrayList<>();
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
+ Map<Integer, AttachedSurfaceInfo> surfaceConfigAttachedSurfaceInfoMap =
+ new HashMap<>();
+ @NonNull Map<Integer, UseCaseConfig<?>> surfaceConfigUseCaseConfigMap =
+ new HashMap<>();
+ List<UseCaseConfigFactory.CaptureType> captureTypes = new ArrayList<>();
+ captureTypes.add(UseCaseConfigFactory.CaptureType.PREVIEW);
+ captureTypes.add(UseCaseConfigFactory.CaptureType.IMAGE_CAPTURE);
+ captureTypes.add(UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE);
+ surfaceConfigAttachedSurfaceInfoMap.put(0,
+ AttachedSurfaceInfo.create(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV,
+ SurfaceConfig.ConfigSize.PREVIEW
+ ),
+ ImageFormat.PRIVATE,
+ SizeUtil.RESOLUTION_720P,
+ DynamicRange.SDR,
+ captureTypes,
+ /*implementationOptions=*/null,
+ /*targetFrameRate=*/null));
+
+ assertFalse(StreamUseCaseUtil.areCaptureTypesEligible(surfaceConfigAttachedSurfaceInfoMap,
+ surfaceConfigUseCaseConfigMap, surfaceConfigsWithStreamUseCase));
+ }
+
+ @Test
+ public void populateStreamUseCaseStreamSpecOptionWithSupportedSurfaceConfigs_success() {
+ List<SurfaceConfig> surfaceConfigsWithStreamUseCase = new ArrayList<>();
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
+ List<SurfaceConfig> originalSurfaceConfigs = new ArrayList<>();
+ originalSurfaceConfigs.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW));
+ originalSurfaceConfigs.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.RECORD));
+ Map<Integer, AttachedSurfaceInfo> surfaceConfigAttachedSurfaceInfoMap =
+ new HashMap<>();
+ AttachedSurfaceInfo attachedSurfaceInfo = getFakeAttachedSurfaceInfo(false, false, false,
+ UseCaseConfigFactory.CaptureType.PREVIEW, ImageFormat.PRIVATE);
+ surfaceConfigAttachedSurfaceInfoMap.put(0, attachedSurfaceInfo);
+ @NonNull Map<Integer, UseCaseConfig<?>> surfaceConfigUseCaseConfigMap =
+ new HashMap<>();
+ UseCaseConfig<?> useCaseConfig = getFakeUseCaseConfigWithOptions(false, false, false,
+ UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE, ImageFormat.PRIVATE);
+ surfaceConfigUseCaseConfigMap.put(1, useCaseConfig);
+ @NonNull Map<AttachedSurfaceInfo, StreamSpec> attachedSurfaceStreamSpecMap =
+ new HashMap<>();
+ Map<UseCaseConfig<?>, StreamSpec> suggestedStreamSpecMap = new HashMap<>();
+ suggestedStreamSpecMap.put(useCaseConfig,
+ getFakeStreamSpecFromFakeUseCaseConfig(useCaseConfig));
+
+ StreamUseCaseUtil.populateStreamUseCaseStreamSpecOptionWithSupportedSurfaceConfigs(
+ suggestedStreamSpecMap, attachedSurfaceStreamSpecMap,
+ surfaceConfigAttachedSurfaceInfoMap,
+ surfaceConfigUseCaseConfigMap, surfaceConfigsWithStreamUseCase);
+
+ assertTrue(attachedSurfaceStreamSpecMap.get(
+ attachedSurfaceInfo).getImplementationOptions().retrieveOption(
+ STREAM_USE_CASE_STREAM_SPEC_OPTION)
+ == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW);
+ assertTrue(suggestedStreamSpecMap.get(
+ useCaseConfig).getImplementationOptions().retrieveOption(
+ STREAM_USE_CASE_STREAM_SPEC_OPTION)
+ == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void populateStreamUseCaseStreamSpecOptionWithSupportedSurfaceConfigs_mappingError() {
+ List<SurfaceConfig> surfaceConfigsWithStreamUseCase = new ArrayList<>();
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW));
+ surfaceConfigsWithStreamUseCase.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD));
+ List<SurfaceConfig> originalSurfaceConfigs = new ArrayList<>();
+ originalSurfaceConfigs.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.PREVIEW));
+ originalSurfaceConfigs.add(SurfaceConfig.create(
+ SurfaceConfig.ConfigType.PRIV, SurfaceConfig.ConfigSize.RECORD));
+ Map<Integer, AttachedSurfaceInfo> surfaceConfigAttachedSurfaceInfoMap =
+ new HashMap<>();
+ @NonNull Map<Integer, UseCaseConfig<?>> surfaceConfigUseCaseConfigMap =
+ new HashMap<>();
+ UseCaseConfig<?> useCaseConfig = getFakeUseCaseConfigWithOptions(false, false, false,
+ UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE, ImageFormat.PRIVATE);
+ surfaceConfigUseCaseConfigMap.put(1, useCaseConfig);
+ @NonNull Map<AttachedSurfaceInfo, StreamSpec> attachedSurfaceStreamSpecMap =
+ new HashMap<>();
+ Map<UseCaseConfig<?>, StreamSpec> suggestedStreamSpecMap = new HashMap<>();
+ suggestedStreamSpecMap.put(useCaseConfig,
+ getFakeStreamSpecFromFakeUseCaseConfig(useCaseConfig));
+
+ StreamUseCaseUtil.populateStreamUseCaseStreamSpecOptionWithSupportedSurfaceConfigs(
+ suggestedStreamSpecMap, attachedSurfaceStreamSpecMap,
+ surfaceConfigAttachedSurfaceInfoMap,
+ surfaceConfigUseCaseConfigMap, surfaceConfigsWithStreamUseCase);
+ }
+
private UseCaseConfig<?> getFakeUseCaseConfigWithOptions(boolean camera2InteropOverride,
boolean isZslDisabled, boolean isZslCaptureMode,
UseCaseConfigFactory.CaptureType captureType, int imageFormat) {
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
index b0437c1..fd76d19 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.camera2.internal
import android.content.Context
@@ -42,6 +44,7 @@
import android.util.Range
import android.util.Size
import android.view.WindowManager
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.Camera2Config
import androidx.camera.camera2.impl.Camera2ImplConfig
import androidx.camera.camera2.internal.SupportedSurfaceCombination.FeatureSettings
@@ -526,7 +529,8 @@
@Test
fun checkConcurrentSurfaceCombinationSupportedInConcurrentCameraMode() {
shadowOf(context.packageManager).setSystemFeature(
- FEATURE_CAMERA_CONCURRENT, true)
+ FEATURE_CAMERA_CONCURRENT, true
+ )
setupCameraAndInitCameraX(
hardwareLevel = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
)
@@ -546,7 +550,8 @@
@Test
fun checkConcurrentSurfaceCombinationSubListSupportedInConcurrentCameraMode() {
shadowOf(context.packageManager).setSystemFeature(
- FEATURE_CAMERA_CONCURRENT, true)
+ FEATURE_CAMERA_CONCURRENT, true
+ )
setupCameraAndInitCameraX(
hardwareLevel = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
)
@@ -554,8 +559,11 @@
context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
)
GuaranteedConfigurationsUtil.getConcurrentSupportedCombinationList().also {
- assertThat(isAllSubConfigListSupported(
- CameraMode.CONCURRENT_CAMERA, supportedSurfaceCombination, it)).isTrue()
+ assertThat(
+ isAllSubConfigListSupported(
+ CameraMode.CONCURRENT_CAMERA, supportedSurfaceCombination, it
+ )
+ ).isTrue()
}
}
@@ -600,8 +608,11 @@
context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
)
GuaranteedConfigurationsUtil.getUltraHighResolutionSupportedCombinationList().also {
- assertThat(isAllSubConfigListSupported(
- CameraMode.ULTRA_HIGH_RESOLUTION_CAMERA, supportedSurfaceCombination, it)).isTrue()
+ assertThat(
+ isAllSubConfigListSupported(
+ CameraMode.ULTRA_HIGH_RESOLUTION_CAMERA, supportedSurfaceCombination, it
+ )
+ ).isTrue()
}
}
@@ -2749,7 +2760,8 @@
@Test
fun generateCorrectSurfaceDefinition() {
shadowOf(context.packageManager).setSystemFeature(
- FEATURE_CAMERA_CONCURRENT, true)
+ FEATURE_CAMERA_CONCURRENT, true
+ )
setupCameraAndInitCameraX()
val supportedSurfaceCombination = SupportedSurfaceCombination(
context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
@@ -2790,7 +2802,8 @@
@Test
fun correctS720pSize_withSmallerOutputSizes() {
shadowOf(context.packageManager).setSystemFeature(
- FEATURE_CAMERA_CONCURRENT, true)
+ FEATURE_CAMERA_CONCURRENT, true
+ )
setupCameraAndInitCameraX(
supportedSizes = arrayOf(RESOLUTION_VGA)
)
@@ -2810,7 +2823,8 @@
@Test
fun correctS1440pSize_withSmallerOutputSizes() {
shadowOf(context.packageManager).setSystemFeature(
- FEATURE_CAMERA_CONCURRENT, true)
+ FEATURE_CAMERA_CONCURRENT, true
+ )
setupCameraAndInitCameraX(
supportedSizes = arrayOf(RESOLUTION_VGA)
)
@@ -3083,6 +3097,107 @@
).isFalse()
}
+ @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+ @Test
+ fun populateStreamUseCaseStreamSpecOptionWithSupportedSurfaceConfigs_differentMaxSize() {
+ val useCase1 =
+ createUseCase(CaptureType.PREVIEW) // VIDEO
+ val useCaseExpectedResultMap = mutableMapOf<UseCase, Size>().apply {
+ put(useCase1, MAXIMUM_SIZE)
+ }
+ val resultPair = getSuggestedSpecsAndVerify(
+ useCaseExpectedResultMap, hardwareLevel = INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
+ )
+ // In this case, the stream use case path and limited path would produce two different max
+ // sizes, resulting in the stream use case path being dropped.
+ assertThat(
+ resultPair.first[useCase1.currentConfig]!!.implementationOptions!!.containsOption(
+ StreamUseCaseUtil.STREAM_USE_CASE_STREAM_SPEC_OPTION
+ )
+ ).isFalse()
+ }
+
+ @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+ @Test
+ fun populateStreamUseCaseStreamSpecOptionWithSupportedSurfaceConfigs_success() {
+ val useCase1 =
+ createUseCase(CaptureType.VIDEO_CAPTURE) // VIDEO
+ val useCase2 =
+ createUseCase(CaptureType.PREVIEW) // PREVIEW
+ val useCaseExpectedResultMap = mutableMapOf<UseCase, Size>().apply {
+ put(useCase1, RECORD_SIZE)
+ put(useCase2, PREVIEW_SIZE)
+ }
+ val resultPair = getSuggestedSpecsAndVerify(
+ useCaseExpectedResultMap,
+ hardwareLevel = INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
+ )
+ assertThat(
+ resultPair.first[useCase1.currentConfig]!!.implementationOptions!!.retrieveOption(
+ StreamUseCaseUtil.STREAM_USE_CASE_STREAM_SPEC_OPTION
+ )
+ ).isEqualTo(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD)
+ assertThat(
+ resultPair.first[useCase2.currentConfig]!!.implementationOptions!!.retrieveOption(
+ StreamUseCaseUtil.STREAM_USE_CASE_STREAM_SPEC_OPTION
+ )
+ ).isEqualTo(CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW)
+ }
+
+ @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+ @Test
+ fun populateStreamUseCaseStreamSpecOptionWithSupportedSurfaceConfigs_wrongImageFormat() {
+ val useCase1 =
+ createUseCase(CaptureType.VIDEO_CAPTURE) // VIDEO
+ val useCase2 =
+ createUseCase(CaptureType.PREVIEW, imageFormat = ImageFormat.JPEG) // PREVIEW
+ val useCaseExpectedResultMap = mutableMapOf<UseCase, Size>().apply {
+ put(useCase1, RECORD_SIZE)
+ put(useCase2, RECORD_SIZE)
+ }
+ val resultPair = getSuggestedSpecsAndVerify(
+ useCaseExpectedResultMap,
+ hardwareLevel = INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
+ )
+ assertThat(
+ resultPair.first[useCase1.currentConfig]!!.implementationOptions!!.containsOption(
+ StreamUseCaseUtil.STREAM_USE_CASE_STREAM_SPEC_OPTION
+ )
+ ).isFalse()
+ assertThat(
+ resultPair.first[useCase1.currentConfig]!!.implementationOptions!!.containsOption(
+ StreamUseCaseUtil.STREAM_USE_CASE_STREAM_SPEC_OPTION
+ )
+ ).isFalse()
+ }
+
+ @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+ @Test
+ fun populateStreamUseCaseStreamSpecOptionWithSupportedSurfaceConfigs_wrongCaptureType() {
+ val useCase1 =
+ createUseCase(CaptureType.PREVIEW) // PREVIEW
+ val useCase2 =
+ createUseCase(CaptureType.PREVIEW) // PREVIEW
+ val useCaseExpectedResultMap = mutableMapOf<UseCase, Size>().apply {
+ put(useCase1, RECORD_SIZE)
+ put(useCase2, PREVIEW_SIZE)
+ }
+ val resultPair = getSuggestedSpecsAndVerify(
+ useCaseExpectedResultMap,
+ hardwareLevel = INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
+ )
+ assertThat(
+ resultPair.first[useCase1.currentConfig]!!.implementationOptions!!.containsOption(
+ StreamUseCaseUtil.STREAM_USE_CASE_STREAM_SPEC_OPTION
+ )
+ ).isFalse()
+ assertThat(
+ resultPair.first[useCase1.currentConfig]!!.implementationOptions!!.containsOption(
+ StreamUseCaseUtil.STREAM_USE_CASE_STREAM_SPEC_OPTION
+ )
+ ).isFalse()
+ }
+
/**
* Sets up camera according to the specified settings and initialize [CameraX].
*
@@ -3205,58 +3320,76 @@
// setup to return different minimum frame durations depending on resolution
// minimum frame durations were designated only for the purpose of testing
- Mockito.`when`(map.getOutputMinFrameDuration(
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.eq(Size(4032, 3024))
- ))
+ Mockito.`when`(
+ map.getOutputMinFrameDuration(
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.eq(Size(4032, 3024))
+ )
+ )
.thenReturn(50000000L) // 20 fps, size maximum
- Mockito.`when`(map.getOutputMinFrameDuration(
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.eq(Size(3840, 2160))
- ))
+ Mockito.`when`(
+ map.getOutputMinFrameDuration(
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.eq(Size(3840, 2160))
+ )
+ )
.thenReturn(40000000L) // 25, size record
- Mockito.`when`(map.getOutputMinFrameDuration(
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.eq(Size(1920, 1440))
- ))
+ Mockito.`when`(
+ map.getOutputMinFrameDuration(
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.eq(Size(1920, 1440))
+ )
+ )
.thenReturn(33333333L) // 30
- Mockito.`when`(map.getOutputMinFrameDuration(
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.eq(Size(1920, 1080))
- ))
+ Mockito.`when`(
+ map.getOutputMinFrameDuration(
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.eq(Size(1920, 1080))
+ )
+ )
.thenReturn(28571428L) // 35
- Mockito.`when`(map.getOutputMinFrameDuration(
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.eq(Size(1280, 960))
- ))
+ Mockito.`when`(
+ map.getOutputMinFrameDuration(
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.eq(Size(1280, 960))
+ )
+ )
.thenReturn(25000000L) // 40
- Mockito.`when`(map.getOutputMinFrameDuration(
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.eq(Size(1280, 720))
- ))
+ Mockito.`when`(
+ map.getOutputMinFrameDuration(
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.eq(Size(1280, 720))
+ )
+ )
.thenReturn(22222222L) // 45, size preview/display
- Mockito.`when`(map.getOutputMinFrameDuration(
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.eq(Size(960, 544))
- ))
+ Mockito.`when`(
+ map.getOutputMinFrameDuration(
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.eq(Size(960, 544))
+ )
+ )
.thenReturn(20000000L) // 50
- Mockito.`when`(map.getOutputMinFrameDuration(
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.eq(Size(800, 450))
- ))
+ Mockito.`when`(
+ map.getOutputMinFrameDuration(
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.eq(Size(800, 450))
+ )
+ )
.thenReturn(16666666L) // 60fps
- Mockito.`when`(map.getOutputMinFrameDuration(
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.eq(Size(640, 480))
- ))
+ Mockito.`when`(
+ map.getOutputMinFrameDuration(
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.eq(Size(640, 480))
+ )
+ )
.thenReturn(16666666L) // 60fps
// Sets up the supported high resolution sizes
@@ -3268,7 +3401,8 @@
val maximumResolutionMap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
(maximumResolutionSupportedSizes != null ||
- maximumResolutionHighResolutionSupportedSizes != null)) {
+ maximumResolutionHighResolutionSupportedSizes != null)
+ ) {
Mockito.mock(StreamConfigurationMap::class.java).also {
Mockito.`when`(it.getOutputSizes(ArgumentMatchers.anyInt()))
.thenReturn(maximumResolutionSupportedSizes)
@@ -3289,7 +3423,8 @@
Range(30, 40),
Range(30, 60),
Range(50, 60),
- Range(60, 60))
+ Range(60, 60)
+ )
val characteristics = ShadowCameraCharacteristics.newCameraCharacteristics()
Shadow.extract<ShadowCameraCharacteristics>(characteristics).apply {
@@ -3413,15 +3548,18 @@
captureType: CaptureType,
targetFrameRate: Range<Int>? = null,
dynamicRange: DynamicRange = DynamicRange.UNSPECIFIED,
- streamUseCaseOverride: Boolean
+ streamUseCaseOverride: Boolean = false,
+ imageFormat: Int? = null
): UseCase {
val builder = FakeUseCaseConfig.Builder(
- captureType, when (captureType) {
- CaptureType.PREVIEW -> ImageFormat.PRIVATE
- CaptureType.IMAGE_CAPTURE -> ImageFormat.JPEG
- CaptureType.IMAGE_ANALYSIS -> ImageFormat.YUV_420_888
- else -> INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
- }
+ captureType, imageFormat
+ ?: when (captureType) {
+ CaptureType.PREVIEW -> ImageFormat.PRIVATE
+ CaptureType.IMAGE_CAPTURE -> ImageFormat.JPEG
+ CaptureType.IMAGE_ANALYSIS -> ImageFormat.YUV_420_888
+ CaptureType.VIDEO_CAPTURE -> ImageFormat.PRIVATE
+ else -> INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
+ }
)
targetFrameRate?.let {
builder.mutableConfig.insertOption(UseCaseConfig.OPTION_TARGET_FRAME_RATE, it)
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/ZslControlImplTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/ZslControlImplTest.kt
index d0c7f7d..4d7a80c 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/ZslControlImplTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/ZslControlImplTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.camera2.internal
import android.graphics.ImageFormat.JPEG
@@ -24,6 +26,7 @@
import android.hardware.camera2.params.StreamConfigurationMap
import android.os.Build
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.internal.ZslControlImpl.MAX_IMAGES
import androidx.camera.camera2.internal.ZslControlImpl.RING_BUFFER_CAPACITY
import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat
@@ -299,4 +302,4 @@
CAMERA_ID_0
)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/quirk/DeviceQuirks.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/quirk/DeviceQuirks.java
index fdc538c..dc80833 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/quirk/DeviceQuirks.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/quirk/DeviceQuirks.java
@@ -18,6 +18,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.camera.core.impl.Quirk;
import java.util.List;
@@ -45,6 +46,7 @@
* @return A device {@link Quirk} instance of the provided type, or {@code null} if it isn't
* found.
*/
+ @RequiresApi(21)
@SuppressWarnings("unchecked")
@Nullable
public static <T extends Quirk> T get(@NonNull final Class<T> quirkClass) {
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerTest.java
index 74fd98c..26cc0fd 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerTest.java
@@ -143,8 +143,8 @@
// Checks the combination is supported by the list retrieved from the
// ExtraSupportedSurfaceCombinationsContainer.
for (SurfaceCombination extraSurfaceCombination : extraSurfaceCombinations) {
- if (extraSurfaceCombination.isSupported(
- expectedSupportedSurfaceCombination.getSurfaceConfigList())) {
+ if (extraSurfaceCombination.getOrderedSupportedSurfaceConfigList(
+ expectedSupportedSurfaceCombination.getSurfaceConfigList()) != null) {
isSupported = true;
break;
}
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/FlashAvailabilityCheckerTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/FlashAvailabilityCheckerTest.kt
index d0e4ac1..c96a13c 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/FlashAvailabilityCheckerTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/FlashAvailabilityCheckerTest.kt
@@ -18,6 +18,7 @@
import android.hardware.camera2.CameraCharacteristics
import android.os.Build
+import androidx.annotation.RequiresApi
import com.google.common.truth.Truth.assertThat
import java.nio.BufferUnderflowException
import org.junit.Assert.assertThrows
@@ -26,14 +27,15 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.ParameterizedRobolectricTestRunner
+import org.robolectric.annotation.Config
import org.robolectric.annotation.internal.DoNotInstrument
import org.robolectric.util.ReflectionHelpers
private const val FAKE_OEM = "fake_oem"
-// @Config() is left out since there currently aren't any API level dependencies in this workaround
@RunWith(ParameterizedRobolectricTestRunner::class)
@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
class FlashAvailabilityCheckerTest(
private val manufacturer: String,
private val model: String,
@@ -80,6 +82,7 @@
}
}
+@RequiresApi(21)
private class FlashAvailabilityTrueProvider : CameraCharacteristicsProvider {
@Suppress("UNCHECKED_CAST")
override fun <T : Any?> get(key: CameraCharacteristics.Key<T>): T? = when (key) {
@@ -88,11 +91,13 @@
}
}
+@RequiresApi(21)
private class BufferUnderflowProvider : CameraCharacteristicsProvider {
override fun <T : Any?> get(key: CameraCharacteristics.Key<T>): T =
throw BufferUnderflowException()
}
+@RequiresApi(21)
private class FlashAvailabilityNullProvider : CameraCharacteristicsProvider {
override fun <T : Any?> get(key: CameraCharacteristics.Key<T>): T? = null
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/MaxPreviewSizeTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/MaxPreviewSizeTest.kt
index e7452c0..2d5c6d0 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/MaxPreviewSizeTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/MaxPreviewSizeTest.kt
@@ -14,10 +14,13 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.camera2.internal.compat.workaround
import android.os.Build
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.internal.compat.quirk.ExtraCroppingQuirk
import androidx.camera.core.impl.SurfaceConfig
import com.google.common.truth.Truth.assertThat
@@ -89,4 +92,4 @@
maxPreviewSize.getMaxPreviewResolution(SELECT_RESOLUTION_JPEG)
assertThat(result).isEqualTo(SELECT_RESOLUTION_JPEG)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrectorTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrectorTest.kt
index 471f557..f802c7d3 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrectorTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrectorTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.camera2.internal.compat.workaround
import android.graphics.ImageFormat
@@ -21,6 +23,7 @@
import android.hardware.camera2.CameraCharacteristics
import android.os.Build
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.core.impl.ImageFormatConstants
import com.google.common.truth.Truth.assertThat
import org.junit.Test
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/ResolutionCorrectorTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/ResolutionCorrectorTest.kt
index 98426d4..2c11efe 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/ResolutionCorrectorTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/ResolutionCorrectorTest.kt
@@ -14,10 +14,13 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.camera2.internal.compat.workaround
import android.os.Build
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.camera2.internal.compat.quirk.ExtraCroppingQuirk
import androidx.camera.core.impl.SurfaceConfig
import com.google.common.truth.Truth
@@ -128,4 +131,4 @@
private fun getEmptyQuirk(): ExtraCroppingQuirk? {
return Mockito.mock(ExtraCroppingQuirk::class.java)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/interop/Camera2InteropTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/interop/Camera2InteropTest.java
index e500f5c..addab95 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/interop/Camera2InteropTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/interop/Camera2InteropTest.java
@@ -32,7 +32,6 @@
import androidx.camera.camera2.internal.CameraDeviceStateCallbacks;
import androidx.camera.core.impl.Config;
import androidx.camera.testing.fakes.FakeConfig;
-import androidx.test.filters.SdkSuppress;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -67,7 +66,7 @@
.isEqualTo(CameraDevice.TEMPLATE_PREVIEW);
}
- @SdkSuppress(minSdkVersion = 33)
+ @org.robolectric.annotation.Config(minSdk = 33)
@Test
public void canExtendWithTStreamUseCase() {
FakeConfig.Builder builder = new FakeConfig.Builder();
@@ -188,6 +187,7 @@
});
}
+ @org.robolectric.annotation.Config(minSdk = 28)
@Test
public void canExtendWithPhysicalCameraId() {
FakeConfig.Builder builder = new FakeConfig.Builder();
diff --git a/camera/camera-core/api/current.txt b/camera/camera-core/api/current.txt
index bf6443f..5cda9c6 100644
--- a/camera/camera-core/api/current.txt
+++ b/camera/camera-core/api/current.txt
@@ -169,6 +169,30 @@
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;
+ }
+
@RequiresApi(21) @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalGetImage {
}
@@ -229,7 +253,6 @@
method public boolean isOutputImageRotationEnabled();
method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
method public void setTargetRotation(int);
- method @Deprecated public void setTargetRotationDegrees(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
@@ -269,7 +292,6 @@
method public void setCropAspectRatio(android.util.Rational);
method public void setFlashMode(int);
method public void setTargetRotation(int);
- method @Deprecated public void setTargetRotationDegrees(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
@@ -463,6 +485,7 @@
@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!>);
diff --git a/camera/camera-core/api/restricted_current.txt b/camera/camera-core/api/restricted_current.txt
index bf6443f..5cda9c6 100644
--- a/camera/camera-core/api/restricted_current.txt
+++ b/camera/camera-core/api/restricted_current.txt
@@ -169,6 +169,30 @@
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;
+ }
+
@RequiresApi(21) @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalGetImage {
}
@@ -229,7 +253,6 @@
method public boolean isOutputImageRotationEnabled();
method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
method public void setTargetRotation(int);
- method @Deprecated public void setTargetRotationDegrees(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
@@ -269,7 +292,6 @@
method public void setCropAspectRatio(android.util.Rational);
method public void setFlashMode(int);
method public void setTargetRotation(int);
- method @Deprecated public void setTargetRotationDegrees(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
@@ -463,6 +485,7 @@
@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!>);
diff --git a/camera/camera-core/build.gradle b/camera/camera-core/build.gradle
index 90360e1..0dfd5e0 100644
--- a/camera/camera-core/build.gradle
+++ b/camera/camera-core/build.gradle
@@ -110,6 +110,10 @@
namespace "androidx.camera.core"
}
+tasks.withType(Test).configureEach { test ->
+ test.maxParallelForks(2)
+}
+
androidx {
name = "Camera Core"
publish = Publish.SNAPSHOT_AND_RELEASE
diff --git a/camera/camera-core/lint-baseline.xml b/camera/camera-core/lint-baseline.xml
index c9366ef..a52b3a9 100644
--- a/camera/camera-core/lint-baseline.xml
+++ b/camera/camera-core/lint-baseline.xml
@@ -1,14 +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">
-
- <issue
- id="UnsafeOptInUsageError"
- message="This declaration is opt-in and its usage should be marked with
'@androidx.camera.core.ExperimentalZeroShutterLag' or '@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)'"
- errorLine1=" if (Build.VERSION.SDK_INT >= 23 && getCaptureMode() == CAPTURE_MODE_ZERO_SHUTTER_LAG) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/core/ImageCapture.java"/>
- </issue>
+<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">
<issue
id="UnsafeOptInUsageError"
diff --git a/camera/camera-core/lint.xml b/camera/camera-core/lint.xml
deleted file mode 100644
index 0843ecf..0000000
--- a/camera/camera-core/lint.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
- <!-- Disable NewApi lint check temporarily for unit tests.
- This file can be removed once b/200599470 is resolved. -->
- <issue id="NewApi">
- <ignore path="src/test/**" />
- </issue>
-</lint>
\ No newline at end of file
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageProcessingUtilTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageProcessingUtilTest.java
index 0b79e79..fa264d4 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageProcessingUtilTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageProcessingUtilTest.java
@@ -134,6 +134,7 @@
public void tearDown() {
mRGBImageReaderProxy.safeClose();
mRotatedRGBImageReaderProxy.safeClose();
+ mJpegImageReaderProxy.safeClose();
}
@Test
@@ -154,6 +155,7 @@
assertThat(bitmap.getWidth()).isEqualTo(WIDTH);
assertThat(bitmap.getHeight()).isEqualTo(HEIGHT);
assertBitmapColor(bitmap, Color.RED, JPEG_ENCODE_ERROR_TOLERANCE);
+ imageProxy.close();
}
@Test
@@ -176,6 +178,7 @@
assertThat(bitmap.getWidth()).isEqualTo(WIDTH);
assertThat(bitmap.getHeight()).isEqualTo(HEIGHT);
assertBitmapColor(bitmap, Color.RED, JPEG_ENCODE_ERROR_TOLERANCE);
+ imageProxy.close();
}
@Test
@@ -209,6 +212,7 @@
assertThat(bitmap.getHeight()).isEqualTo(HEIGHT);
Exif exif = Exif.createFromImageProxy(imageProxy);
assertThat(exif.getRotation()).isEqualTo(expectedRotation);
+ imageProxy.close();
}
/**
@@ -247,6 +251,7 @@
// Assert.
assertThat(rgbImageProxy.getFormat()).isEqualTo(PixelFormat.RGBA_8888);
assertThat(rgbImageProxy.getPlanes().length).isEqualTo(1);
+ rgbImageProxy.close();
}
@Test
@@ -271,6 +276,7 @@
// Assert.
assertThat(rgbImageProxy.getFormat()).isEqualTo(PixelFormat.RGBA_8888);
assertThat(rgbImageProxy.getPlanes().length).isEqualTo(1);
+ rgbImageProxy.close();
}
@Test
@@ -295,6 +301,7 @@
// Assert.
assertThat(rgbImageProxy.getFormat()).isEqualTo(PixelFormat.RGBA_8888);
assertThat(rgbImageProxy.getPlanes().length).isEqualTo(1);
+ rgbImageProxy.close();
}
@Test
@@ -376,6 +383,7 @@
assertThat(rgbImageProxy.getPlanes().length).isEqualTo(1);
assertThat(rgbImageProxy.getWidth()).isEqualTo(HEIGHT);
assertThat(rgbImageProxy.getHeight()).isEqualTo(WIDTH);
+ rgbImageProxy.close();
}
@SdkSuppress(minSdkVersion = 23)
@@ -408,6 +416,7 @@
assertThat(yuvImageProxy.getPlanes().length).isEqualTo(3);
assertThat(yuvImageProxy.getWidth()).isEqualTo(HEIGHT);
assertThat(yuvImageProxy.getHeight()).isEqualTo(WIDTH);
+ yuvImageProxy.close();
}
@Test
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/utils/ImageUtilDeviceTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/utils/ImageUtilDeviceTest.kt
index 0738973..3627d63 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/utils/ImageUtilDeviceTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/utils/ImageUtilDeviceTest.kt
@@ -16,6 +16,7 @@
package androidx.camera.core.internal.utils
+import android.graphics.Bitmap
import android.graphics.ImageFormat
import android.graphics.Matrix
import android.graphics.PixelFormat
@@ -27,12 +28,15 @@
import androidx.camera.core.impl.TagBundle
import androidx.camera.testing.TestImageUtil
import androidx.camera.testing.fakes.FakeImageProxy
+import androidx.camera.testing.fakes.FakeJpegPlaneProxy
import androidx.camera.testing.fakes.FakePlaneProxy
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import androidx.testutils.assertThrows
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer
import org.junit.Test
import org.junit.runner.RunWith
@@ -174,15 +178,46 @@
assertThat(bitmap.byteCount).isEqualTo(76800)
}
- @Test(expected = java.lang.IllegalArgumentException::class)
+ @Test
+ fun createBitmapFromImageProxy_jpeg() {
+ val jpegBytes = TestImageUtil.createJpegBytes(WIDTH, HEIGHT)
+ val fakeJpegImageProxy = TestImageUtil.createJpegFakeImageProxy(jpegBytes)
+
+ val bitmap = ImageUtil.createBitmapFromImageProxy(fakeJpegImageProxy)
+
+ assertThat(bitmap.width).isEqualTo(WIDTH)
+ assertThat(bitmap.height).isEqualTo(HEIGHT)
+ assertThat(bitmap.byteCount).isEqualTo(76800)
+
+ val stream = ByteArrayOutputStream()
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream)
+ val byteArray = stream.toByteArray()
+ assertThat(TestImageUtil.getAverageDiff(jpegBytes, byteArray)).isEqualTo(0)
+ }
+
+ @Test
+ fun createBitmapFromImageProxy_invalidJpegByteArray() {
+ val jpegBytes = TestImageUtil.createJpegBytes(WIDTH, HEIGHT)
+ val fakeJpegImageProxy = TestImageUtil.createJpegFakeImageProxy(jpegBytes)
+
+ fakeJpegImageProxy.planes = arrayOf(FakeJpegPlaneProxy(byteArrayOf(0)))
+
+ assertThrows<UnsupportedOperationException> {
+ ImageUtil.createBitmapFromImageProxy(fakeJpegImageProxy)
+ }
+ }
+
+ @Test
fun createBitmapFromImageProxy_invalidFormat() {
val image = FakeImageProxy(ImmutableImageInfo.create(
TagBundle.emptyBundle(), 0, 0, Matrix()
))
- image.format = ImageFormat.JPEG
+ image.format = ImageFormat.PRIVATE
image.width = WIDTH
image.height = HEIGHT
- ImageUtil.createBitmapFromImageProxy(image)
+ assertThrows<IllegalArgumentException> {
+ ImageUtil.createBitmapFromImageProxy(image)
+ }
}
}
\ No newline at end of file
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
index daa23c4..b1020d6 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
@@ -24,6 +24,7 @@
import android.util.Size
import android.view.Surface
import androidx.camera.core.CameraEffect
+import androidx.camera.core.DynamicRange
import androidx.camera.core.ImageProxy
import androidx.camera.core.ImageReaderProxys
import androidx.camera.core.SurfaceRequest
@@ -332,7 +333,7 @@
fun createByInvalidShaderString_throwException() {
val shaderProvider = createCustomShaderProvider(shaderString = "Invalid shader")
assertThrows(IllegalArgumentException::class.java) {
- createSurfaceProcessor(shaderProvider)
+ createSurfaceProcessor(shaderProvider = shaderProvider)
}
}
@@ -341,7 +342,7 @@
val shaderProvider =
createCustomShaderProvider(exceptionToThrow = RuntimeException("Failed Shader"))
assertThrows(IllegalArgumentException::class.java) {
- createSurfaceProcessor(shaderProvider)
+ createSurfaceProcessor(shaderProvider = shaderProvider)
}
}
@@ -349,7 +350,7 @@
fun createByIncorrectSamplerName_throwException() {
val shaderProvider = createCustomShaderProvider(samplerVarName = "_mySampler_")
assertThrows(IllegalArgumentException::class.java) {
- createSurfaceProcessor(shaderProvider)
+ createSurfaceProcessor(shaderProvider = shaderProvider)
}
}
@@ -357,7 +358,7 @@
fun createByIncorrectFragCoordsName_throwException() {
val shaderProvider = createCustomShaderProvider(fragCoordsVarName = "_myFragCoords_")
assertThrows(IllegalArgumentException::class.java) {
- createSurfaceProcessor(shaderProvider)
+ createSurfaceProcessor(shaderProvider = shaderProvider)
}
}
@@ -365,7 +366,7 @@
outputType: OutputType,
shaderProvider: ShaderProvider = ShaderProvider.DEFAULT
) {
- createSurfaceProcessor(shaderProvider)
+ createSurfaceProcessor(shaderProvider = shaderProvider)
// Prepare input
val inputSurfaceRequest = createInputSurfaceRequest()
surfaceProcessor.onInputSurface(inputSurfaceRequest)
@@ -396,8 +397,12 @@
)
}
- private fun createSurfaceProcessor(shaderProvider: ShaderProvider = ShaderProvider.DEFAULT) {
+ private fun createSurfaceProcessor(
+ dynamicRange: DynamicRange = DynamicRange.SDR,
+ shaderProvider: ShaderProvider = ShaderProvider.DEFAULT
+ ) {
surfaceProcessor = DefaultSurfaceProcessor(
+ dynamicRange,
shaderProvider
)
}
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/OpenGlRendererTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/OpenGlRendererTest.kt
index 0d7695d..d1c03c8 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/OpenGlRendererTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/OpenGlRendererTest.kt
@@ -18,6 +18,7 @@
import android.graphics.SurfaceTexture
import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.params.OutputConfiguration
import android.opengl.Matrix
import android.os.Build
import android.os.Handler
@@ -26,6 +27,11 @@
import android.util.Size
import android.view.Surface
import androidx.annotation.RequiresApi
+import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat
+import androidx.camera.camera2.internal.compat.params.DynamicRangeConversions
+import androidx.camera.camera2.internal.compat.params.DynamicRangesCompat
+import androidx.camera.core.CameraSelector.LENS_FACING_BACK
+import androidx.camera.core.DynamicRange
import androidx.camera.core.impl.utils.executor.CameraXExecutors
import androidx.camera.testing.CameraUtil
import androidx.camera.testing.TestImageUtil.createBitmap
@@ -46,6 +52,7 @@
import kotlinx.coroutines.withTimeoutOrNull
import org.junit.After
import org.junit.Assert.fail
+import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Rule
@@ -100,8 +107,11 @@
private lateinit var glHandler: Handler
private lateinit var glDispatcher: CoroutineDispatcher
private lateinit var glRenderer: OpenGlRenderer
+ private lateinit var cameraId: String
+ private lateinit var cameraCharacteristicsCompat: CameraCharacteristicsCompat
private lateinit var cameraDeviceHolder: CameraUtil.CameraDeviceHolder
private lateinit var renderOutput: RenderOutput<*>
+ private var lensFacing = LENS_FACING_BACK
private val surfacesToRelease = mutableListOf<Surface>()
private val surfaceTexturesToRelease = mutableListOf<SurfaceTexture>()
@@ -258,7 +268,7 @@
val shaderProvider = createCustomShaderProvider(shaderString = "Invalid shader")
assertThrows(IllegalArgumentException::class.java) {
runBlocking(glDispatcher) {
- createOpenGlRendererAndInit(shaderProvider)
+ createOpenGlRendererAndInit(shaderProvider = shaderProvider)
}
}
}
@@ -269,7 +279,7 @@
createCustomShaderProvider(exceptionToThrow = RuntimeException("Failed Shader"))
assertThrows(IllegalArgumentException::class.java) {
runBlocking(glDispatcher) {
- createOpenGlRendererAndInit(shaderProvider)
+ createOpenGlRendererAndInit(shaderProvider = shaderProvider)
}
}
}
@@ -279,7 +289,7 @@
val shaderProvider = createCustomShaderProvider(samplerVarName = "_mySampler_")
assertThrows(IllegalArgumentException::class.java) {
runBlocking(glDispatcher) {
- createOpenGlRendererAndInit(shaderProvider)
+ createOpenGlRendererAndInit(shaderProvider = shaderProvider)
}
}
}
@@ -289,7 +299,7 @@
val shaderProvider = createCustomShaderProvider(fragCoordsVarName = "_myFragCoords_")
assertThrows(IllegalArgumentException::class.java) {
runBlocking(glDispatcher) {
- createOpenGlRendererAndInit(shaderProvider)
+ createOpenGlRendererAndInit(shaderProvider = shaderProvider)
}
}
}
@@ -298,7 +308,7 @@
fun reInit(): Unit = runBlocking(glDispatcher) {
createOpenGlRendererAndInit()
glRenderer.release()
- glRenderer.init(ShaderProvider.DEFAULT)
+ glRenderer.init(DynamicRange.SDR, ShaderProvider.DEFAULT)
assertThat(glRenderer.textureName).isNotEqualTo(0L)
}
@@ -314,16 +324,22 @@
testRender(OutputType.SURFACE_TEXTURE)
}
+ @SdkSuppress(minSdkVersion = 33) // HDR is supported from API 33.
+ @Test
+ fun renderByHlg(): Unit = runBlocking(glDispatcher) {
+ testRender(OutputType.SURFACE_TEXTURE, dynamicRange = DynamicRange.HLG_10_BIT)
+ }
+
@SdkSuppress(minSdkVersion = 23)
@Test
fun renderByCustomShader(): Unit = runBlocking(glDispatcher) {
- testRender(OutputType.IMAGE_READER, createCustomShaderProvider())
+ testRender(OutputType.IMAGE_READER, shaderProvider = createCustomShaderProvider())
}
@SdkSuppress(minSdkVersion = 21, maxSdkVersion = 22)
@Test
fun renderByCustomShaderBelowApi23(): Unit = runBlocking(glDispatcher) {
- testRender(OutputType.SURFACE_TEXTURE, createCustomShaderProvider())
+ testRender(OutputType.SURFACE_TEXTURE, shaderProvider = createCustomShaderProvider())
}
@Test
@@ -343,17 +359,20 @@
private suspend fun testRender(
outputType: OutputType,
+ dynamicRange: DynamicRange = DynamicRange.SDR,
shaderProvider: ShaderProvider = ShaderProvider.DEFAULT
) {
// Arrange.
- createOpenGlRendererAndInit(shaderProvider = shaderProvider)
+ prepareCamera()
+ assumeDynamicRange(dynamicRange)
+ createOpenGlRendererAndInit(dynamicRange = dynamicRange, shaderProvider = shaderProvider)
// Prepare input
val surfaceTexture = SurfaceTexture(glRenderer.textureName).apply {
setDefaultBufferSize(WIDTH, HEIGHT)
}
val inputSurface = Surface(surfaceTexture)
- openCameraAndSetRepeating(inputSurface)
+ openCameraAndSetRepeating(inputSurface, dynamicRange)
cameraDeviceHolder.closedFuture.addListener({
inputSurface.release()
surfaceTexture.release()
@@ -375,16 +394,17 @@
}
private suspend fun createOpenGlRendererAndInit(
+ dynamicRange: DynamicRange = DynamicRange.SDR,
shaderProvider: ShaderProvider = ShaderProvider.DEFAULT
) {
createOpenGlRenderer()
if (currentCoroutineContext()[ContinuationInterceptor] == glDispatcher) {
// same dispatcher, init directly
- glRenderer.init(shaderProvider)
+ glRenderer.init(dynamicRange, shaderProvider)
} else {
runBlocking(glDispatcher) {
- glRenderer.init(shaderProvider)
+ glRenderer.init(dynamicRange, shaderProvider)
}
}
}
@@ -425,9 +445,51 @@
return surface
}
- private fun openCameraAndSetRepeating(surface: Surface) {
- cameraDeviceHolder = CameraUtil.getCameraDevice(null)
- val captureSessionHolder = cameraDeviceHolder.createCaptureSession(listOf(surface))
+ private fun prepareCamera() {
+ assumeTrue(CameraUtil.hasCameraWithLensFacing(lensFacing))
+ cameraId = CameraUtil.getCameraIdWithLensFacing(lensFacing)!!
+ val cameraCharacteristics = CameraUtil.getCameraCharacteristics(lensFacing)!!
+ cameraCharacteristicsCompat = CameraCharacteristicsCompat.toCameraCharacteristicsCompat(
+ cameraCharacteristics,
+ cameraId
+ )
+ }
+
+ private fun assumeDynamicRange(dynamicRange: DynamicRange) {
+ if (dynamicRange == DynamicRange.SDR) {
+ // SDR is always supported.
+ return
+ }
+ val supportedDynamicRange =
+ DynamicRangesCompat.fromCameraCharacteristics(cameraCharacteristicsCompat)
+ .supportedDynamicRanges
+ assumeTrue(
+ "$dynamicRange is not in supported set $supportedDynamicRange",
+ supportedDynamicRange.contains(dynamicRange)
+ )
+ }
+
+ private fun openCameraAndSetRepeating(surface: Surface, dynamicRange: DynamicRange) {
+ // Open camera
+ cameraDeviceHolder = CameraUtil.getCameraDevice(cameraId, null)
+
+ // Create capture session
+ val captureSessionHolder = if (dynamicRange == DynamicRange.SDR) {
+ cameraDeviceHolder.createCaptureSession(listOf(surface))
+ } else {
+ if (Build.VERSION.SDK_INT >= 33) {
+ val outputConfiguration = OutputConfiguration(surface).apply {
+ dynamicRangeProfile = dynamicRange.toDynamicRangeProfile()
+ }
+ cameraDeviceHolder.createCaptureSessionByOutputConfigurations(
+ listOf(outputConfiguration)
+ )
+ } else {
+ throw AssertionError("HDR is supported from API 33")
+ }
+ }
+
+ // Set repeating
captureSessionHolder.startRepeating(
CameraDevice.TEMPLATE_PREVIEW,
listOf(surface),
@@ -435,4 +497,15 @@
null
)
}
+
+ @RequiresApi(33)
+ private fun DynamicRange.toDynamicRangeProfile(): Long {
+ val dynamicRangeProfiles =
+ DynamicRangesCompat.fromCameraCharacteristics(cameraCharacteristicsCompat)
+ .toDynamicRangeProfiles()!!
+ return DynamicRangeConversions.dynamicRangeToFirstSupportedProfile(
+ this,
+ dynamicRangeProfiles
+ )!!
+ }
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/DynamicRange.java b/camera/camera-core/src/main/java/androidx/camera/core/DynamicRange.java
index 535d0f9..4934072 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/DynamicRange.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/DynamicRange.java
@@ -47,7 +47,6 @@
* @see androidx.camera.video.VideoCapture.Builder#setDynamicRange(DynamicRange)
*/
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public final class DynamicRange {
/**
* An unspecified dynamic range encoding which allows the device to determine the underlying
@@ -265,6 +264,18 @@
&& getBitDepth() != BIT_DEPTH_UNSPECIFIED;
}
+ /**
+ * Returns true if this dynamic range is fully specified, the encoding is one of the HDR
+ * encodings and bit depth is 10-bit.
+ *
+ * @see #isFullySpecified()
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public boolean is10BitHdr() {
+ return isFullySpecified() && getEncoding() != ENCODING_SDR
+ && getBitDepth() == BIT_DEPTH_10_BIT;
+ }
+
@NonNull
@Override
public String toString() {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
index 8c70299..9663b78 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
@@ -43,7 +43,6 @@
import static androidx.camera.core.impl.UseCaseConfig.OPTION_TARGET_NAME;
import static androidx.camera.core.impl.UseCaseConfig.OPTION_USE_CASE_EVENT_CALLBACK;
import static androidx.camera.core.impl.UseCaseConfig.OPTION_ZSL_DISABLED;
-import static androidx.camera.core.impl.utils.TransformUtils.within360;
import static androidx.camera.core.internal.ThreadConfig.OPTION_BACKGROUND_EXECUTOR;
import android.graphics.ImageFormat;
@@ -507,78 +506,6 @@
}
}
- // TODO(b/277999375): Remove API setTargetRotationDegrees.
- /**
- * Sets the target rotation in degrees.
- *
- * <p>In general, it is best to use an {@link android.view.OrientationEventListener} to set
- * the target rotation. This way, the rotation output will indicate which way is down for a
- * given image. This is important since display orientation may be locked by device default,
- * user setting, or app configuration, and some devices may not transition to a
- * reverse-portrait display orientation. In these cases, use
- * {@code setTargetRotationDegrees()} to set target rotation dynamically according
- * to the {@link android.view.OrientationEventListener}, without re-creating the use case.
- * The sample code is as below:
- * <pre>{@code
- * public class CameraXActivity extends AppCompatActivity {
- *
- * private OrientationEventListener mOrientationEventListener;
- *
- * @Override
- * protected void onStart() {
- * super.onStart();
- * if (mOrientationEventListener == null) {
- * mOrientationEventListener = new OrientationEventListener(this) {
- * @Override
- * public void onOrientationChanged(int orientation) {
- * if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
- * return;
- * }
- * mImageAnalysis.setTargetRotationDegrees(orientation);
- * }
- * };
- * }
- * mOrientationEventListener.enable();
- * }
- *
- * @Override
- * protected void onStop() {
- * super.onStop();
- * mOrientationEventListener.disable();
- * }
- * }
- * }</pre>
- *
- * <p>{@code setTargetRotationDegrees()} cannot rotate the camera image to an arbitrary angle,
- * instead it maps the angle to one of {@link Surface#ROTATION_0},
- * {@link Surface#ROTATION_90}, {@link Surface#ROTATION_180} and {@link Surface#ROTATION_270}
- * as the input of {@link #setTargetRotation(int)}. The rule is as follows:
- * <p>If the input degrees is not in the range [0..359], it will be converted to the equivalent
- * degrees in the range [0..359]. And then take the following mapping based on the input
- * degrees.
- * <p>degrees >= 315 || degrees < 45 -> {@link Surface#ROTATION_0}
- * <p>degrees >= 225 && degrees < 315 -> {@link Surface#ROTATION_90}
- * <p>degrees >= 135 && degrees < 225 -> {@link Surface#ROTATION_180}
- * <p>degrees >= 45 && degrees < 135 -> {@link Surface#ROTATION_270}
- * <p>The rotation value can be obtained by {@link #getTargetRotation()}. This means the
- * rotation previously set by {@link #setTargetRotation(int)} will be overridden by
- * {@code setTargetRotationDegrees(int)}, and vice versa.
- *
- * <p>When this function is called, value set by
- * {@link ImageAnalysis.Builder#setTargetResolution(Size)} will be updated automatically to
- * make sure the suitable resolution can be selected when the use case is bound.
- *
- * @param degrees Desired rotation degree of the output image.
- * @see #setTargetRotation(int)
- * @see #getTargetRotation()
- * @deprecated Use {@link UseCase#snapToSurfaceRotation(int)} and
- * {@link #setTargetRotation(int)} to convert and set the rotation.
- */
- @Deprecated // TODO(b/277999375): Remove API setTargetRotationDegrees.
- public void setTargetRotationDegrees(int degrees) {
- setTargetRotation(snapToSurfaceRotation(within360(degrees)));
- }
-
/**
* Sets an analyzer to receive and analyze images.
*
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index ef78ae5..d5f554e 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -48,7 +48,6 @@
import static androidx.camera.core.impl.UseCaseConfig.OPTION_ZSL_DISABLED;
import static androidx.camera.core.impl.utils.Threads.checkMainThread;
import static androidx.camera.core.impl.utils.TransformUtils.is90or270;
-import static androidx.camera.core.impl.utils.TransformUtils.within360;
import static androidx.camera.core.internal.utils.ImageUtil.computeCropRectFromAspectRatio;
import static androidx.camera.core.internal.utils.ImageUtil.isAspectRatioValid;
import static androidx.core.util.Preconditions.checkNotNull;
@@ -610,82 +609,6 @@
}
/**
- * Sets the desired rotation of the output image in degrees.
- *
- * <p>In general, it is best to use an {@link android.view.OrientationEventListener} to set
- * the target rotation. This way, the rotation output will indicate which way is down for a
- * given image. This is important since display orientation may be locked by device default,
- * user setting, or app configuration, and some devices may not transition to a
- * reverse-portrait display orientation. In these cases, use
- * {@code setTargetRotationDegrees()} to set target rotation dynamically according
- * to the {@link android.view.OrientationEventListener}, without re-creating the use case.
- * The sample code is as below:
- * <pre>{@code
- * public class CameraXActivity extends AppCompatActivity {
- *
- * private OrientationEventListener mOrientationEventListener;
- *
- * @Override
- * protected void onStart() {
- * super.onStart();
- * if (mOrientationEventListener == null) {
- * mOrientationEventListener = new OrientationEventListener(this) {
- * @Override
- * public void onOrientationChanged(int orientation) {
- * if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
- * return;
- * }
- * mImageCapture.setTargetRotationDegrees(orientation);
- * }
- * };
- * }
- * mOrientationEventListener.enable();
- * }
- *
- * @Override
- * protected void onStop() {
- * super.onStop();
- * mOrientationEventListener.disable();
- * }
- * }
- * }</pre>
- *
- * <p>{@code setTargetRotationDegrees()} cannot rotate the camera image to an arbitrary angle,
- * instead it maps the angle to one of {@link Surface#ROTATION_0},
- * {@link Surface#ROTATION_90}, {@link Surface#ROTATION_180} and {@link Surface#ROTATION_270}
- * as the input of {@link #setTargetRotation(int)}. The rule is as follows:
- * <p>If the input degrees is not in the range [0..359], it will be converted to the equivalent
- * degrees in the range [0..359]. And then take the following mapping based on the input
- * degrees.
- * <p>degrees >= 315 || degrees < 45 -> {@link Surface#ROTATION_0}
- * <p>degrees >= 225 && degrees < 315 -> {@link Surface#ROTATION_90}
- * <p>degrees >= 135 && degrees < 225 -> {@link Surface#ROTATION_180}
- * <p>degrees >= 45 && degrees < 135 -> {@link Surface#ROTATION_270}
- * <p>The rotation value can be obtained by {@link #getTargetRotation()}. This means the
- * rotation previously set by {@link #setTargetRotation(int)} will be overridden by
- * {@code setTargetRotationDegrees(int)}, and vice versa.
- *
- * <p>When this function is called, value set by
- * {@link ImageCapture.Builder#setTargetResolution(Size)} will be updated automatically to make
- * sure the suitable resolution can be selected when the use case is bound. Value set by
- * {@link ImageCapture#setCropAspectRatio(Rational)} will also be updated automatically to
- * make sure the output image is cropped into expected aspect ratio.
- *
- * <p>takePicture uses the target rotation at the time it begins executing (which may be delayed
- * waiting on a previous takePicture call to complete).
- *
- * @param degrees Desired rotation degree of the output image.
- * @see #setTargetRotation(int)
- * @see #getTargetRotation()
- * @deprecated Use {@link UseCase#snapToSurfaceRotation(int)} and
- * {@link #setTargetRotation(int)} to convert and set the rotation.
- */
- @Deprecated // TODO(b/277999375): Remove API setTargetRotationDegrees.
- public void setTargetRotationDegrees(int degrees) {
- setTargetRotation(snapToSurfaceRotation(within360(degrees)));
- }
-
- /**
* Returns the set capture mode.
*
* <p>This is set when constructing an ImageCapture using
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageProxy.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageProxy.java
index 3bea291..beab036 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageProxy.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageProxy.java
@@ -142,9 +142,9 @@
/**
* Converts {@link ImageProxy} to {@link Bitmap}.
*
- * <p>The supported {@link ImageProxy} format is {@link ImageFormat#YUV_420_888} or
- * {@link PixelFormat#RGBA_8888}. If format is invalid, an {@link IllegalArgumentException}
- * will be thrown. If the conversion to bimap failed, an
+ * <p>The supported {@link ImageProxy} format is {@link ImageFormat#YUV_420_888},
+ * {@link ImageFormat#JPEG} or {@link PixelFormat#RGBA_8888}. If format is invalid, an
+ * {@link IllegalArgumentException} will be thrown. If the conversion to bimap failed, an
* {@link UnsupportedOperationException} will be thrown.
*
* @return {@link Bitmap} instance.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
index e593232..6368731 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
@@ -180,7 +180,7 @@
// [UseCase attached dynamic] - Can change but is only available when the UseCase is attached.
////////////////////////////////////////////////////////////////////////////////////////////
- @SuppressWarnings("WeakerAccess") /* synthetic accessor */
+ @SuppressWarnings("WeakerAccess") // Synthetic accessor
SessionConfig.Builder mSessionConfigBuilder;
// TODO(b/259308680): remove mSessionDeferrableSurface and rely on mCameraEdge to get the
@@ -195,11 +195,6 @@
@Nullable
SurfaceRequest mCurrentSurfaceRequest;
- // The attached surface size. Same as getAttachedSurfaceResolution() but is available during
- // createPipeline().
- @Nullable
- private Size mSurfaceSize;
-
@Nullable
private SurfaceProcessorNode mNode;
@@ -214,45 +209,6 @@
super(config);
}
- @MainThread
- @SuppressWarnings("WeakerAccess") /* synthetic accessor */
- SessionConfig.Builder createPipeline(@NonNull String cameraId, @NonNull PreviewConfig config,
- @NonNull StreamSpec streamSpec) {
- // Build pipeline with node if processor is set. Eventually we will move all the code to
- // createPipelineWithNode.
- if (getEffect() != null) {
- return createPipelineWithNode(cameraId, config, streamSpec);
- }
-
- checkMainThread();
- SessionConfig.Builder sessionConfigBuilder = SessionConfig.Builder.createFrom(config,
- streamSpec.getResolution());
-
- // Close previous session's deferrable surface before creating new one
- clearPipeline();
-
- final SurfaceRequest surfaceRequest = new SurfaceRequest(
- streamSpec.getResolution(),
- getCamera(),
- streamSpec.getDynamicRange(),
- streamSpec.getExpectedFrameRateRange(),
- this::notifyReset);
- mCurrentSurfaceRequest = surfaceRequest;
-
- if (mSurfaceProvider != null) {
- // Only send surface request if the provider is set.
- sendSurfaceRequest();
- }
-
- mSessionDeferrableSurface = surfaceRequest.getDeferrableSurface();
- addCameraSurfaceAndErrorListener(sessionConfigBuilder, cameraId, config, streamSpec);
- sessionConfigBuilder.setExpectedFrameRateRange(streamSpec.getExpectedFrameRateRange());
- if (streamSpec.getImplementationOptions() != null) {
- sessionConfigBuilder.addImplementationOptions(streamSpec.getImplementationOptions());
- }
- return sessionConfigBuilder;
- }
-
/**
* Creates the post-processing pipeline with the {@link Node} pattern.
*
@@ -261,19 +217,16 @@
*/
@NonNull
@MainThread
- private SessionConfig.Builder createPipelineWithNode(
+ private SessionConfig.Builder createPipeline(
@NonNull String cameraId,
@NonNull PreviewConfig config,
@NonNull StreamSpec streamSpec) {
// Check arguments
checkMainThread();
- CameraEffect effect = requireNonNull(getEffect());
- CameraInternal camera = requireNonNull(getCamera());
+ CameraInternal camera = requireNonNull(getCamera());
clearPipeline();
- // Create nodes and edges.
- mNode = new SurfaceProcessorNode(camera, effect.createSurfaceProcessorInternal());
// Make sure the previously created camera edge is cleared before creating a new one.
checkState(mCameraEdge == null);
mCameraEdge = new SurfaceEdge(
@@ -284,18 +237,28 @@
camera.getHasTransform(),
requireNonNull(getCropRect(streamSpec.getResolution())),
getRelativeRotation(camera, isMirroringRequired(camera)),
+ getAppTargetRotation(),
shouldMirror(camera));
- mCameraEdge.addOnInvalidatedListener(this::notifyReset);
- SurfaceProcessorNode.OutConfig outConfig = SurfaceProcessorNode.OutConfig.of(mCameraEdge);
- SurfaceProcessorNode.In nodeInput = SurfaceProcessorNode.In.of(mCameraEdge,
- singletonList(outConfig));
- SurfaceProcessorNode.Out nodeOutput = mNode.transform(nodeInput);
- SurfaceEdge appEdge = requireNonNull(nodeOutput.get(outConfig));
- appEdge.addOnInvalidatedListener(() -> onAppEdgeInvalidated(appEdge, camera));
+ CameraEffect effect = getEffect();
+ if (effect != null) {
+ // Create nodes and edges.
+ mNode = new SurfaceProcessorNode(camera, effect.createSurfaceProcessorInternal());
+ mCameraEdge.addOnInvalidatedListener(this::notifyReset);
+ SurfaceProcessorNode.OutConfig outConfig = SurfaceProcessorNode.OutConfig.of(
+ mCameraEdge);
+ SurfaceProcessorNode.In nodeInput = SurfaceProcessorNode.In.of(mCameraEdge,
+ singletonList(outConfig));
+ SurfaceProcessorNode.Out nodeOutput = mNode.transform(nodeInput);
+ SurfaceEdge appEdge = requireNonNull(nodeOutput.get(outConfig));
+ appEdge.addOnInvalidatedListener(() -> onAppEdgeInvalidated(appEdge, camera));
+ mCurrentSurfaceRequest = appEdge.createSurfaceRequest(camera);
+ } else {
+ mCameraEdge.addOnInvalidatedListener(this::notifyReset);
+ mCurrentSurfaceRequest = mCameraEdge.createSurfaceRequest(camera);
+ }
// Send the app Surface to the app.
mSessionDeferrableSurface = mCameraEdge.getDeferrableSurface();
- mCurrentSurfaceRequest = appEdge.createSurfaceRequest(camera);
if (mSurfaceProvider != null) {
// Only send surface request if the provider is set.
sendSurfaceRequest();
@@ -427,21 +390,11 @@
// TODO(b/159659392): only send transformation after CameraCaptureCallback
// .onCaptureCompleted is called.
CameraInternal cameraInternal = getCamera();
- SurfaceProvider surfaceProvider = mSurfaceProvider;
- Rect cropRect = getCropRect(mSurfaceSize);
- SurfaceRequest surfaceRequest = mCurrentSurfaceRequest;
- if (cameraInternal != null && surfaceProvider != null && cropRect != null
- && surfaceRequest != null) {
- if (mNode == null) {
- surfaceRequest.updateTransformationInfo(SurfaceRequest.TransformationInfo.of(
- cropRect,
- getRelativeRotation(cameraInternal, isMirroringRequired(cameraInternal)),
- getAppTargetRotation(),
- cameraInternal.getHasTransform()));
- } else {
- mCameraEdge.setRotationDegrees(
- getRelativeRotation(cameraInternal, isMirroringRequired(cameraInternal)));
- }
+ SurfaceEdge cameraEdge = mCameraEdge;
+ if (cameraInternal != null && cameraEdge != null) {
+ cameraEdge.updateTransformation(
+ getRelativeRotation(cameraInternal, isMirroringRequired(cameraInternal)),
+ getAppTargetRotation());
}
}
@@ -645,7 +598,6 @@
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
protected StreamSpec onSuggestedStreamSpecUpdated(@NonNull StreamSpec suggestedStreamSpec) {
- mSurfaceSize = suggestedStreamSpec.getResolution();
updateConfigAndOutput(getCameraId(), (PreviewConfig) getCurrentConfig(),
suggestedStreamSpec);
return suggestedStreamSpec;
@@ -665,7 +617,6 @@
/**
* {@inheritDoc}
- *
*/
@Override
@RestrictTo(Scope.LIBRARY)
@@ -707,7 +658,7 @@
* <p>This is just the frame rate range requested by the user, and may not necessarily be
* equal to the range the camera is actually operating at.
*
- * @return the target frame rate range of this Preview.
+ * @return the target frame rate range of this Preview.
*/
@NonNull
public Range<Integer> getTargetFrameRate() {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java
index b68ceca..70cc414 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java
@@ -338,7 +338,6 @@
* {@link android.graphics.ImageFormat#PRIVATE} or
* {@link android.graphics.ImageFormat#YCBCR_P010}.
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
public DynamicRange getDynamicRange() {
return mDynamicRange;
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/AttachedSurfaceInfo.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/AttachedSurfaceInfo.java
index 8fe27de..3f4b1cd 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/AttachedSurfaceInfo.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/AttachedSurfaceInfo.java
@@ -55,6 +55,23 @@
dynamicRange, captureTypes, implementationOptions, targetFrameRate);
}
+ /**
+ * Obtains the StreamSpec from the given AttachedSurfaceInfo with the given
+ * implementationOptions.
+ */
+ @NonNull
+ public StreamSpec toStreamSpec(
+ @NonNull Config implementationOptions) {
+ StreamSpec.Builder streamSpecBuilder =
+ StreamSpec.builder(getSize())
+ .setDynamicRange(getDynamicRange())
+ .setImplementationOptions(implementationOptions);
+ if (getTargetFrameRate() != null) {
+ streamSpecBuilder.setExpectedFrameRateRange(getTargetFrameRate());
+ }
+ return streamSpecBuilder.build();
+ }
+
/** Returns the SurfaceConfig. */
@NonNull
public abstract SurfaceConfig getSurfaceConfig();
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/SurfaceCombination.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/SurfaceCombination.java
index 43ada23..8109249 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/SurfaceCombination.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/SurfaceCombination.java
@@ -17,9 +17,11 @@
package androidx.camera.core.impl;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -79,16 +81,21 @@
/**
* Check whether the input surface configuration list is under the capability of the combination
- * of this object.
+ * of this object. If so, return the supporting combination ordered such that the
+ * SurfaceConfig at each position of the returned list is the one that supports the
+ * SurfaceConfig at the same position of the input list.
*
* @param configList the surface configuration list to be compared
- * @return the check result that whether it could be supported
+ * @return the ordered surface configuration list or {@code null} if the configuration list
+ * is not supported by this combination.
*/
- public boolean isSupported(@NonNull List<SurfaceConfig> configList) {
+ @Nullable
+ public List<SurfaceConfig> getOrderedSupportedSurfaceConfigList(
+ @NonNull List<SurfaceConfig> configList) {
boolean isSupported = false;
if (configList.isEmpty()) {
- return true;
+ return new ArrayList<>();
}
/**
@@ -98,10 +105,11 @@
* MAXIMUM) + (RAW, MAXIMUM).
*/
if (configList.size() > mSurfaceConfigList.size()) {
- return false;
+ return null;
}
List<int[]> elementsArrangements = getElementsArrangements(mSurfaceConfigList.size());
+ SurfaceConfig[] surfaceConfigArray = new SurfaceConfig[configList.size()];
for (int[] elementsArrangement : elementsArrangements) {
boolean checkResult = true;
@@ -115,6 +123,9 @@
if (!checkResult) {
break;
+ } else {
+ surfaceConfigArray[elementsArrangement[index]] =
+ mSurfaceConfigList.get(index);
}
}
}
@@ -125,7 +136,7 @@
}
}
- return isSupported;
+ return isSupported ? Arrays.asList(surfaceConfigArray) : null;
}
private List<int[]> getElementsArrangements(int n) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/SurfaceConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/SurfaceConfig.java
index 1f98de1..11efbac 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/SurfaceConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/SurfaceConfig.java
@@ -40,6 +40,7 @@
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
@AutoValue
public abstract class SurfaceConfig {
+ public static final long DEFAULT_STREAM_USE_CASE_VALUE = 0;
/** Prevent subclassing */
SurfaceConfig() {
}
@@ -49,7 +50,16 @@
*/
@NonNull
public static SurfaceConfig create(@NonNull ConfigType type, @NonNull ConfigSize size) {
- return new AutoValue_SurfaceConfig(type, size);
+ return new AutoValue_SurfaceConfig(type, size, DEFAULT_STREAM_USE_CASE_VALUE);
+ }
+
+ /**
+ * Creates a new instance of SurfaceConfig with the given parameters.
+ */
+ @NonNull
+ public static SurfaceConfig create(@NonNull ConfigType type, @NonNull ConfigSize size,
+ long streamUseCase) {
+ return new AutoValue_SurfaceConfig(type, size, streamUseCase);
}
/** Returns the configuration type. */
@@ -61,6 +71,21 @@
public abstract ConfigSize getConfigSize();
/**
+ * Returns the stream use case.
+ * <p>Stream use case constants are implementation-specific constants that allow the
+ * implementation to optimize power and quality characteristics of a stream depending on how
+ * it will be used.
+ * <p> Stream use case is an int flag used to specify the purpose of the stream associated
+ * with this surface. Use cases for the camera2 implementation that are available on devices can
+ * be found in
+ * {@link android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES}
+ *
+ * <p>See {@link android.hardware.camera2.params.OutputConfiguration#setStreamUseCase}
+ * to see how Camera2 framework uses this.
+ */
+ public abstract long getStreamUseCase();
+
+ /**
* Check whether the input surface configuration has a smaller size than this object and can be
* supported
*
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfigFactory.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfigFactory.java
index 480eb29..a044bc6 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfigFactory.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfigFactory.java
@@ -51,11 +51,15 @@
* Capture type for video capture. A use case of this type is consuming a stream of frames.
*/
VIDEO_CAPTURE,
-
/**
* Capture type for stream sharing. A use case of this type is consuming a stream of frames.
*/
- STREAM_SHARING
+ STREAM_SHARING,
+ /**
+ * Capture type for metering repeating. A use case of this type is consuming a stream of
+ * frames.
+ */
+ METERING_REPEATING
}
/**
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
index 9cad93f..c198150 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
@@ -65,9 +65,10 @@
/**
* Creates {@link Bitmap} from {@link ImageProxy}.
*
- * <p> Currently only {@link ImageFormat#YUV_420_888} and {@link PixelFormat#RGBA_8888} are
- * supported. If the format is invalid, an {@link IllegalArgumentException} will be thrown.
- * If the conversion to bimap failed, an {@link UnsupportedOperationException} will be thrown.
+ * <p> Currently only {@link ImageFormat#YUV_420_888}, {@link ImageFormat#JPEG} and
+ * {@link PixelFormat#RGBA_8888} are supported. If the format is invalid, an
+ * {@link IllegalArgumentException} will be thrown. If the conversion to bimap failed, an
+ * {@link UnsupportedOperationException} will be thrown.
*
* @param imageProxy The input {@link ImageProxy} instance.
* @return {@link Bitmap} instance.
@@ -77,6 +78,8 @@
switch (imageProxy.getFormat()) {
case ImageFormat.YUV_420_888:
return ImageProcessingUtil.convertYUVToBitmap(imageProxy);
+ case ImageFormat.JPEG:
+ return createBitmapFromJpegImage(imageProxy);
case PixelFormat.RGBA_8888:
return createBitmapFromRgbaImage(imageProxy);
default:
@@ -442,6 +445,16 @@
return bitmap;
}
+ @NonNull
+ private static Bitmap createBitmapFromJpegImage(@NonNull ImageProxy imageProxy) {
+ byte[] bytes = jpegImageToJpegByteArray(imageProxy);
+ Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
+ if (bitmap == null) {
+ throw new UnsupportedOperationException("Decode jpeg byte array failed");
+ }
+ return bitmap;
+ }
+
/**
* Checks whether the image's crop rectangle is the same as the source image size.
*/
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/DefaultSurfaceProcessor.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/DefaultSurfaceProcessor.java
index 8413467..7d70186 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/processing/DefaultSurfaceProcessor.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/DefaultSurfaceProcessor.java
@@ -38,6 +38,8 @@
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
+import androidx.arch.core.util.Function;
+import androidx.camera.core.DynamicRange;
import androidx.camera.core.Logger;
import androidx.camera.core.SurfaceOutput;
import androidx.camera.core.SurfaceProcessor;
@@ -46,7 +48,6 @@
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.impl.utils.futures.Futures;
import androidx.concurrent.futures.CallbackToFutureAdapter;
-import androidx.core.util.Supplier;
import com.google.auto.value.AutoValue;
import com.google.common.util.concurrent.ListenableFuture;
@@ -97,8 +98,8 @@
private final List<PendingSnapshot> mPendingSnapshots = new ArrayList<>();
/** Constructs {@link DefaultSurfaceProcessor} with default shaders. */
- DefaultSurfaceProcessor() {
- this(ShaderProvider.DEFAULT);
+ DefaultSurfaceProcessor(@NonNull DynamicRange dynamicRange) {
+ this(dynamicRange, ShaderProvider.DEFAULT);
}
/**
@@ -107,14 +108,15 @@
* @param shaderProvider custom shader provider for OpenGL rendering.
* @throws IllegalArgumentException if the shaderProvider provides invalid shader.
*/
- DefaultSurfaceProcessor(@NonNull ShaderProvider shaderProvider) {
+ DefaultSurfaceProcessor(@NonNull DynamicRange dynamicRange,
+ @NonNull ShaderProvider shaderProvider) {
mGlThread = new HandlerThread("GL Thread");
mGlThread.start();
mGlHandler = new Handler(mGlThread.getLooper());
mGlExecutor = CameraXExecutors.newHandlerExecutor(mGlHandler);
mGlRenderer = new OpenGlRenderer();
try {
- initGlRenderer(shaderProvider);
+ initGlRenderer(dynamicRange, shaderProvider);
} catch (RuntimeException e) {
release();
throw e;
@@ -342,11 +344,12 @@
}
}
- private void initGlRenderer(@NonNull ShaderProvider shaderProvider) {
+ private void initGlRenderer(@NonNull DynamicRange dynamicRange,
+ @NonNull ShaderProvider shaderProvider) {
ListenableFuture<Void> initFuture = CallbackToFutureAdapter.getFuture(completer -> {
executeSafely(() -> {
try {
- mGlRenderer.init(shaderProvider);
+ mGlRenderer.init(dynamicRange, shaderProvider);
completer.set(null);
} catch (RuntimeException e) {
completer.setException(e);
@@ -423,21 +426,23 @@
private Factory() {
}
- private static Supplier<SurfaceProcessorInternal> sSupplier = DefaultSurfaceProcessor::new;
+ private static Function<DynamicRange, SurfaceProcessorInternal> sSupplier =
+ DefaultSurfaceProcessor::new;
/**
* Creates a new {@link DefaultSurfaceProcessor} with no-op shader.
*/
@NonNull
- public static SurfaceProcessorInternal newInstance() {
- return sSupplier.get();
+ public static SurfaceProcessorInternal newInstance(@NonNull DynamicRange dynamicRange) {
+ return sSupplier.apply(dynamicRange);
}
/**
* Overrides the {@link DefaultSurfaceProcessor} supplier for testing.
*/
@VisibleForTesting
- public static void setSupplier(@NonNull Supplier<SurfaceProcessorInternal> supplier) {
+ public static void setSupplier(
+ @NonNull Function<DynamicRange, SurfaceProcessorInternal> supplier) {
sSupplier = supplier;
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/OpenGlRenderer.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/OpenGlRenderer.java
index 05fcd6f..c04e0aa 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/processing/OpenGlRenderer.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/OpenGlRenderer.java
@@ -40,6 +40,7 @@
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
+import androidx.camera.core.DynamicRange;
import androidx.camera.core.Logger;
import androidx.camera.core.SurfaceOutput;
import androidx.core.util.Preconditions;
@@ -59,7 +60,7 @@
* OpenGLRenderer renders texture image to the output surface.
*
* <p>OpenGLRenderer's methods must run on the same thread, so called GL thread. The GL thread is
- * locked as the thread running the {@link #init(ShaderProvider)} method, otherwise an
+ * locked as the thread running the {@link #init(DynamicRange, ShaderProvider)} method, otherwise an
* {@link IllegalStateException} will be thrown when other methods are called.
*/
@WorkerThread
@@ -81,6 +82,17 @@
+ " %s = (uTexMatrix * aTextureCoord).xy;\n"
+ "}\n", VAR_TEXTURE_COORD, VAR_TEXTURE_COORD);
+ private static final String HDR_VERTEX_SHADER = String.format(Locale.US,
+ "#version 300 es\n"
+ + "in vec4 aPosition;\n"
+ + "in vec4 aTextureCoord;\n"
+ + "uniform mat4 uTexMatrix;\n"
+ + "out vec2 %s;\n"
+ + "void main() {\n"
+ + " gl_Position = aPosition;\n"
+ + " %s = (uTexMatrix * aTextureCoord).xy;\n"
+ + "}\n", VAR_TEXTURE_COORD, VAR_TEXTURE_COORD);
+
private static final String DEFAULT_FRAGMENT_SHADER = String.format(Locale.US,
"#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
@@ -90,6 +102,31 @@
+ " gl_FragColor = texture2D(%s, %s);\n"
+ "}\n", VAR_TEXTURE_COORD, VAR_TEXTURE, VAR_TEXTURE, VAR_TEXTURE_COORD);
+ private static final String HDR_FRAGMENT_SHADER = String.format(Locale.US,
+ "#version 300 es\n"
+ + "#extension GL_OES_EGL_image_external : require\n"
+ + "#extension GL_EXT_YUV_target : require\n"
+ + "precision mediump float;\n"
+ + "uniform __samplerExternal2DY2YEXT %s;\n"
+ + "in vec2 %s;\n"
+ + "out vec4 outColor;\n"
+ + "\n"
+ + "vec3 yuvToRgb(vec3 yuv) {\n"
+ + " const vec3 yuvOffset = vec3(0.0625, 0.5, 0.5);\n"
+ + " const mat3 yuvToRgbColorTransform = mat3(\n"
+ + " 1.1689f, 1.1689f, 1.1689f,\n"
+ + " 0.0000f, -0.1881f, 2.1502f,\n"
+ + " 1.6853f, -0.6530f, 0.0000f\n"
+ + " );\n"
+ + " return clamp(yuvToRgbColorTransform * (yuv - yuvOffset), 0.0, 1.0);\n"
+ + "}\n"
+ + "\n"
+ + "void main() {\n"
+ + " vec3 srcYuv = texture(%s, %s).xyz;\n"
+ + " outColor = vec4(yuvToRgb(srcYuv), 1.0);\n"
+ + "}", VAR_TEXTURE, VAR_TEXTURE_COORD, VAR_TEXTURE, VAR_TEXTURE_COORD
+ );
+
private static final float[] VERTEX_COORDS = {
-1.0f, -1.0f, // 0 bottom left
1.0f, -1.0f, // 1 bottom right
@@ -144,13 +181,20 @@
* @throws IllegalArgumentException if the ShaderProvider fails to create shader or provides
* invalid shader string.
*/
- public void init(@NonNull ShaderProvider shaderProvider) {
+ public void init(@NonNull DynamicRange dynamicRange, @NonNull ShaderProvider shaderProvider) {
checkInitializedOrThrow(false);
try {
- createEglContext();
+ if (dynamicRange.is10BitHdr()) {
+ String glExtensions = getGlExtensionsBeforeInitialized(dynamicRange);
+ if (!glExtensions.contains("GL_EXT_YUV_target")) {
+ Log.w(TAG, "Device does not support GL_EXT_YUV_target. Fallback to SDR.");
+ dynamicRange = DynamicRange.SDR;
+ }
+ }
+ createEglContext(dynamicRange);
createTempSurface();
makeCurrent(mTempSurface);
- createProgram(shaderProvider);
+ createProgram(dynamicRange, shaderProvider);
loadLocations();
createTexture();
useAndConfigureProgram();
@@ -369,6 +413,24 @@
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTextureId);
}
+ @NonNull
+ private String getGlExtensionsBeforeInitialized(
+ @NonNull DynamicRange dynamicRangeToInitialize) {
+ checkInitializedOrThrow(false);
+ try {
+ createEglContext(dynamicRangeToInitialize);
+ createTempSurface();
+ makeCurrent(mTempSurface);
+ // eglMakeCurrent() has to be called before checking GL_EXTENSIONS.
+ String glExtensions = GLES20.glGetString(GLES20.GL_EXTENSIONS);
+ return glExtensions != null ? glExtensions : "";
+ } catch (IllegalStateException e) {
+ Logger.w(TAG, "Failed to get GL extensions: " + e.getMessage(), e);
+ return "";
+ } finally {
+ releaseInternal();
+ }
+ }
private static int generateFbo() {
int[] fbos = new int[1];
@@ -396,7 +458,7 @@
checkGlErrorOrThrow("glDeleteFramebuffers");
}
- private void createEglContext() {
+ private void createEglContext(@NonNull DynamicRange dynamicRange) {
mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
if (Objects.equals(mEglDisplay, EGL14.EGL_NO_DISPLAY)) {
throw new IllegalStateException("Unable to get EGL14 display");
@@ -406,13 +468,21 @@
mEglDisplay = EGL14.EGL_NO_DISPLAY;
throw new IllegalStateException("Unable to initialize EGL14");
}
+ int rgbBits = dynamicRange.is10BitHdr() ? 10 : 8;
+ int alphaBits = dynamicRange.is10BitHdr() ? 2 : 8;
+ int renderType = dynamicRange.is10BitHdr() ? EGLExt.EGL_OPENGL_ES3_BIT_KHR
+ : EGL14.EGL_OPENGL_ES2_BIT;
+ // recordableAndroid with EGL14.EGL_TRUE causes eglError for 10BitHdr.
+ int recordableAndroid = dynamicRange.is10BitHdr() ? EGL14.EGL_FALSE : EGL14.EGL_TRUE;
int[] attribToChooseConfig = {
- EGL14.EGL_RED_SIZE, 8,
- EGL14.EGL_GREEN_SIZE, 8,
- EGL14.EGL_BLUE_SIZE, 8,
- EGL14.EGL_ALPHA_SIZE, 8,
- EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
- EGLExt.EGL_RECORDABLE_ANDROID, EGL14.EGL_TRUE,
+ EGL14.EGL_RED_SIZE, rgbBits,
+ EGL14.EGL_GREEN_SIZE, rgbBits,
+ EGL14.EGL_BLUE_SIZE, rgbBits,
+ EGL14.EGL_ALPHA_SIZE, alphaBits,
+ EGL14.EGL_DEPTH_SIZE, 0,
+ EGL14.EGL_STENCIL_SIZE, 0,
+ EGL14.EGL_RENDERABLE_TYPE, renderType,
+ EGLExt.EGL_RECORDABLE_ANDROID, recordableAndroid,
EGL14.EGL_SURFACE_TYPE, EGL14.EGL_WINDOW_BIT | EGL14.EGL_PBUFFER_BIT,
EGL14.EGL_NONE
};
@@ -424,7 +494,7 @@
}
EGLConfig config = configs[0];
int[] attribToCreateContext = {
- EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL14.EGL_CONTEXT_CLIENT_VERSION, dynamicRange.is10BitHdr() ? 3 : 2,
EGL14.EGL_NONE
};
EGLContext context = EGL14.eglCreateContext(mEglDisplay, config, EGL14.EGL_NO_CONTEXT,
@@ -453,13 +523,15 @@
}
}
- private void createProgram(@NonNull ShaderProvider shaderProvider) {
+ private void createProgram(@NonNull DynamicRange dynamicRange,
+ @NonNull ShaderProvider shaderProvider) {
int vertexShader = -1;
int fragmentShader = -1;
int program = -1;
try {
- vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, DEFAULT_VERTEX_SHADER);
- fragmentShader = loadFragmentShader(shaderProvider);
+ vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
+ dynamicRange.is10BitHdr() ? HDR_VERTEX_SHADER : DEFAULT_VERTEX_SHADER);
+ fragmentShader = loadFragmentShader(dynamicRange, shaderProvider);
program = GLES20.glCreateProgram();
checkGlErrorOrThrow("glCreateProgram");
GLES20.glAttachShader(program, vertexShader);
@@ -551,9 +623,11 @@
mExternalTextureId = texId;
}
- private int loadFragmentShader(@NonNull ShaderProvider shaderProvider) {
+ private int loadFragmentShader(@NonNull DynamicRange dynamicRange,
+ @NonNull ShaderProvider shaderProvider) {
if (shaderProvider == ShaderProvider.DEFAULT) {
- return loadShader(GLES20.GL_FRAGMENT_SHADER, DEFAULT_FRAGMENT_SHADER);
+ return loadShader(GLES20.GL_FRAGMENT_SHADER,
+ dynamicRange.is10BitHdr() ? HDR_FRAGMENT_SHADER : DEFAULT_FRAGMENT_SHADER);
} else {
// Throw IllegalArgumentException if the shader provider can not provide a valid
// fragment shader.
@@ -775,7 +849,7 @@
try {
checkEglErrorOrThrow(op);
} catch (IllegalStateException e) {
- Logger.e(TAG, e.getMessage(), e);
+ Logger.e(TAG, e.toString(), e);
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java
index 2344f84..3fbe8da 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java
@@ -30,6 +30,7 @@
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.os.Build;
import android.util.Size;
import android.view.Surface;
@@ -49,6 +50,7 @@
import androidx.camera.core.UseCase;
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.impl.DeferrableSurface;
+import androidx.camera.core.impl.ImageOutputConfig;
import androidx.camera.core.impl.SessionConfig;
import androidx.camera.core.impl.StreamSpec;
import androidx.camera.core.impl.utils.futures.Futures;
@@ -104,6 +106,11 @@
@CameraEffect.Targets
private final int mTargets;
private final StreamSpec mStreamSpec;
+
+ // Guarded by main thread.
+ @ImageOutputConfig.OptionalRotationValue
+ private int mTargetRotation;
+
// Guarded by main thread.
private int mRotationDegrees;
@@ -141,6 +148,7 @@
boolean hasCameraTransform,
@NonNull Rect cropRect,
int rotationDegrees,
+ @ImageOutputConfig.OptionalRotationValue int targetRotation,
boolean mirroring) {
mTargets = targets;
mFormat = format;
@@ -149,6 +157,7 @@
mHasCameraTransform = hasCameraTransform;
mCropRect = cropRect;
mRotationDegrees = rotationDegrees;
+ mTargetRotation = targetRotation;
mMirroring = mirroring;
mSettableSurface = new SettableSurface(streamSpec.getResolution(), mFormat);
}
@@ -461,21 +470,44 @@
}
/**
- * Sets the rotation degrees.
+ * @see #updateTransformation(int, int)
+ */
+ public void updateTransformation(int rotationDegrees) {
+ updateTransformation(rotationDegrees, ROTATION_NOT_SPECIFIED);
+ }
+
+ /**
+ * Updates the transformation info.
*
* <p>If the surface provider is created via {@link #createSurfaceRequest(CameraInternal)}, the
* returned SurfaceRequest will receive the rotation update by
* {@link SurfaceRequest.TransformationInfoListener}.
+ *
+ * @param rotationDegrees the suggested clockwise rotation degrees of the buffer.
+ * @param targetRotation the UseCase target rotation configured by the app. This value is
+ * needed if the SurfaceProvider is a TextureView without GL processing.
+ * TextureView will combine this value and the value in
+ * {@link SurfaceTexture#getTransformMatrix} to correct the output.
+ * @ TODO(b/284336967): allow setting the crop rect and propagate it to the SurfaceProcessor.
*/
- public void setRotationDegrees(int rotationDegrees) {
+ public void updateTransformation(
+ int rotationDegrees,
+ @ImageOutputConfig.OptionalRotationValue int targetRotation) {
// This method is not limited to the main thread because UseCase#setTargetRotation calls
// this method and can be called from a background thread.
runOnMain(() -> {
- if (mRotationDegrees == rotationDegrees) {
- return;
+ boolean isDirty = false;
+ if (mRotationDegrees != rotationDegrees) {
+ isDirty = true;
+ mRotationDegrees = rotationDegrees;
}
- mRotationDegrees = rotationDegrees;
- notifyTransformationInfoUpdate();
+ if (mTargetRotation != targetRotation) {
+ isDirty = true;
+ mTargetRotation = targetRotation;
+ }
+ if (isDirty) {
+ notifyTransformationInfoUpdate();
+ }
});
}
@@ -483,9 +515,8 @@
private void notifyTransformationInfoUpdate() {
checkMainThread();
if (mProviderSurfaceRequest != null) {
- mProviderSurfaceRequest.updateTransformationInfo(
- TransformationInfo.of(mCropRect, mRotationDegrees, ROTATION_NOT_SPECIFIED,
- hasCameraTransform()));
+ mProviderSurfaceRequest.updateTransformationInfo(TransformationInfo.of(
+ mCropRect, mRotationDegrees, mTargetRotation, hasCameraTransform()));
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceProcessorNode.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceProcessorNode.java
index 5f4ae6c..cf8a4d8 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceProcessorNode.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceProcessorNode.java
@@ -16,6 +16,7 @@
package androidx.camera.core.processing;
+import static androidx.camera.core.impl.ImageOutputConfig.ROTATION_NOT_SPECIFIED;
import static androidx.camera.core.impl.utils.TransformUtils.getRectToRect;
import static androidx.camera.core.impl.utils.TransformUtils.getRotatedSize;
import static androidx.camera.core.impl.utils.TransformUtils.isAspectRatioMatchingWithRoundingError;
@@ -156,6 +157,8 @@
// Crop rect is always the full size.
sizeToRect(outConfig.getSize()),
/*rotationDegrees=*/input.getRotationDegrees() - rotationDegrees,
+ // Once copied, the target rotation is no longer useful.
+ /*targetRotation*/ ROTATION_NOT_SPECIFIED,
/*mirroring=*/input.getMirroring() != mirroring);
return outputSurface;
@@ -247,7 +250,8 @@
rotationDegrees = -rotationDegrees;
}
rotationDegrees = within360(rotationDegrees);
- output.getValue().setRotationDegrees(rotationDegrees);
+ // Once copied, the target rotation is no longer useful.
+ output.getValue().updateTransformation(rotationDegrees, ROTATION_NOT_SPECIFIED);
}
});
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java
index 830387a..0fcf886 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java
@@ -29,6 +29,7 @@
import android.graphics.Rect;
import android.os.Build;
+import android.util.Log;
import android.util.Size;
import androidx.annotation.IntRange;
@@ -44,6 +45,7 @@
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.ImageFormatConstants;
+import androidx.camera.core.impl.ImageOutputConfig;
import androidx.camera.core.impl.MutableConfig;
import androidx.camera.core.impl.MutableOptionsBundle;
import androidx.camera.core.impl.OptionsBundle;
@@ -61,6 +63,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -69,8 +72,9 @@
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class StreamSharing extends UseCase {
+ private static final String TAG = "StreamSharing";
@NonNull
- private static final StreamSharingConfig DEFAULT_CONFIG;
+ private final StreamSharingConfig mDefaultConfig;
@NonNull
private final VirtualCamera mVirtualCamera;
@@ -87,18 +91,28 @@
@Nullable
private SurfaceEdge mSharingInputEdge;
- @SuppressWarnings("WeakerAccess") /* synthetic accessor */
+ @SuppressWarnings("WeakerAccess") // Synthetic access
SessionConfig.Builder mSessionConfigBuilder;
- static {
+ private static StreamSharingConfig getDefaultConfig(Set<UseCase> children) {
MutableConfig mutableConfig = new StreamSharingBuilder().getMutableConfig();
mutableConfig.insertOption(OPTION_INPUT_FORMAT,
ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE);
mutableConfig.insertOption(OPTION_CAPTURE_TYPE,
UseCaseConfigFactory.CaptureType.STREAM_SHARING);
- DEFAULT_CONFIG = new StreamSharingConfig(OptionsBundle.from(mutableConfig));
+ List<UseCaseConfigFactory.CaptureType> captureTypes = new ArrayList<>();
+ for (UseCase child : children) {
+ if (child.getCurrentConfig().containsOption(OPTION_CAPTURE_TYPE)) {
+ captureTypes.add(child.getCurrentConfig().getCaptureType());
+ } else {
+ Log.e(TAG, "A child does not have capture type.");
+ }
+ }
+ mutableConfig.insertOption(StreamSharingConfig.OPTION_CAPTURE_TYPES, captureTypes);
+ return new StreamSharingConfig(OptionsBundle.from(mutableConfig));
}
+
/**
* Constructs a {@link StreamSharing} with a parent {@link CameraInternal}, children
* {@link UseCase}s, and a {@link UseCaseConfigFactory} for getting default {@link UseCase}
@@ -107,7 +121,8 @@
public StreamSharing(@NonNull CameraInternal parentCamera,
@NonNull Set<UseCase> children,
@NonNull UseCaseConfigFactory useCaseConfigFactory) {
- super(DEFAULT_CONFIG);
+ super(getDefaultConfig(children));
+ mDefaultConfig = getDefaultConfig(children);
mVirtualCamera = new VirtualCamera(parentCamera, children, useCaseConfigFactory,
(jpegQuality, rotationDegrees) -> {
SurfaceProcessorNode sharingNode = mSharingNode;
@@ -127,11 +142,11 @@
@NonNull UseCaseConfigFactory factory) {
// The shared stream optimizes for VideoCapture.
Config captureConfig = factory.getConfig(
- DEFAULT_CONFIG.getCaptureType(),
+ mDefaultConfig.getCaptureType(),
ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY);
if (applyDefaultConfig) {
- captureConfig = Config.mergeConfigs(captureConfig, DEFAULT_CONFIG.getConfig());
+ captureConfig = Config.mergeConfigs(captureConfig, mDefaultConfig.getConfig());
}
return captureConfig == null ? null :
getUseCaseConfigBuilder(captureConfig).getUseCaseConfig();
@@ -230,11 +245,13 @@
camera.getHasTransform(),
requireNonNull(getCropRect(streamSpec.getResolution())),
/*rotationDegrees=*/0, // Rotation are handled by each child.
+ // Once copied, the target rotation will no longer be useful.
+ ImageOutputConfig.ROTATION_NOT_SPECIFIED,
/*mirroring=*/false); // Mirroring will be decided by each child.
mSharingInputEdge = getSharingInputEdge(mCameraEdge, camera);
mSharingNode = new SurfaceProcessorNode(camera,
- DefaultSurfaceProcessor.Factory.newInstance());
+ DefaultSurfaceProcessor.Factory.newInstance(streamSpec.getDynamicRange()));
// Transform the input based on virtual camera configuration.
Map<UseCase, SurfaceProcessorNode.OutConfig> outConfigMap =
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharingConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharingConfig.java
index adf1207..11a156c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharingConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharingConfig.java
@@ -25,8 +25,11 @@
import androidx.camera.core.impl.MutableConfig;
import androidx.camera.core.impl.OptionsBundle;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.internal.ThreadConfig;
+import java.util.List;
+
/**
* Configuration for a {@link StreamSharing} use case.
*
@@ -35,9 +38,12 @@
* {@link MutableConfig#insertOption} and {@link MutableConfig#retrieveOption} directly.
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
-class StreamSharingConfig implements UseCaseConfig<StreamSharing>,
+public class StreamSharingConfig implements UseCaseConfig<StreamSharing>,
ImageOutputConfig,
ThreadConfig {
+ static final Config.Option<List<UseCaseConfigFactory.CaptureType>> OPTION_CAPTURE_TYPES =
+ Config.Option.create("camerax.core.streamSharing.captureTypes",
+ List.class);
private final OptionsBundle mConfig;
@@ -51,4 +57,9 @@
public Config getConfig() {
return mConfig;
}
+
+ @NonNull
+ public List<UseCaseConfigFactory.CaptureType> getCaptureTypes() {
+ return retrieveOption(OPTION_CAPTURE_TYPES);
+ }
}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/FocusMeteringActionTest.java b/camera/camera-core/src/test/java/androidx/camera/core/FocusMeteringActionTest.java
index 1f7200f..8968622 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/FocusMeteringActionTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/FocusMeteringActionTest.java
@@ -18,9 +18,12 @@
import static com.google.common.truth.Truth.assertThat;
+import android.os.Build;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
import org.robolectric.annotation.internal.DoNotInstrument;
import java.util.Arrays;
@@ -28,6 +31,7 @@
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
public class FocusMeteringActionTest {
private SurfaceOrientedMeteringPointFactory mPointFactory =
new SurfaceOrientedMeteringPointFactory(1.0f, 1.0f);
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
index 3b09a2a..a20c1a5 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
@@ -27,6 +27,7 @@
import android.util.Rational
import android.util.Size
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.core.CameraEffect.IMAGE_CAPTURE
import androidx.camera.core.CameraEffect.PREVIEW
import androidx.camera.core.CameraEffect.VIDEO_CAPTURE
@@ -71,6 +72,7 @@
import org.robolectric.annotation.Config
import org.robolectric.annotation.internal.DoNotInstrument
+@RequiresApi(21)
private val TEST_CAMERA_SELECTOR = CameraSelector.DEFAULT_BACK_CAMERA
/**
@@ -246,6 +248,23 @@
}
@Test
+ fun setTargetRotation_rotationIsPropagated() {
+ // Arrange: create preview and wait for transformation info.
+ val preview = createPreview()
+ var transformationInfo: TransformationInfo? = null
+ preview.mCurrentSurfaceRequest!!.setTransformationInfoListener(
+ mainThreadExecutor()
+ ) { newValue: TransformationInfo -> transformationInfo = newValue }
+
+ // Act: set target rotation.
+ preview.targetRotation = Surface.ROTATION_180
+ shadowOf(getMainLooper()).idle()
+
+ // Assert: target rotation is updated.
+ assertThat(transformationInfo!!.targetRotation).isEqualTo(Surface.ROTATION_180)
+ }
+
+ // @Test TODO re-enable once b/284336967 is done.
fun attachUseCase_transformationInfoUpdates() {
// Arrange: attach Preview without a SurfaceProvider.
// Build and bind use case.
@@ -784,4 +803,4 @@
handlersToRelease.add(handler)
return handler
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeImageCaptureControl.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeImageCaptureControl.kt
index ee31c80..d0b5089 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeImageCaptureControl.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeImageCaptureControl.kt
@@ -16,6 +16,7 @@
package androidx.camera.core.imagecapture
+import androidx.annotation.RequiresApi
import androidx.camera.core.impl.CaptureConfig
import androidx.camera.core.impl.utils.futures.Futures
import androidx.concurrent.futures.CallbackToFutureAdapter
@@ -24,6 +25,7 @@
/**
* Fake [ImageCaptureControl] that records method calls.
*/
+@RequiresApi(21)
class FakeImageCaptureControl : ImageCaptureControl {
companion object {
@@ -71,4 +73,4 @@
UNLOCK_FLASH,
SUBMIT_REQUESTS
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeImagePipeline.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeImagePipeline.kt
index 1975ec9..734ef61 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeImagePipeline.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeImagePipeline.kt
@@ -18,6 +18,7 @@
import android.util.Size
import androidx.annotation.MainThread
+import androidx.annotation.RequiresApi
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.imagecapture.CaptureNode.MAX_IMAGES
import androidx.camera.core.imagecapture.Utils.createEmptyImageCaptureConfig
@@ -29,6 +30,7 @@
/**
* Fake [ImagePipeline] class for testing.
*/
+@RequiresApi(21)
class FakeImagePipeline(config: ImageCaptureConfig, cameraSurfaceSize: Size) :
ImagePipeline(config, cameraSurfaceSize) {
@@ -84,4 +86,4 @@
override fun getCapacity(): Int {
return queueCapacity
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeProcessingRequest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeProcessingRequest.kt
index ba83f5d..56d05b8 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeProcessingRequest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeProcessingRequest.kt
@@ -18,6 +18,7 @@
import android.graphics.Matrix
import android.graphics.Rect
+import androidx.annotation.RequiresApi
import androidx.camera.core.ImageCapture
import androidx.camera.core.imagecapture.Utils.CROP_RECT
import androidx.camera.core.impl.CaptureBundle
@@ -26,6 +27,7 @@
/**
* Fake [ProcessingRequest].
*/
+@RequiresApi(21)
internal class FakeProcessingRequest(
outputFileOptions: ImageCapture.OutputFileOptions?,
captureBundle: CaptureBundle,
@@ -59,4 +61,4 @@
callback,
captureFuture
)
-}
\ No newline at end of file
+}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeTakePictureRequest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeTakePictureRequest.kt
index 2ae941f..48e202c 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeTakePictureRequest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeTakePictureRequest.kt
@@ -18,6 +18,7 @@
import android.graphics.Matrix
import android.graphics.Rect
+import androidx.annotation.RequiresApi
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCapture.OnImageCapturedCallback
import androidx.camera.core.ImageCaptureException
@@ -31,6 +32,7 @@
/**
* Fake [TakePictureRequest].
*/
+@RequiresApi(21)
class FakeTakePictureRequest() : TakePictureRequest() {
var imageCapturedCallback: OnImageCapturedCallback? = null
@@ -110,4 +112,4 @@
enum class Type {
IN_MEMORY, ON_DISK
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/Utils.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/Utils.kt
index d8c5ae3..adecafa 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/Utils.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/Utils.kt
@@ -22,6 +22,7 @@
import android.os.Build
import android.util.Pair
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.core.CaptureBundles
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageInfo
@@ -42,6 +43,7 @@
/**
* Utility methods for testing image capture.
*/
+@RequiresApi(21)
object Utils {
internal const val WIDTH = 640
@@ -116,4 +118,4 @@
it.setTag(TagBundle.create(Pair(tagBundleKey, stageId)))
})
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/impl/CameraFiltersTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/impl/CameraFiltersTest.kt
index 8cfc8a7..29978fc 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/impl/CameraFiltersTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/impl/CameraFiltersTest.kt
@@ -16,6 +16,7 @@
package androidx.camera.core.impl
+import android.os.Build
import androidx.camera.core.CameraInfo
import androidx.camera.core.CameraSelector
import androidx.camera.testing.fakes.FakeCameraInfoInternal
@@ -24,6 +25,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
import org.robolectric.annotation.internal.DoNotInstrument
/**
@@ -31,6 +33,7 @@
*/
@RunWith(RobolectricTestRunner::class)
@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
class CameraFiltersTest {
private val mCameraInfos: ArrayList<CameraInfo> = arrayListOf()
@@ -54,4 +57,4 @@
val resultCameras = CameraFilters.NONE.filter(mCameraInfos)
assertThat(resultCameras).isEmpty()
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/impl/QuirksTest.java b/camera/camera-core/src/test/java/androidx/camera/core/impl/QuirksTest.java
index 8cb5c42..67b39ff 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/impl/QuirksTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/impl/QuirksTest.java
@@ -18,12 +18,15 @@
import static com.google.common.truth.Truth.assertThat;
+import androidx.test.filters.SdkSuppress;
+
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+@SdkSuppress(minSdkVersion = 21)
public class QuirksTest {
@Test
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/impl/ResolutionValidatedEncoderProfilesProviderTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/impl/ResolutionValidatedEncoderProfilesProviderTest.kt
index 198bc4c..dfcd851 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/impl/ResolutionValidatedEncoderProfilesProviderTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/impl/ResolutionValidatedEncoderProfilesProviderTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.core.impl
import android.media.CamcorderProfile.QUALITY_1080P
@@ -22,6 +24,7 @@
import android.media.CamcorderProfile.QUALITY_720P
import android.os.Build
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.core.impl.quirk.ProfileResolutionQuirk
import androidx.camera.testing.EncoderProfilesUtil.PROFILES_1080P
import androidx.camera.testing.EncoderProfilesUtil.PROFILES_2160P
@@ -122,4 +125,4 @@
return supportedResolutions.toMutableList()
}
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/impl/utils/ExifTest.java b/camera/camera-core/src/test/java/androidx/camera/core/impl/utils/ExifTest.java
index 56ab7fe..14457d6 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/impl/utils/ExifTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/impl/utils/ExifTest.java
@@ -33,7 +33,7 @@
import java.io.IOException;
import java.io.InputStream;
-import java.time.Duration;
+import java.util.concurrent.TimeUnit;
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
@@ -157,10 +157,10 @@
@Test
public void attachedTimestampUsesSystemWallTime() {
long beforeTimestamp = SystemClock.uptimeMillis();
- ShadowSystemClock.advanceBy(Duration.ofMillis(100));
+ ShadowSystemClock.advanceBy(100, TimeUnit.MILLISECONDS);
mExif.attachTimestamp();
- ShadowSystemClock.advanceBy(Duration.ofMillis(100));
+ ShadowSystemClock.advanceBy(100, TimeUnit.MILLISECONDS);
long afterTimestamp = SystemClock.uptimeMillis();
// Check that the attached timestamp is in the closed range [beforeTimestamp,
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
index 670ef68..7b08809 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
@@ -24,6 +24,7 @@
import android.util.Rational
import android.util.Size
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.core.CameraEffect
import androidx.camera.core.CameraEffect.PREVIEW
import androidx.camera.core.CameraEffect.VIDEO_CAPTURE
@@ -927,6 +928,7 @@
assertThat(video.effect).isNull()
}
+ @RequiresApi(23)
private fun createAdapterWithSupportedCameraOperations(
@RestrictedCameraControl.CameraOperation supportedOps: Set<Int>
): CameraUseCaseAdapter {
@@ -945,6 +947,7 @@
return cameraUseCaseAdapter
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun cameraControlFailed_whenNoCameraOperationsSupported(): Unit = runBlocking {
// 1. Arrange
@@ -980,6 +983,7 @@
.build()
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun zoomEnabled_whenZoomOperationsSupported(): Unit = runBlocking {
// 1. Arrange
@@ -994,6 +998,7 @@
assertThat(fakeCameraControl.linearZoom).isEqualTo(1.0f)
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun torchEnabled_whenTorchOperationSupported(): Unit = runBlocking {
// 1. Arrange
@@ -1008,6 +1013,7 @@
assertThat(fakeCameraControl.torchEnabled).isEqualTo(true)
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun focusMetering_afEnabled_whenAfOperationSupported(): Unit = runBlocking {
// 1. Arrange
@@ -1033,6 +1039,7 @@
.isEmpty()
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun focusMetering_aeEnabled_whenAeOperationsSupported(): Unit = runBlocking {
// 1. Arrange
@@ -1057,6 +1064,7 @@
.isEmpty()
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun focusMetering_awbEnabled_whenAwbOperationsSupported(): Unit = runBlocking {
// 1. Arrange
@@ -1081,6 +1089,7 @@
.isEmpty()
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun focusMetering_disabled_whenNoneIsSupported(): Unit = runBlocking {
// 1. Arrange
@@ -1099,6 +1108,7 @@
assertThat(fakeCameraControl.lastSubmittedFocusMeteringAction).isNull()
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun exposureEnabled_whenExposureOperationSupported(): Unit = runBlocking {
// 1. Arrange
@@ -1113,6 +1123,7 @@
assertThat(fakeCameraControl.exposureCompensationIndex).isEqualTo(0)
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun cameraInfo_returnsDisabledState_AllOpsDisabled(): Unit = runBlocking {
// 1. Arrange
@@ -1150,6 +1161,7 @@
.isEqualTo(0)
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun cameraInfo_zoomEnabled(): Unit = runBlocking {
// 1. Arrange
@@ -1170,6 +1182,7 @@
assertThat(zoomState.linearZoom).isEqualTo(fakeZoomState.linearZoom)
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun cameraInfo_torchEnabled(): Unit = runBlocking {
// 1. Arrange
@@ -1184,6 +1197,7 @@
.isEqualTo(fakeCameraInfo.torchState.value)
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun cameraInfo_afEnabled(): Unit = runBlocking {
// 1. Arrange
@@ -1202,6 +1216,7 @@
)).isTrue()
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun cameraInfo_exposureExposureEnabled(): Unit = runBlocking {
// 1. Arrange
@@ -1224,6 +1239,7 @@
.isEqualTo(fakeCameraInfo.exposureState.isExposureCompensationSupported)
}
+ @org.robolectric.annotation.Config(minSdk = 23)
@Test
fun cameraInfo_flashEnabled(): Unit = runBlocking {
// 1. Arrange
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterLegacyTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterLegacyTest.kt
index 9d18516..036cc6a 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterLegacyTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterLegacyTest.kt
@@ -20,6 +20,7 @@
import android.os.Build
import android.util.Size
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.core.AspectRatio
import androidx.camera.core.impl.UseCaseConfig
import androidx.camera.core.impl.UseCaseConfigFactory.CaptureType
@@ -35,6 +36,7 @@
import org.robolectric.annotation.internal.DoNotInstrument
private const val TARGET_ASPECT_RATIO_NONE = -99
+@RequiresApi(21)
private val DEFAULT_SUPPORTED_SIZES = listOf(
Size(4032, 3024), // 4:3
Size(3840, 2160), // 16:9
@@ -387,4 +389,4 @@
defaultResolution?.let { builder.setDefaultResolution(it) }
return builder.useCaseConfig
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterTest.kt
index d4346fc..3cb7587 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterTest.kt
@@ -14,12 +14,15 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.core.internal
import android.graphics.ImageFormat
import android.os.Build
import android.util.Pair
import android.util.Size
+import androidx.annotation.RequiresApi
import androidx.camera.core.AspectRatio
import androidx.camera.core.impl.UseCaseConfig
import androidx.camera.core.impl.UseCaseConfigFactory.CaptureType
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/internal/compat/quirk/DeviceQuirks.java b/camera/camera-core/src/test/java/androidx/camera/core/internal/compat/quirk/DeviceQuirks.java
index a0870ad..63fc7fc 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/internal/compat/quirk/DeviceQuirks.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/internal/compat/quirk/DeviceQuirks.java
@@ -18,6 +18,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.camera.core.impl.Quirk;
import java.util.List;
@@ -45,6 +46,7 @@
* @return A device {@link Quirk} instance of the provided type, or {@code null} if it isn't
* found.
*/
+ @RequiresApi(21)
@SuppressWarnings("unchecked")
@Nullable
public static <T extends Quirk> T get(@NonNull final Class<T> quirkClass) {
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
index 2bc0793..016de19 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
@@ -17,6 +17,7 @@
package androidx.camera.core.processing
import android.os.Build
+import androidx.camera.core.DynamicRange
import androidx.camera.core.SurfaceOutput
import androidx.camera.core.SurfaceRequest
import com.google.common.truth.Truth.assertThat
@@ -49,6 +50,7 @@
}
DefaultSurfaceProcessor.Factory.setSupplier { noOpProcessor }
// Assert: new instance returns the no-op processor.
- assertThat(DefaultSurfaceProcessor.Factory.newInstance()).isSameInstanceAs(noOpProcessor)
+ assertThat(DefaultSurfaceProcessor.Factory.newInstance(DynamicRange.SDR))
+ .isSameInstanceAs(noOpProcessor)
}
}
\ No newline at end of file
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceEdgeTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceEdgeTest.kt
index 10a60cc..96b08b3 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceEdgeTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceEdgeTest.kt
@@ -34,6 +34,7 @@
import androidx.camera.core.impl.DeferrableSurface.SurfaceClosedException
import androidx.camera.core.impl.DeferrableSurface.SurfaceUnavailableException
import androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
+import androidx.camera.core.impl.ImageOutputConfig.ROTATION_NOT_SPECIFIED
import androidx.camera.core.impl.StreamSpec
import androidx.camera.core.impl.utils.TransformUtils.sizeToRect
import androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor
@@ -77,7 +78,8 @@
fun setUp() {
surfaceEdge = SurfaceEdge(
PREVIEW, INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
- StreamSpec.builder(INPUT_SIZE).build(), Matrix(), true, Rect(), 0, false
+ StreamSpec.builder(INPUT_SIZE).build(), Matrix(), true, Rect(), 0,
+ ROTATION_NOT_SPECIFIED, false
)
fakeSurfaceTexture = SurfaceTexture(0)
fakeSurface = Surface(fakeSurfaceTexture)
@@ -145,6 +147,7 @@
true,
Rect(),
0,
+ ROTATION_NOT_SPECIFIED,
false
)
assertThat(edge.streamSpec).isEqualTo(FRAME_SPEC)
@@ -342,6 +345,7 @@
hasCameraTransform,
Rect(),
0,
+ ROTATION_NOT_SPECIFIED,
false
)
var transformationInfo: TransformationInfo? = null
@@ -515,7 +519,7 @@
}
// Act.
- surfaceEdge.rotationDegrees = 90
+ surfaceEdge.updateTransformation(90)
shadowOf(getMainLooper()).idle()
// Assert.
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceProcessorNodeTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceProcessorNodeTest.kt
index f6287b4..bd38d08 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceProcessorNodeTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceProcessorNodeTest.kt
@@ -31,6 +31,7 @@
import androidx.camera.core.SurfaceRequest
import androidx.camera.core.SurfaceRequest.TransformationInfo
import androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
+import androidx.camera.core.impl.ImageOutputConfig.ROTATION_NOT_SPECIFIED
import androidx.camera.core.impl.ImmediateSurface
import androidx.camera.core.impl.StreamSpec
import androidx.camera.core.impl.utils.TransformUtils
@@ -124,10 +125,11 @@
PREVIEW,
INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
StreamSpec.builder(INPUT_SIZE).build(),
- Matrix.IDENTITY_MATRIX,
+ Matrix(),
false,
PREVIEW_CROP_RECT,
0,
+ ROTATION_NOT_SPECIFIED,
false
)
)
@@ -153,10 +155,11 @@
PREVIEW,
INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
StreamSpec.builder(INPUT_SIZE).build(),
- Matrix.IDENTITY_MATRIX,
+ Matrix(),
true,
PREVIEW_CROP_RECT,
0,
+ ROTATION_NOT_SPECIFIED,
false
)
val outConfig = OutConfig.of(
@@ -203,10 +206,11 @@
PREVIEW,
INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
StreamSpec.builder(INPUT_SIZE).build(),
- Matrix.IDENTITY_MATRIX,
+ Matrix(),
true,
PREVIEW_CROP_RECT,
0,
+ ROTATION_NOT_SPECIFIED,
false
)
val outConfig1 = OutConfig.of(inputEdge)
@@ -343,7 +347,7 @@
shadowOf(getMainLooper()).idle()
// Act: update rotation degrees
- inputSurface.rotationDegrees = 270
+ inputSurface.updateTransformation(270)
shadowOf(getMainLooper()).idle()
// Assert: surfaceOutput of SurfaceProcessor will consume the initial rotation degrees and
@@ -362,7 +366,7 @@
assertThat(videoSurfaceOutput.mirroring).isTrue()
// Act: update rotation degrees
- inputSurface.rotationDegrees = 180
+ inputSurface.updateTransformation(180)
shadowOf(getMainLooper()).idle()
// Assert: video rotation degrees is opposite of preview because it's not mirrored.
assertThat(previewTransformInfo.rotationDegrees).isEqualTo(90)
@@ -380,7 +384,7 @@
shadowOf(getMainLooper()).idle()
// Act: update rotation degrees
- inputSurface.rotationDegrees = 270
+ inputSurface.updateTransformation(270)
shadowOf(getMainLooper()).idle()
// Assert: surfaceOutput of SurfaceProcessor will consume the initial rotation degrees and
@@ -399,7 +403,7 @@
assertThat(videoSurfaceOutput.mirroring).isTrue()
// Act: update rotation degrees
- inputSurface.rotationDegrees = 180
+ inputSurface.updateTransformation(180)
shadowOf(getMainLooper()).idle()
// Assert: video rotation is the same as preview and are compensated by mirroring.
assertThat(previewTransformInfo.rotationDegrees).isEqualTo(270)
@@ -462,6 +466,7 @@
hasCameraTransform,
previewCropRect,
inputRotationDegrees,
+ ROTATION_NOT_SPECIFIED,
mirroring,
),
) {
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt
index 82b2799..ed08929 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt
@@ -34,6 +34,7 @@
import androidx.camera.core.impl.StreamSpec
import androidx.camera.core.impl.UseCaseConfig
import androidx.camera.core.impl.UseCaseConfigFactory
+import androidx.camera.core.impl.UseCaseConfigFactory.CaptureType
import androidx.camera.core.impl.utils.executor.CameraXExecutors.directExecutor
import androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor
import androidx.camera.core.internal.TargetConfig.OPTION_TARGET_CLASS
@@ -373,4 +374,13 @@
)
).startsWith("androidx.camera.core.streamsharing.StreamSharing-")
}
+
+ @Test
+ fun getDefaultConfig_getCaptureTypes() {
+ val config: StreamSharingConfig =
+ (streamSharing.getDefaultConfig(true, useCaseConfigFactory) as StreamSharingConfig?)!!
+ assertThat(config.captureTypes.size).isEqualTo(2)
+ assertThat(config.captureTypes[0]).isEqualTo(CaptureType.PREVIEW)
+ assertThat(config.captureTypes[1]).isEqualTo(CaptureType.PREVIEW)
+ }
}
\ No newline at end of file
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraTest.kt
index e6062de..2d9af14 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraTest.kt
@@ -37,6 +37,7 @@
import androidx.camera.core.impl.CaptureConfig
import androidx.camera.core.impl.DeferrableSurface
import androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
+import androidx.camera.core.impl.ImageOutputConfig.ROTATION_NOT_SPECIFIED
import androidx.camera.core.impl.SessionConfig
import androidx.camera.core.impl.SessionConfig.defaultEmptySessionConfig
import androidx.camera.core.impl.StreamSpec
@@ -312,6 +313,7 @@
hasCameraTransform,
cropRect,
rotationDegrees,
+ ROTATION_NOT_SPECIFIED,
mirroring
).also { surfaceEdgesToClose.add(it) }
}
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
index 9875af2..2ec214e 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
@@ -375,6 +375,7 @@
* as part of this callback. Both Camera2 and CameraX guarantee
* that those two settings and results are always supported and
* applied by the corresponding framework.
+ * @since 1.3
*/
void onCaptureCompleted(long timestamp, int captureSequenceId,
@NonNull Map<CaptureResult.Key, Object> result);
diff --git a/camera/camera-extensions/build.gradle b/camera/camera-extensions/build.gradle
index 4cb5a01..26e3110 100644
--- a/camera/camera-extensions/build.gradle
+++ b/camera/camera-extensions/build.gradle
@@ -42,6 +42,7 @@
testImplementation(project(":camera:camera-extensions-stub"))
testImplementation(libs.testCore)
// To use the extensions-stub for testing directly.
+ testImplementation(libs.testRunner)
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.testRunner)
diff --git a/camera/camera-extensions/lint-baseline.xml b/camera/camera-extensions/lint-baseline.xml
index e20f0f0..2931c74 100644
--- a/camera/camera-extensions/lint-baseline.xml
+++ b/camera/camera-extensions/lint-baseline.xml
@@ -1,14 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public ListenableFuture<Void> shutdown() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/extensions/ExtensionsManager.java"/>
- </issue>
+<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">
<issue
id="BanThreadSleep"
diff --git a/camera/camera-extensions/lint.xml b/camera/camera-extensions/lint.xml
deleted file mode 100644
index 0843ecf..0000000
--- a/camera/camera-extensions/lint.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
- <!-- Disable NewApi lint check temporarily for unit tests.
- This file can be removed once b/200599470 is resolved. -->
- <issue id="NewApi">
- <ignore path="src/test/**" />
- </issue>
-</lint>
\ No newline at end of file
diff --git a/camera/camera-extensions/proguard-rules.pro b/camera/camera-extensions/proguard-rules.pro
index 898fbf8..64b007c 100644
--- a/camera/camera-extensions/proguard-rules.pro
+++ b/camera/camera-extensions/proguard-rules.pro
@@ -16,3 +16,5 @@
# Otherwise, it will cause AbstractMethodError if proguard is enabled.
-keep class androidx.camera.extensions.ExtensionsManager$** {*;}
-keep class androidx.camera.extensions.internal.sessionprocessor.AdvancedSessionProcessor$** {*;}
+-keep class androidx.camera.extensions.internal.sessionprocessor.StillCaptureProcessor** {*;}
+-keep class androidx.camera.extensions.internal.sessionprocessor.PreviewProcessor** {*;}
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsManagerTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsManagerTest.kt
index 9d75cee..f04e0706 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsManagerTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsManagerTest.kt
@@ -27,10 +27,10 @@
import androidx.camera.core.SurfaceRequest
import androidx.camera.core.impl.CameraInfoInternal
import androidx.camera.core.impl.MutableStateObservable
+import androidx.camera.extensions.internal.ClientVersion
import androidx.camera.extensions.internal.ExtensionVersion
import androidx.camera.extensions.internal.VendorExtender
import androidx.camera.extensions.internal.Version
-import androidx.camera.extensions.internal.VersionName
import androidx.camera.extensions.util.ExtensionsTestUtil
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.testing.CameraUtil
@@ -117,7 +117,7 @@
extensionsManager = ExtensionsManager.getInstanceAsync(
context,
cameraProvider,
- VersionName("99.0.0")
+ ClientVersion("99.0.0")
)[10000, TimeUnit.MILLISECONDS]
assumeTrue(
@@ -132,7 +132,7 @@
extensionsManager = ExtensionsManager.getInstanceAsync(
context,
cameraProvider,
- VersionName("99.0.0")
+ ClientVersion("99.0.0")
)[10000, TimeUnit.MILLISECONDS]
assumeTrue(
@@ -280,6 +280,11 @@
extensionsManager.extensionsAvailability
== ExtensionsManager.ExtensionsAvailability.LIBRARY_AVAILABLE
)
+ // Skips the test when the extension version is 1.1 or below. It is the case that the
+ // device has its own implementation and ExtensionsInfo will directly return null to impact
+ // the test result.
+ assumeTrue(ExtensionVersion.getRuntimeVersion()!! >= Version.VERSION_1_2)
+
val estimatedCaptureLatency = Range(100L, 1000L)
val fakeVendorExtender = object : VendorExtender {
@@ -309,7 +314,7 @@
extensionsManager = ExtensionsManager.getInstanceAsync(
context,
cameraProvider,
- VersionName("99.0.0")
+ ClientVersion("99.0.0")
)[10000, TimeUnit.MILLISECONDS]
assumeTrue(
@@ -532,7 +537,7 @@
extensionsManager = ExtensionsManager.getInstanceAsync(
context,
cameraProvider,
- VersionName("99.0.0")
+ ClientVersion("99.0.0")
)[10000, TimeUnit.MILLISECONDS]
assumeTrue(
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt
index cfa06c8..eb342e6 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt
@@ -203,6 +203,7 @@
@Test
fun canInvokeStartTrigger() = runBlocking {
+ assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_3))
val fakeSessionProcessImpl = FakeSessionProcessImpl()
val advancedSessionProcessor = AdvancedSessionProcessor(
fakeSessionProcessImpl, emptyList(), context)
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheckTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheckTest.kt
index 515d672..9398550 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheckTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheckTest.kt
@@ -16,13 +16,14 @@
package androidx.camera.extensions.internal.compat.workaround
-import android.os.SystemClock
import androidx.camera.extensions.internal.compat.workaround.OnEnableDisableSessionDurationCheck.MIN_DURATION_FOR_ENABLE_DISABLE_SESSION
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
-import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
+import kotlin.system.measureTimeMillis
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
@@ -35,29 +36,27 @@
}
@Test
- fun enabled_ensureMinimalDuration() {
+ fun enabled_ensureMinimalDuration() = runBlocking {
// Arrange
val check = OnEnableDisableSessionDurationCheck(/* enabledMinimumDuration */true)
val duration = 80L
// Act
- val startTime = SystemClock.elapsedRealtime()
check.onEnableSessionInvoked()
- Thread.sleep(duration)
- check.onDisableSessionInvoked()
- val endTime = SystemClock.elapsedRealtime()
+ val actualDuration = measureTimeMillis {
+ delay(duration)
+ }
+ val elapsedTime = measureTimeMillis {
+ check.onDisableSessionInvoked()
+ }
// Assert
- assertThat((endTime - startTime))
- .isIn(
- Range.closed(
- MIN_DURATION_FOR_ENABLE_DISABLE_SESSION,
- MIN_DURATION_FOR_ENABLE_DISABLE_SESSION + TOLERANCE
- ))
+ val min = (MIN_DURATION_FOR_ENABLE_DISABLE_SESSION - actualDuration).coerceAtLeast(0)
+ assertThat(elapsedTime).isAtLeast(min)
}
@Test
- fun enabled_doNotWaitExtraIfDurationExceeds() {
+ fun enabled_doNotWaitExtraIfDurationExceeds() = runBlocking {
// 1. Arrange
val check = OnEnableDisableSessionDurationCheck(/* enabledMinimumDuration */true)
@@ -65,18 +64,15 @@
val duration = MIN_DURATION_FOR_ENABLE_DISABLE_SESSION
// 2. Act
- val startTime = SystemClock.elapsedRealtime()
check.onEnableSessionInvoked()
// make the duration of onEnable to onDisable to be the minimal duration.
- Thread.sleep(duration)
- check.onDisableSessionInvoked()
- val endTime = SystemClock.elapsedRealtime()
+ delay(duration)
+ val elapsedTime = measureTimeMillis {
+ check.onDisableSessionInvoked()
+ }
// 3. Assert: no extra time waited.
- assertThat((endTime - startTime))
- .isLessThan(
- duration + TOLERANCE
- )
+ assertThat(elapsedTime).isLessThan(TOLERANCE)
}
@Test
@@ -85,13 +81,12 @@
val check = OnEnableDisableSessionDurationCheck(/* enabledMinimumDuration */ false)
// 2. Act
- val startTime = SystemClock.elapsedRealtime()
- check.onEnableSessionInvoked()
- check.onDisableSessionInvoked()
- val endTime = SystemClock.elapsedRealtime()
+ val elapsedTime = measureTimeMillis {
+ check.onEnableSessionInvoked()
+ check.onDisableSessionInvoked()
+ }
// 3. Assert
- assertThat((endTime - startTime))
- .isLessThan(TOLERANCE)
+ assertThat(elapsedTime).isLessThan(TOLERANCE)
}
}
\ No newline at end of file
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt
index 5a0fb78..1634996 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt
@@ -154,7 +154,7 @@
fakePreviewExtenderImpl = FakePreviewExtenderImpl(previewProcessorType)
fakeCaptureExtenderImpl = FakeImageCaptureExtenderImpl(hasCaptureProcessor)
basicExtenderSessionProcessor = BasicExtenderSessionProcessor(
- fakePreviewExtenderImpl, fakeCaptureExtenderImpl, emptyList(), context
+ fakePreviewExtenderImpl, fakeCaptureExtenderImpl, emptyList(), emptyList(), context
)
}
@@ -209,7 +209,7 @@
hasCaptureProcessor, throwErrorOnProcess = true
)
basicExtenderSessionProcessor = BasicExtenderSessionProcessor(
- fakePreviewExtenderImpl, fakeCaptureExtenderImpl, emptyList(), context
+ fakePreviewExtenderImpl, fakeCaptureExtenderImpl, emptyList(), emptyList(), context
)
val preview = Preview.Builder().build()
val imageCapture = ImageCapture.Builder().build()
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessorTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessorTest.kt
index 2ae872f..2a6bdd1 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessorTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessorTest.kt
@@ -18,7 +18,10 @@
import android.content.Context
import android.graphics.ImageFormat
+import android.graphics.PixelFormat.RGBA_8888
import android.graphics.SurfaceTexture
+import android.hardware.camera2.CameraCaptureSession
+import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CameraManager
import android.hardware.camera2.TotalCaptureResult
import android.media.Image
@@ -59,10 +62,12 @@
val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
)
-
+ private lateinit var cameraDevice: CameraDevice
+ private lateinit var cameraCaptureSession: CameraCaptureSession
private lateinit var surfaceTexture: SurfaceTexture
private lateinit var previewSurface: Surface
private lateinit var previewProcessor: PreviewProcessor
+ private lateinit var imageReaderYuv: ImageReader
private val context = ApplicationProvider.getApplicationContext<Context>()
private val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
@@ -74,11 +79,11 @@
const val CAMERA_ID = "0"
const val WIDTH = 640
const val HEIGHT = 480
- const val MAX_IMAGES = 6
+ const val MAX_IMAGES = 2
}
@Before
- fun setUp() {
+ fun setUp() = runBlocking {
Assume.assumeTrue(CameraUtil.deviceHasCamera())
backgroundThread = HandlerThread(
@@ -95,10 +100,28 @@
previewProcessor = PreviewProcessor(
fakePreviewImageProcessorImpl, previewSurface, Size(WIDTH, HEIGHT)
)
+ imageReaderYuv = ImageReader.newInstance(
+ WIDTH, HEIGHT, ImageFormat.YUV_420_888, MAX_IMAGES
+ )
+
+ cameraDevice = Camera2Util.openCameraDevice(cameraManager, CAMERA_ID, backgroundHandler)
+ cameraCaptureSession = Camera2Util.openCaptureSession(
+ cameraDevice,
+ arrayListOf(imageReaderYuv.surface),
+ backgroundHandler
+ )
}
@After
fun tearDown() {
+ if (::cameraCaptureSession.isInitialized) {
+ cameraCaptureSession.close()
+ }
+
+ if (::cameraDevice.isInitialized) {
+ cameraDevice.close()
+ }
+
if (::backgroundThread.isInitialized) {
backgroundThread.quitSafely()
}
@@ -117,34 +140,43 @@
if (::fakePreviewImageProcessorImpl.isInitialized) {
fakePreviewImageProcessorImpl.close()
}
+
+ if (::imageReaderYuv.isInitialized) {
+ imageReaderYuv.close()
+ }
}
@Test
fun canOutputToPreview(): Unit = runBlocking {
- val cameraDevice = Camera2Util.openCameraDevice(cameraManager, CAMERA_ID, backgroundHandler)
- val imageReaderYuv = ImageReader.newInstance(
- WIDTH, HEIGHT, ImageFormat.YUV_420_888, MAX_IMAGES
- )
- val session = Camera2Util.openCaptureSession(
- cameraDevice,
- arrayListOf(imageReaderYuv.surface),
- backgroundHandler
- )
+ startPreviewProcessorAndAwaitFrameUpdate()
+ }
- previewProcessor.start()
+ private suspend fun startPreviewProcessorAndAwaitFrameUpdate() {
+ previewProcessor.start { _, _ -> }
+ var imageFetched = false
+ var captureResultFetched = false
imageReaderYuv.setOnImageAvailableListener({
- val image = it.acquireNextImage()
- previewProcessor.notifyImage(createImageReference(image))
+ if (!imageFetched) {
+ imageFetched = true
+ val image = it.acquireNextImage()
+ previewProcessor.notifyImage(createImageReference(image))
+ }
}, backgroundHandler)
- Camera2Util.startRepeating(cameraDevice, session, arrayListOf(imageReaderYuv.surface)) {
- previewProcessor.notifyCaptureResult(it)
- }
+
val previewUpdateDeferred = CompletableDeferred<Boolean>()
surfaceTexture.setOnFrameAvailableListener {
previewUpdateDeferred.complete(true)
}
+ Camera2Util.startRepeating(cameraDevice, cameraCaptureSession,
+ arrayListOf(imageReaderYuv.surface)) {
+ if (!captureResultFetched) {
+ captureResultFetched = true
+ previewProcessor.notifyCaptureResult(it)
+ }
+ }
+
withTimeout(3000) {
assertTrue(previewUpdateDeferred.await())
}
@@ -152,35 +184,9 @@
@Test
fun canCloseProcessor(): Unit = runBlocking {
- val cameraDevice = Camera2Util.openCameraDevice(cameraManager, CAMERA_ID, backgroundHandler)
- val imageReaderYuv = ImageReader.newInstance(
- WIDTH, HEIGHT, ImageFormat.YUV_420_888, MAX_IMAGES
- )
- val session = Camera2Util.openCaptureSession(
- cameraDevice,
- arrayListOf(imageReaderYuv.surface),
- backgroundHandler
- )
-
- previewProcessor.start()
-
- imageReaderYuv.setOnImageAvailableListener({
- val image = it.acquireNextImage()
- previewProcessor.notifyImage(createImageReference(image))
- }, backgroundHandler)
-
- Camera2Util.startRepeating(cameraDevice, session, arrayListOf(imageReaderYuv.surface)) {
- previewProcessor.notifyCaptureResult(it)
- }
- val previewUpdateDeferred = CompletableDeferred<Boolean>()
- surfaceTexture.setOnFrameAvailableListener {
- previewUpdateDeferred.complete(true)
- }
-
- withTimeout(3000) {
- previewUpdateDeferred.await()
- }
+ startPreviewProcessorAndAwaitFrameUpdate()
previewProcessor.close()
+
// close the preview surface to see if closing causes any issues.
surfaceTexture.release()
previewSurface.release()
@@ -231,7 +237,7 @@
}
override fun onOutputSurface(surface: Surface, imageFormat: Int) {
- imageWriter = ImageWriter.newInstance(surface, 2)
+ imageWriter = ImageWriter.newInstance(surface, 2, RGBA_8888)
}
override fun onResolutionUpdate(size: Size) {
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/StillCaptureProcessorTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/StillCaptureProcessorTest.kt
index 6435358..0346ab5 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/StillCaptureProcessorTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/StillCaptureProcessorTest.kt
@@ -21,6 +21,7 @@
import android.hardware.camera2.CameraCaptureSession
import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CameraManager
+import android.hardware.camera2.CaptureResult
import android.hardware.camera2.TotalCaptureResult
import android.media.Image
import android.media.ImageReader
@@ -193,6 +194,12 @@
override fun onError(e: Exception) {
deferredCaptureCompleted.completeExceptionally(e)
}
+
+ override fun onCaptureResult(
+ shutterTimestamp: Long,
+ result: MutableList<android.util.Pair<CaptureResult.Key<Any>, Any>>
+ ) {
+ }
})
val outputJpegDeferred = CompletableDeferred<ImageProxy>()
@@ -289,6 +296,12 @@
override fun onError(e: java.lang.Exception) {
deferredCapture.completeExceptionally(e)
}
+
+ override fun onCaptureResult(
+ shutterTimestamp: Long,
+ result: MutableList<android.util.Pair<CaptureResult.Key<Any>, Any>>
+ ) {
+ }
})
val deferredOutputJpeg = CompletableDeferred<ImageProxy>()
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
index 9020456..b9608a7 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
@@ -15,6 +15,8 @@
*/
package androidx.camera.extensions;
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
import android.content.Context;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.params.StreamConfigurationMap;
@@ -24,6 +26,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.CameraProvider;
import androidx.camera.core.CameraSelector;
@@ -36,9 +39,9 @@
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.impl.utils.futures.Futures;
import androidx.camera.extensions.impl.InitializerImpl;
+import androidx.camera.extensions.internal.ClientVersion;
import androidx.camera.extensions.internal.ExtensionVersion;
import androidx.camera.extensions.internal.Version;
-import androidx.camera.extensions.internal.VersionName;
import androidx.concurrent.futures.CallbackToFutureAdapter;
import androidx.lifecycle.LifecycleOwner;
@@ -188,11 +191,41 @@
@NonNull
public static ListenableFuture<ExtensionsManager> getInstanceAsync(@NonNull Context context,
@NonNull CameraProvider cameraProvider) {
- return getInstanceAsync(context, cameraProvider, VersionName.getCurrentVersion());
+ return getInstanceAsync(context, cameraProvider, ClientVersion.getCurrentVersion());
}
+
+ /**
+ * Retrieves the {@link ExtensionsManager} associated with the current process and
+ * initializes with the given client extensions-interface version.
+ *
+ * <p>This is for testing purpose. Since CameraX uses the latest extensions-interface
+ * version, we need a way to emulate the earlier version to see if OEM implementation can be
+ * compatible. For example, CameraX uses 1.3.0 and OEM implements 1.3.0 as well. We can use
+ * this API to emulate the situation that CameraX uses 1.2.0 and invokes the older version of
+ * API.
+ *
+ * @param context The context to initialize the extensions library.
+ * @param cameraProvider A {@link CameraProvider} will be used to query the information
+ * of cameras on the device. The {@link CameraProvider} can be the
+ * {@link androidx.camera.lifecycle.ProcessCameraProvider}
+ * which is obtained by*
+ * {@link androidx.camera.lifecycle.ProcessCameraProvider#getInstance(Context)}.
+ * @param clientVersionStr the extensions-interface version used to initialize the extensions.
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ @VisibleForTesting
+ @NonNull
+ public static ListenableFuture<ExtensionsManager> getInstanceAsync(@NonNull Context context,
+ @NonNull CameraProvider cameraProvider, @NonNull String clientVersionStr) {
+ ClientVersion clientVersion = new ClientVersion(clientVersionStr);
+ ClientVersion.setCurrentVersion(clientVersion);
+ return getInstanceAsync(context, cameraProvider, clientVersion);
+ }
+
+ @NonNull
static ListenableFuture<ExtensionsManager> getInstanceAsync(@NonNull Context context,
- @NonNull CameraProvider cameraProvider, @NonNull VersionName versionName) {
+ @NonNull CameraProvider cameraProvider, @NonNull ClientVersion clientVersion) {
synchronized (EXTENSIONS_LOCK) {
if (sDeinitializeFuture != null && !sDeinitializeFuture.isDone()) {
throw new IllegalStateException("Not yet done deinitializing extensions");
@@ -216,7 +249,7 @@
if (sInitializeFuture == null) {
sInitializeFuture = CallbackToFutureAdapter.getFuture(completer -> {
try {
- InitializerImpl.init(versionName.toVersionString(),
+ InitializerImpl.init(clientVersion.toVersionString(),
ContextUtil.getApplicationContext(context),
new InitializerImpl.OnExtensionsInitializedCallback() {
@Override
@@ -272,12 +305,11 @@
* complete. Then, tests can call the
* {@link ExtensionsManager#getInstanceAsync(Context, CameraProvider)} function again to
* initialize a new {@link ExtensionsManager} instance.
- *
- * @hide
*/
// TODO: Will need to be rewritten to be threadsafe with use in conjunction with
// ExtensionsManager.init(...) if this is to be released for use outside of testing.
@VisibleForTesting
+ @RestrictTo(LIBRARY_GROUP)
@NonNull
public ListenableFuture<Void> shutdown() {
synchronized (EXTENSIONS_LOCK) {
@@ -287,6 +319,9 @@
return Futures.immediateFuture(null);
}
+ // Reset the ExtensionsVersion.
+ ExtensionVersion.injectInstance(null);
+
// If initialization not yet attempted then deinit should succeed immediately.
if (sInitializeFuture == null) {
return Futures.immediateFuture(null);
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
index d78bc97..dcb8a01 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
@@ -20,6 +20,7 @@
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Build;
import android.util.Pair;
@@ -314,25 +315,23 @@
@NonNull
private List<CaptureRequest.Key> getSupportedParameterKeys(Context context) {
- if (ExtensionVersion.getRuntimeVersion().compareTo(Version.VERSION_1_3) >= 0) {
+ if (ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)) {
try {
List<CaptureRequest.Key> keys =
- Collections.unmodifiableList(
- mAvailableKeysRetriever.getAvailableCaptureRequestKeys(
- mImageCaptureExtenderImpl,
- mCameraId,
- mCameraCharacteristics,
- context));
- if (keys == null) {
- keys = Collections.emptyList();
+ mAvailableKeysRetriever.getAvailableCaptureRequestKeys(
+ mImageCaptureExtenderImpl,
+ mCameraId,
+ mCameraCharacteristics,
+ context);
+ if (keys != null) {
+ return Collections.unmodifiableList(keys);
}
- return keys;
} catch (Exception e) {
// it could crash on some OEMs.
Logger.e(TAG, "ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys "
+ "throws exceptions", e);
- return Collections.emptyList();
}
+ return Collections.emptyList();
} else {
// For Basic Extender implementing v1.2 or below, we assume zoom/tap-to-focus/flash/EC
// are supported for compatibility reason.
@@ -340,6 +339,24 @@
}
}
+ @NonNull
+ private List<CaptureResult.Key> getSupportedCaptureResultKeys() {
+ if (ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)) {
+ try {
+ List<CaptureResult.Key> keys =
+ mImageCaptureExtenderImpl.getAvailableCaptureResultKeys();
+ if (keys != null) {
+ return Collections.unmodifiableList(keys);
+ }
+ } catch (Exception e) {
+ // it could crash on some OEMs.
+ Logger.e(TAG, "ImageCaptureExtenderImpl.getAvailableCaptureResultKeys "
+ + "throws exceptions", e);
+ }
+ }
+ return Collections.emptyList();
+ }
+
@Nullable
@Override
public SessionProcessor createSessionProcessor(@NonNull Context context) {
@@ -347,6 +364,7 @@
return new BasicExtenderSessionProcessor(
mPreviewExtenderImpl, mImageCaptureExtenderImpl,
getSupportedParameterKeys(context),
+ getSupportedCaptureResultKeys(),
context);
}
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ClientVersion.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ClientVersion.java
new file mode 100644
index 0000000..400b6f7
--- /dev/null
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ClientVersion.java
@@ -0,0 +1,81 @@
+/*
+ * 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.camera.extensions.internal;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.VisibleForTesting;
+
+/**
+ * The client version of the Extensions-Interface that CameraX extension library uses.
+ */
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+public class ClientVersion {
+ // Current version of vendor library implementation that the CameraX extension supports. This
+ // needs to be increased along with the version of vendor library interface.
+ private static ClientVersion sCurrent = new ClientVersion("1.3.0");
+
+ @NonNull
+ public static ClientVersion getCurrentVersion() {
+ return sCurrent;
+ }
+
+ /**
+ * Overrides the client version for testing.
+ */
+ @VisibleForTesting
+ public static void setCurrentVersion(@NonNull ClientVersion clientVersion) {
+ sCurrent = clientVersion;
+ }
+
+ private final Version mVersion;
+
+ @NonNull
+ public Version getVersion() {
+ return mVersion;
+ }
+
+ public ClientVersion(@NonNull String versionString) {
+ mVersion = Version.parse(versionString);
+ }
+
+ /**
+ * Check if the client version meets the minimum compatible version requirement. This implies
+ * that the client version is equal to or newer than the version.
+ *
+ * <p> The compatible version is comprised of the major and minor version numbers. The patch
+ * number is ignored.
+ *
+ * @param version The minimum compatible version required
+ * @return True if the client version meets the minimum version requirement and False
+ * otherwise.
+ */
+ public static boolean isMinimumCompatibleVersion(@NonNull Version version) {
+ return ClientVersion.getCurrentVersion().mVersion
+ .compareTo(version.getMajor(), version.getMinor()) >= 0;
+ }
+
+ /**
+ * Gets this version number as string.
+ *
+ * @return the string of the version in a form of MAJOR.MINOR.PATCH-description.
+ */
+ @NonNull
+ public String toVersionString() {
+ return mVersion.toString();
+ }
+}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ExtensionVersion.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ExtensionVersion.java
index 52af0b8..eb41e7b 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ExtensionVersion.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ExtensionVersion.java
@@ -19,11 +19,10 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
+import androidx.annotation.VisibleForTesting;
import androidx.camera.core.Logger;
import androidx.camera.extensions.impl.ExtensionVersionImpl;
-import org.jetbrains.annotations.TestOnly;
-
/**
* Provides interfaces to check the extension version.
*/
@@ -37,7 +36,7 @@
* For testing only. Inject a fake {@link ExtensionVersion}. Set it to {@code null} to unset
* it.
*/
- @TestOnly
+ @VisibleForTesting
public static void injectInstance(@Nullable ExtensionVersion extensionVersion) {
sExtensionVersion = extensionVersion;
}
@@ -137,10 +136,10 @@
}
String vendorVersion = sImpl.checkApiVersion(
- VersionName.getCurrentVersion().toVersionString());
+ ClientVersion.getCurrentVersion().toVersionString());
Version vendorVersionObj = Version.parse(vendorVersion);
if (vendorVersionObj != null
- && VersionName.getCurrentVersion().getVersion().getMajor()
+ && ClientVersion.getCurrentVersion().getVersion().getMajor()
== vendorVersionObj.getMajor()) {
mRuntimeVersion = vendorVersionObj;
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/VersionName.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/VersionName.java
deleted file mode 100644
index bb904e1..0000000
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/VersionName.java
+++ /dev/null
@@ -1,60 +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.camera.extensions.internal;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-
-/**
- * The version of CameraX extension releases.
- */
-@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-public class VersionName {
- // Current version of vendor library implementation that the CameraX extension supports. This
- // needs to be increased along with the version of vendor library interface.
- private static final VersionName CURRENT = new VersionName("1.3.0");
-
- @NonNull
- public static VersionName getCurrentVersion() {
- return CURRENT;
- }
-
- private final Version mVersion;
-
- @NonNull
- public Version getVersion() {
- return mVersion;
- }
-
- public VersionName(@NonNull String versionString) {
- mVersion = Version.parse(versionString);
- }
-
- VersionName(int major, int minor, int patch, String description) {
- mVersion = Version.create(major, minor, patch, description);
- }
-
- /**
- * Gets this version number as string.
- *
- * @return the string of the version in a form of MAJOR.MINOR.PATCH-description.
- */
- @NonNull
- public String toVersionString() {
- return mVersion.toString();
- }
-}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheck.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheck.java
index ffc0791..9fbbdb8 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheck.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheck.java
@@ -36,7 +36,7 @@
static final long MIN_DURATION_FOR_ENABLE_DISABLE_SESSION = 100L;
public OnEnableDisableSessionDurationCheck() {
- mEnabledMinimumDuration = DeviceQuirks.get(CrashWhenOnDisableTooSoon.class) != null;
+ this(DeviceQuirks.get(CrashWhenOnDisableTooSoon.class) != null);
}
@VisibleForTesting
@@ -76,7 +76,7 @@
private void ensureMinDurationAfterOnEnableSession() {
long timeAfterOnEnableSession =
SystemClock.elapsedRealtime() - mOnEnableSessionTimeStamp;
- if (timeAfterOnEnableSession < MIN_DURATION_FOR_ENABLE_DISABLE_SESSION) {
+ while (timeAfterOnEnableSession < MIN_DURATION_FOR_ENABLE_DISABLE_SESSION) {
try {
long timeToWait =
MIN_DURATION_FOR_ENABLE_DISABLE_SESSION - timeAfterOnEnableSession;
@@ -84,7 +84,9 @@
Thread.sleep(timeToWait);
} catch (InterruptedException e) {
Logger.e(TAG, "sleep interrupted");
+ return;
}
+ timeAfterOnEnableSession = SystemClock.elapsedRealtime() - mOnEnableSessionTimeStamp;
}
}
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/AdvancedSessionProcessor.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/AdvancedSessionProcessor.java
index ab42134..a9c4432 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/AdvancedSessionProcessor.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/AdvancedSessionProcessor.java
@@ -47,6 +47,9 @@
import androidx.camera.extensions.impl.advanced.OutputSurfaceImpl;
import androidx.camera.extensions.impl.advanced.RequestProcessorImpl;
import androidx.camera.extensions.impl.advanced.SessionProcessorImpl;
+import androidx.camera.extensions.internal.ClientVersion;
+import androidx.camera.extensions.internal.ExtensionVersion;
+import androidx.camera.extensions.internal.Version;
import androidx.core.util.Preconditions;
import java.util.ArrayList;
@@ -166,7 +169,12 @@
@Override
public int startTrigger(@NonNull Config config, @NonNull CaptureCallback callback) {
HashMap<CaptureRequest.Key<?>, Object> map = convertConfigToMap(config);
- return mImpl.startTrigger(map, new SessionProcessorImplCaptureCallbackAdapter(callback));
+ if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)
+ && ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)) {
+ return mImpl.startTrigger(map,
+ new SessionProcessorImplCaptureCallbackAdapter(callback));
+ }
+ return -1;
}
@Override
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessor.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessor.java
index 4a282ab..649640c 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessor.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessor.java
@@ -49,6 +49,9 @@
import androidx.camera.extensions.impl.PreviewExtenderImpl;
import androidx.camera.extensions.impl.PreviewImageProcessorImpl;
import androidx.camera.extensions.impl.RequestUpdateProcessorImpl;
+import androidx.camera.extensions.internal.ClientVersion;
+import androidx.camera.extensions.internal.ExtensionVersion;
+import androidx.camera.extensions.internal.Version;
import androidx.camera.extensions.internal.compat.workaround.OnEnableDisableSessionDurationCheck;
import androidx.core.util.Preconditions;
@@ -91,16 +94,19 @@
static AtomicInteger sLastOutputConfigId = new AtomicInteger(0);
@GuardedBy("mLock")
private final Map<CaptureRequest.Key<?>, Object> mParameters = new LinkedHashMap<>();
+ private final List<CaptureResult.Key> mSupportedResultKeys;
private OnEnableDisableSessionDurationCheck mOnEnableDisableSessionDurationCheck =
new OnEnableDisableSessionDurationCheck();
public BasicExtenderSessionProcessor(@NonNull PreviewExtenderImpl previewExtenderImpl,
@NonNull ImageCaptureExtenderImpl imageCaptureExtenderImpl,
- @NonNull List<CaptureRequest.Key> supportedKeys,
+ @NonNull List<CaptureRequest.Key> supportedRequestKeys,
+ @NonNull List<CaptureResult.Key> supportedResultKeys,
@NonNull Context context) {
- super(supportedKeys);
+ super(supportedRequestKeys);
mPreviewExtenderImpl = previewExtenderImpl;
mImageCaptureExtenderImpl = imageCaptureExtenderImpl;
+ mSupportedResultKeys = supportedResultKeys;
mContext = context;
}
@@ -275,7 +281,6 @@
}
}
});
- mPreviewProcessor.start();
}
}
@@ -349,6 +354,27 @@
mIsCapturing = false;
}
+ Map<CaptureResult.Key, Object> getCaptureResultKeyMapFromList(
+ List<Pair<CaptureResult.Key, Object>> list) {
+ Map<CaptureResult.Key, Object> map = new HashMap<>();
+ for (Pair<CaptureResult.Key, Object> pair : list) {
+ map.put(pair.first, pair.second);
+ }
+ return map;
+ }
+
+
+ Map<CaptureResult.Key, Object> getCaptureResultKeyMaps(TotalCaptureResult captureResult) {
+ Map<CaptureResult.Key, Object> map = new HashMap<>();
+ for (CaptureResult.Key<?> key : captureResult.getKeys()) {
+ if (mSupportedResultKeys.contains(key)) {
+ map.put(key, captureResult.get(key));
+ }
+ }
+ return map;
+ }
+
+
@Override
public int startRepeating(@NonNull CaptureCallback captureCallback) {
int repeatingCaptureSequenceId = mNextCaptureSequenceId.getAndIncrement();
@@ -356,6 +382,12 @@
captureCallback.onCaptureFailed(repeatingCaptureSequenceId);
captureCallback.onCaptureSequenceAborted(repeatingCaptureSequenceId);
} else {
+ if (mPreviewProcessor != null) {
+ mPreviewProcessor.start((shutterTimestamp, result) -> {
+ captureCallback.onCaptureCompleted(shutterTimestamp,
+ repeatingCaptureSequenceId, getCaptureResultKeyMapFromList(result));
+ });
+ }
updateRepeating(repeatingCaptureSequenceId, captureCallback);
}
@@ -389,6 +421,17 @@
if (mPreviewProcessor != null) {
mPreviewProcessor.notifyCaptureResult(totalCaptureResult);
+ } else {
+ if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)
+ && ExtensionVersion
+ .isMinimumCompatibleVersion(Version.VERSION_1_3)) {
+ Long timestamp = totalCaptureResult.get(CaptureResult.SENSOR_TIMESTAMP);
+ if (timestamp != null) {
+ captureCallback.onCaptureCompleted(timestamp,
+ repeatingCaptureSequenceId,
+ getCaptureResultKeyMaps(totalCaptureResult));
+ }
+ }
}
if (mRequestUpdateProcessor != null) {
@@ -529,6 +572,13 @@
captureCallback.onCaptureFailed(captureSequenceId);
mIsCapturing = false;
}
+
+ @Override
+ public void onCaptureResult(long shutterTimestamp,
+ @NonNull List<Pair<CaptureResult.Key, Object>> result) {
+ captureCallback.onCaptureCompleted(shutterTimestamp,
+ captureSequenceId, getCaptureResultKeyMapFromList(result));
+ }
});
}
setImageProcessor(mCaptureOutputConfig.getId(),
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java
index 1e8acf7..bf0f327 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java
@@ -18,7 +18,9 @@
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
+import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
+import android.util.Pair;
import android.util.Size;
import android.view.Surface;
@@ -26,7 +28,14 @@
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.camera.core.Logger;
+import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.extensions.impl.PreviewImageProcessorImpl;
+import androidx.camera.extensions.impl.ProcessResultImpl;
+import androidx.camera.extensions.internal.ClientVersion;
+import androidx.camera.extensions.internal.ExtensionVersion;
+import androidx.camera.extensions.internal.Version;
+
+import java.util.List;
/**
* A preview processor that is responsible for invoking OEM's PreviewImageProcessorImpl and
@@ -58,7 +67,12 @@
mPreviewImageProcessor.onImageFormatUpdate(ImageFormat.YUV_420_888);
}
- void start() {
+ interface OnCaptureResultCallback {
+ void onCaptureResult(long shutterTimestamp,
+ @NonNull List<Pair<CaptureResult.Key, Object>> result);
+ }
+
+ void start(@NonNull OnCaptureResultCallback onResultCallback) {
mCaptureResultImageMatcher.setImageReferenceListener(
(imageReference, totalCaptureResult, captureStageId) -> {
synchronized (mLock) {
@@ -67,8 +81,28 @@
Logger.d(TAG, "Ignore image in closed state");
return;
}
- mPreviewImageProcessor.process(imageReference.get(),
- totalCaptureResult);
+ if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)
+ && ExtensionVersion
+ .isMinimumCompatibleVersion(Version.VERSION_1_3)) {
+ mPreviewImageProcessor.process(imageReference.get(), totalCaptureResult,
+ new ProcessResultImpl() {
+ @Override
+ public void onCaptureCompleted(long shutterTimestamp,
+ @NonNull List<Pair<CaptureResult.Key, Object>>
+ result) {
+ onResultCallback.onCaptureResult(shutterTimestamp,
+ result);
+ }
+
+ @Override
+ public void onCaptureProcessProgressed(int progress) {
+
+ }
+ }, CameraXExecutors.ioExecutor());
+ } else {
+ mPreviewImageProcessor.process(imageReference.get(),
+ totalCaptureResult);
+ }
imageReference.decrement();
}
});
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/StillCaptureProcessor.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/StillCaptureProcessor.java
index b1d702f..ae8be40 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/StillCaptureProcessor.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/StillCaptureProcessor.java
@@ -17,6 +17,7 @@
package androidx.camera.extensions.internal.sessionprocessor;
import android.graphics.ImageFormat;
+import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
import android.util.Pair;
@@ -37,6 +38,10 @@
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.internal.CameraCaptureResultImageInfo;
import androidx.camera.extensions.impl.CaptureProcessorImpl;
+import androidx.camera.extensions.impl.ProcessResultImpl;
+import androidx.camera.extensions.internal.ClientVersion;
+import androidx.camera.extensions.internal.ExtensionVersion;
+import androidx.camera.extensions.internal.Version;
import org.jetbrains.annotations.TestOnly;
@@ -161,6 +166,8 @@
interface OnCaptureResultCallback {
void onCompleted();
+ void onCaptureResult(long shutterTimestamp,
+ @NonNull List<Pair<CaptureResult.Key, Object>> result);
void onError(@NonNull Exception e);
}
@@ -210,7 +217,29 @@
}
Logger.d(TAG, "CaptureProcessorImpl.process()");
try {
- mCaptureProcessorImpl.process(convertedResult);
+ if (ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)
+ && ClientVersion.isMinimumCompatibleVersion(
+ Version.VERSION_1_3)) {
+ mCaptureProcessorImpl.process(convertedResult,
+ new ProcessResultImpl() {
+ @Override
+ public void onCaptureCompleted(
+ long shutterTimestamp,
+ @NonNull List<Pair<CaptureResult.Key,
+ Object>> result) {
+ onCaptureResultCallback.onCaptureResult(
+ shutterTimestamp, result);
+ }
+
+ @Override
+ public void onCaptureProcessProgressed(
+ int progress) {
+
+ }
+ }, CameraXExecutors.ioExecutor());
+ } else {
+ mCaptureProcessorImpl.process(convertedResult);
+ }
} catch (Exception e) {
mOnCaptureResultCallback = null;
errorException = e;
diff --git a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ClientVersionTest.java b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ClientVersionTest.java
new file mode 100644
index 0000000..69c2f3a
--- /dev/null
+++ b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ClientVersionTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.camera.extensions.internal;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.os.Build;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+public class ClientVersionTest {
+ @Test
+ public void testCurrentVersion_shouldNotEmpty() {
+ assertNotNull(ClientVersion.getCurrentVersion().getVersion());
+ }
+
+ @Test
+ public void testSetCurrentVersion() {
+ ClientVersion.setCurrentVersion(new ClientVersion("1.9.0"));
+ assertThat(ClientVersion.getCurrentVersion().toVersionString()).isEqualTo("1.9.0");
+ }
+
+ @Test
+ public void testIsMinimumCompatibleVersion() {
+ ClientVersion.setCurrentVersion(new ClientVersion("1.2.0"));
+ assertThat(ClientVersion.isMinimumCompatibleVersion(Version.parse("1.1.0")))
+ .isTrue();
+ assertThat(ClientVersion.isMinimumCompatibleVersion(Version.parse("1.2.0")))
+ .isTrue();
+ assertThat(ClientVersion.isMinimumCompatibleVersion(Version.parse("1.3.0")))
+ .isFalse();
+ }
+}
diff --git a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionMaximumCompatibleTest.kt b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionMaximumCompatibleTest.kt
index b21dea5..74a649e3 100644
--- a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionMaximumCompatibleTest.kt
+++ b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionMaximumCompatibleTest.kt
@@ -37,11 +37,8 @@
class ExtensionVersionMaximumCompatibleTest(private val config: TestConfig) {
@Before
- @Throws(NoSuchFieldException::class, IllegalAccessException::class)
fun setUp() {
- val field = VersionName::class.java.getDeclaredField("CURRENT")
- field.isAccessible = true
- field[null] = VersionName(config.targetVersion)
+ ClientVersion.setCurrentVersion(ClientVersion(config.targetVersion))
}
@After
diff --git a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionMinimumCompatibleTest.kt b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionMinimumCompatibleTest.kt
index d92c03db1..b39e854 100644
--- a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionMinimumCompatibleTest.kt
+++ b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionMinimumCompatibleTest.kt
@@ -39,9 +39,7 @@
@Before
@Throws(NoSuchFieldException::class, IllegalAccessException::class)
fun setUp() {
- val field = VersionName::class.java.getDeclaredField("CURRENT")
- field.isAccessible = true
- field[null] = VersionName(config.targetVersion)
+ ClientVersion.setCurrentVersion(ClientVersion(config.targetVersion))
}
@After
diff --git a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionTest.java b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionTest.java
index 3d5fc8e..0622806 100644
--- a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionTest.java
+++ b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/ExtensionVersionTest.java
@@ -35,8 +35,6 @@
import org.robolectric.annotation.Config;
import org.robolectric.annotation.internal.DoNotInstrument;
-import java.lang.reflect.Field;
-
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
@Config(
@@ -46,10 +44,8 @@
public class ExtensionVersionTest {
@Before
- public void setUp() throws NoSuchFieldException, IllegalAccessException {
- Field field = VersionName.class.getDeclaredField("CURRENT");
- field.setAccessible(true);
- field.set(null, new VersionName("1.1.0"));
+ public void setUp() {
+ ClientVersion.setCurrentVersion(new ClientVersion("1.1.0"));
}
@Test
diff --git a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/SupportedCameraOperationsTest.kt b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/SupportedCameraOperationsTest.kt
index 0efc40a..3b6be71 100644
--- a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/SupportedCameraOperationsTest.kt
+++ b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/SupportedCameraOperationsTest.kt
@@ -70,9 +70,7 @@
}
}
private fun setCameraXExtensionsVersion(version: String) {
- val field = VersionName::class.java.getDeclaredField("CURRENT")
- field.isAccessible = true
- field[null] = VersionName(version)
+ ClientVersion.setCurrentVersion(ClientVersion(version))
}
private fun setExtensionRuntimeVersion(version: String) {
diff --git a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/VersionNameTest.java b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/VersionNameTest.java
deleted file mode 100644
index d8a36f7..0000000
--- a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/VersionNameTest.java
+++ /dev/null
@@ -1,28 +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.camera.extensions.internal;
-
-import static org.junit.Assert.assertNotNull;
-
-import org.junit.Test;
-
-public class VersionNameTest {
- @Test
- public void testCurrentVersion_shouldNotEmpty() {
- assertNotNull(VersionName.getCurrentVersion().getVersion());
- }
-}
diff --git a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/VersionTest.java b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/VersionTest.java
index 65294fc..337f2af 100644
--- a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/VersionTest.java
+++ b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/VersionTest.java
@@ -18,8 +18,11 @@
import static com.google.common.truth.Truth.assertThat;
+import androidx.test.filters.SdkSuppress;
+
import org.junit.Test;
+@SdkSuppress(minSdkVersion = 21)
public class VersionTest {
@Test
diff --git a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/compat/quirk/DeviceQuirks.java b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/compat/quirk/DeviceQuirks.java
index 8d61c48..2680c7b 100644
--- a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/compat/quirk/DeviceQuirks.java
+++ b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/compat/quirk/DeviceQuirks.java
@@ -18,6 +18,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.camera.core.impl.Quirk;
import java.util.List;
@@ -45,6 +46,7 @@
* @return A device {@link Quirk} instance of the provided type, or {@code null} if it isn't
* found.
*/
+ @RequiresApi(21)
@SuppressWarnings("unchecked")
@Nullable
public static <T extends Quirk> T get(@NonNull final Class<T> quirkClass) {
diff --git a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/sessionprocessor/Camera2OutputConfigConverterTest.kt b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/sessionprocessor/Camera2OutputConfigConverterTest.kt
index e55cb1f..c853218 100644
--- a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/sessionprocessor/Camera2OutputConfigConverterTest.kt
+++ b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/sessionprocessor/Camera2OutputConfigConverterTest.kt
@@ -20,6 +20,7 @@
import android.os.Build
import android.util.Size
import android.view.Surface
+import androidx.annotation.RequiresApi
import androidx.camera.extensions.impl.advanced.Camera2OutputConfigImpl
import androidx.camera.extensions.impl.advanced.ImageReaderOutputConfigImpl
import androidx.camera.extensions.impl.advanced.MultiResolutionImageReaderOutputConfigImpl
@@ -37,6 +38,8 @@
private const val IMAGE_FORMAT = ImageFormat.YUV_420_888
private const val MAX_IMAGES = 2
private const val ID = 10
+
+@RequiresApi(21)
private val SIZE = Size(640, 480)
@RunWith(RobolectricTestRunner::class)
@@ -222,4 +225,4 @@
override fun getImageFormat() = format
override fun getMaxImages() = maxImages
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/util/ExtensionsTestUtil.kt b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/util/ExtensionsTestUtil.kt
index 445330e..297aa9d 100644
--- a/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/util/ExtensionsTestUtil.kt
+++ b/camera/camera-extensions/src/test/java/androidx/camera/extensions/internal/util/ExtensionsTestUtil.kt
@@ -16,6 +16,7 @@
package androidx.camera.extensions.internal.util
+import androidx.annotation.RequiresApi
import androidx.camera.extensions.impl.ExtensionVersionImpl
import androidx.camera.extensions.internal.ExtensionVersion
import java.lang.reflect.Field
@@ -25,6 +26,7 @@
/**
* Util functions for extensions related robolectric test
*/
+@RequiresApi(21)
object ExtensionsTestUtil {
/**
@@ -76,4 +78,4 @@
field.isAccessible = true
field[null] = mockExtensionVersionImpl
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-lifecycle/lint-baseline.xml b/camera/camera-lifecycle/lint-baseline.xml
deleted file mode 100644
index cab989c..0000000
--- a/camera/camera-lifecycle/lint-baseline.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public ListenableFuture<Void> shutdown() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public ConcurrentCamera bindToLifecycle("
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<List<CameraInfo>> getAvailableConcurrentCameraInfos() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isConcurrentCameraModeOn() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java"/>
- </issue>
-
-</issues>
diff --git a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
index 5d9db0e..d675fb8 100644
--- a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
+++ b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
@@ -36,6 +36,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraEffect;
@@ -280,8 +281,8 @@
*
* @return A {@link ListenableFuture} representing the shutdown status. Cancellation of this
* future is a no-op.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@VisibleForTesting
@NonNull
public ListenableFuture<Void> shutdown() {
diff --git a/camera/camera-mlkit-vision/lint.xml b/camera/camera-mlkit-vision/lint.xml
deleted file mode 100644
index a65139c..0000000
--- a/camera/camera-mlkit-vision/lint.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- 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.
- 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.
- -->
-
-<lint>
- <!-- Disable NewApi lint check temporarily for unit tests.
- This file can be removed once b/200599470 is resolved. -->
- <issue id="NewApi">
- <ignore path="src/test/**" />
- </issue>
-</lint>
\ No newline at end of file
diff --git a/camera/camera-testing/lint.xml b/camera/camera-testing/lint.xml
deleted file mode 100644
index 0843ecf..0000000
--- a/camera/camera-testing/lint.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
- <!-- Disable NewApi lint check temporarily for unit tests.
- This file can be removed once b/200599470 is resolved. -->
- <issue id="NewApi">
- <ignore path="src/test/**" />
- </issue>
-</lint>
\ No newline at end of file
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java b/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
index 832c091..53a943d 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
@@ -31,6 +31,7 @@
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.CamcorderProfile;
import android.media.MediaCodec;
@@ -363,7 +364,30 @@
mCameraCaptureSessionHolder.close();
mCameraCaptureSessionHolder = null;
}
- mCameraCaptureSessionHolder = new CameraCaptureSessionHolder(this, surfaces, null);
+ mCameraCaptureSessionHolder = CameraCaptureSessionHolder.create(this, surfaces, null);
+ return mCameraCaptureSessionHolder;
+ }
+
+ /**
+ * Create a {@link CameraCaptureSession} by the hold CameraDevice
+ *
+ * @param outputConfigurations the outputConfigurations used to create CameraCaptureSession
+ * @return the CameraCaptureSession holder
+ */
+ @RequiresApi(24)
+ @NonNull
+ public CameraCaptureSessionHolder createCaptureSessionByOutputConfigurations(
+ @NonNull List<OutputConfiguration> outputConfigurations)
+ throws ExecutionException, InterruptedException, TimeoutException {
+ synchronized (mLock) {
+ Preconditions.checkState(mCameraDevice != null, "Camera is closed.");
+ }
+ if (mCameraCaptureSessionHolder != null) {
+ mCameraCaptureSessionHolder.close();
+ mCameraCaptureSessionHolder = null;
+ }
+ mCameraCaptureSessionHolder = CameraCaptureSessionHolder.createByOutputConfigurations(
+ this, outputConfigurations, null);
return mCameraCaptureSessionHolder;
}
}
@@ -386,39 +410,77 @@
private CameraCaptureSession mCameraCaptureSession;
private ListenableFuture<Void> mCloseFuture;
- CameraCaptureSessionHolder(@NonNull CameraDeviceHolder cameraDeviceHolder,
+ @NonNull
+ static CameraCaptureSessionHolder create(@NonNull CameraDeviceHolder cameraDeviceHolder,
@NonNull List<Surface> surfaces,
@Nullable CameraCaptureSession.StateCallback stateCallback
) throws ExecutionException, InterruptedException, TimeoutException {
+ return new CameraCaptureSessionHolder(cameraDeviceHolder, surfaces, stateCallback);
+ }
+
+ @RequiresApi(24)
+ @NonNull
+ static CameraCaptureSessionHolder createByOutputConfigurations(
+ @NonNull CameraDeviceHolder cameraDeviceHolder,
+ @NonNull List<OutputConfiguration> outputConfigurations,
+ @Nullable CameraCaptureSession.StateCallback stateCallback
+ ) throws ExecutionException, InterruptedException, TimeoutException {
+ return new CameraCaptureSessionHolder(cameraDeviceHolder, outputConfigurations,
+ stateCallback);
+ }
+
+ private CameraCaptureSessionHolder(@NonNull CameraDeviceHolder cameraDeviceHolder,
+ @NonNull Object paramToCreateSession,
+ @Nullable CameraCaptureSession.StateCallback stateCallback
+ ) throws ExecutionException, InterruptedException, TimeoutException {
mCameraDeviceHolder = cameraDeviceHolder;
CameraDevice cameraDevice = Preconditions.checkNotNull(cameraDeviceHolder.get());
ListenableFuture<CameraCaptureSession> openFuture = openCaptureSession(cameraDevice,
- surfaces, stateCallback, cameraDeviceHolder.mHandler);
+ paramToCreateSession, stateCallback, cameraDeviceHolder.mHandler);
mCameraCaptureSession = openFuture.get(5, TimeUnit.SECONDS);
}
- @SuppressWarnings("deprecation")
+ @SuppressLint("ClassVerificationFailure")
+ @SuppressWarnings({"deprecation", "newApi", "unchecked"})
@NonNull
private ListenableFuture<CameraCaptureSession> openCaptureSession(
@NonNull CameraDevice cameraDevice,
- @NonNull List<Surface> surfaces,
+ @NonNull Object paramToCreateSession,
@Nullable CameraCaptureSession.StateCallback stateCallback,
@NonNull Handler handler) {
return CallbackToFutureAdapter.getFuture(
openCompleter -> {
mCloseFuture = CallbackToFutureAdapter.getFuture(
closeCompleter -> {
- cameraDevice.createCaptureSession(surfaces,
- new SessionStateCallbackImpl(
- openCompleter, closeCompleter, stateCallback),
- handler);
+ if (isOutputConfigurationList(paramToCreateSession)) {
+ cameraDevice.createCaptureSessionByOutputConfigurations(
+ (List<OutputConfiguration>) paramToCreateSession,
+ new SessionStateCallbackImpl(
+ openCompleter, closeCompleter,
+ stateCallback),
+ handler);
+ } else {
+ cameraDevice.createCaptureSession(
+ (List<Surface>) paramToCreateSession,
+ new SessionStateCallbackImpl(
+ openCompleter, closeCompleter,
+ stateCallback),
+ handler);
+ }
return "Close CameraCaptureSession";
});
return "Open CameraCaptureSession";
});
}
+ private static boolean isOutputConfigurationList(@NonNull Object param) {
+ List<?> list;
+ return Build.VERSION.SDK_INT >= 24 && param instanceof List
+ && !(list = (List<?>) param).isEmpty()
+ && OutputConfiguration.class.isInstance(list.get(0));
+ }
+
void close() throws ExecutionException, InterruptedException, TimeoutException {
if (mCameraCaptureSession != null) {
mCameraCaptureSession.close();
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeSessionProcessor.kt b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeSessionProcessor.kt
index ba115c1..e6cb90e 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeSessionProcessor.kt
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeSessionProcessor.kt
@@ -45,7 +45,7 @@
const val FAKE_CAPTURE_SEQUENCE_ID = 1
-@RequiresApi(28) // writing to PRIVATE surface requires API 28+
+@RequiresApi(23) // ImageWriter requires API 23+
class FakeSessionProcessor(
val inputFormatPreview: Int? = null,
val inputFormatCapture: Int? = null
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
index 2e1ec2f..1c05072 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
@@ -73,6 +73,7 @@
public FakeUseCase() {
this(new FakeUseCaseConfig.Builder()
.setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY)
+ .setCaptureType(CaptureType.PREVIEW)
.getUseCaseConfig());
}
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
index 8902d29..a406e43 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
@@ -45,11 +45,9 @@
public class FakeUseCaseConfig implements UseCaseConfig<FakeUseCase>, ImageOutputConfig {
private final Config mConfig;
- private final CaptureType mCaptureType;
- FakeUseCaseConfig(Config config, CaptureType captureType) {
+ FakeUseCaseConfig(Config config) {
mConfig = config;
- mCaptureType = captureType;
}
@NonNull
@@ -67,7 +65,7 @@
@NonNull
@Override
public CaptureType getCaptureType() {
- return mCaptureType;
+ return retrieveOption(OPTION_CAPTURE_TYPE);
}
/** Builder for an empty Config */
@@ -77,7 +75,6 @@
ImageOutputConfig.Builder<FakeUseCaseConfig.Builder> {
private final MutableOptionsBundle mOptionsBundle;
- private final CaptureType mCaptureType;
public Builder() {
this(MutableOptionsBundle.create(), CaptureType.PREVIEW);
@@ -99,7 +96,7 @@
public Builder(@NonNull Config config, @NonNull CaptureType captureType) {
mOptionsBundle = MutableOptionsBundle.from(config);
setTargetClass(FakeUseCase.class);
- mCaptureType = captureType;
+ mOptionsBundle.insertOption(OPTION_CAPTURE_TYPE, captureType);
}
@Override
@@ -111,13 +108,13 @@
@NonNull
@Override
public FakeUseCaseConfig getUseCaseConfig() {
- return new FakeUseCaseConfig(OptionsBundle.from(mOptionsBundle), mCaptureType);
+ return new FakeUseCaseConfig(OptionsBundle.from(mOptionsBundle));
}
@Override
@NonNull
public FakeUseCase build() {
- return new FakeUseCase(getUseCaseConfig(), mCaptureType);
+ return new FakeUseCase(getUseCaseConfig());
}
// Implementations of TargetConfig.Builder default methods
diff --git a/camera/camera-video/api/current.txt b/camera/camera-video/api/current.txt
index 5b4653b..fb0f4c7 100644
--- a/camera/camera-video/api/current.txt
+++ b/camera/camera-video/api/current.txt
@@ -94,8 +94,8 @@
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 public static java.util.List<androidx.camera.video.Quality!> getSupportedQualities(androidx.camera.core.CameraInfo);
- method public static boolean isQualitySupported(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 {
@@ -103,6 +103,7 @@
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);
@@ -133,19 +134,26 @@
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 @Deprecated public void setTargetRotationDegrees(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);
diff --git a/camera/camera-video/api/restricted_current.txt b/camera/camera-video/api/restricted_current.txt
index 5b4653b..fb0f4c7 100644
--- a/camera/camera-video/api/restricted_current.txt
+++ b/camera/camera-video/api/restricted_current.txt
@@ -94,8 +94,8 @@
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 public static java.util.List<androidx.camera.video.Quality!> getSupportedQualities(androidx.camera.core.CameraInfo);
- method public static boolean isQualitySupported(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 {
@@ -103,6 +103,7 @@
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);
@@ -133,19 +134,26 @@
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 @Deprecated public void setTargetRotationDegrees(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);
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/SupportedQualitiesVerificationTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/SupportedQualitiesVerificationTest.kt
index 2458f9c..85fd4aa 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/SupportedQualitiesVerificationTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/SupportedQualitiesVerificationTest.kt
@@ -247,7 +247,7 @@
}
private fun createEffect(): CameraEffect {
- val fakeSurfaceProcessor = DefaultSurfaceProcessor.Factory.newInstance()
+ val fakeSurfaceProcessor = DefaultSurfaceProcessor.Factory.newInstance(DynamicRange.SDR)
surfaceProcessorsToRelease.add(fakeSurfaceProcessor)
return FakeSurfaceEffect(
VIDEO_CAPTURE,
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolverTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolverTest.kt
index 354f38a..ea11ae8 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolverTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolverTest.kt
@@ -16,11 +16,16 @@
package androidx.camera.video.internal.config
+import android.media.MediaCodecInfo.CodecProfileLevel
+import android.media.MediaFormat
import android.util.Range
+import androidx.camera.core.DynamicRange
import androidx.camera.core.SurfaceRequest
+import androidx.camera.core.impl.EncoderProfilesProxy
import androidx.camera.core.impl.Timebase
import androidx.camera.testing.EncoderProfilesUtil
import androidx.camera.video.VideoSpec
+import androidx.camera.video.internal.encoder.VideoEncoderDataSpace
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
@@ -34,7 +39,8 @@
class VideoEncoderConfigDefaultResolverTest {
companion object {
- const val MIME_TYPE = "video/avc"
+ const val DEFAULT_MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC
+ const val UNSUPPORTED_MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_SCRAMBLED
val TIMEBASE = Timebase.UPTIME
const val FRAME_RATE_30 = 30
const val FRAME_RATE_45 = 45
@@ -53,43 +59,46 @@
val configSupplierCif =
VideoEncoderConfigDefaultResolver(
- MIME_TYPE,
+ DEFAULT_MIME_TYPE,
TIMEBASE,
DEFAULT_VIDEO_SPEC,
surfaceSizeCif,
+ DynamicRange.SDR,
expectedFrameRateRange
)
val configSupplier720p =
VideoEncoderConfigDefaultResolver(
- MIME_TYPE,
+ DEFAULT_MIME_TYPE,
TIMEBASE,
DEFAULT_VIDEO_SPEC,
surfaceSize720p,
+ DynamicRange.SDR,
expectedFrameRateRange
)
val configSupplier1080p =
VideoEncoderConfigDefaultResolver(
- MIME_TYPE,
+ DEFAULT_MIME_TYPE,
TIMEBASE,
DEFAULT_VIDEO_SPEC,
surfaceSize1080p,
+ DynamicRange.SDR,
expectedFrameRateRange
)
val configCif = configSupplierCif.get()
- assertThat(configCif.mimeType).isEqualTo(MIME_TYPE)
+ assertThat(configCif.mimeType).isEqualTo(DEFAULT_MIME_TYPE)
assertThat(configCif.bitrate).isGreaterThan(0)
assertThat(configCif.resolution).isEqualTo(surfaceSizeCif)
assertThat(configCif.frameRate).isEqualTo(FRAME_RATE_30)
val config720p = configSupplier720p.get()
- assertThat(config720p.mimeType).isEqualTo(MIME_TYPE)
+ assertThat(config720p.mimeType).isEqualTo(DEFAULT_MIME_TYPE)
assertThat(config720p.bitrate).isGreaterThan(0)
assertThat(config720p.resolution).isEqualTo(surfaceSize720p)
assertThat(config720p.frameRate).isEqualTo(FRAME_RATE_30)
val config1080p = configSupplier1080p.get()
- assertThat(config1080p.mimeType).isEqualTo(MIME_TYPE)
+ assertThat(config1080p.mimeType).isEqualTo(DEFAULT_MIME_TYPE)
assertThat(config1080p.bitrate).isGreaterThan(0)
assertThat(config1080p.resolution).isEqualTo(surfaceSize1080p)
assertThat(config1080p.frameRate).isEqualTo(FRAME_RATE_30)
@@ -102,10 +111,11 @@
// Get default bit rate for this size
val defaultConfig =
VideoEncoderConfigDefaultResolver(
- MIME_TYPE,
+ DEFAULT_MIME_TYPE,
TIMEBASE,
DEFAULT_VIDEO_SPEC,
surfaceSize720p,
+ DynamicRange.SDR,
SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
).get()
val defaultBitrate = defaultConfig.bitrate
@@ -121,20 +131,22 @@
assertThat(
VideoEncoderConfigDefaultResolver(
- MIME_TYPE,
+ DEFAULT_MIME_TYPE,
TIMEBASE,
higherVideoSpec,
surfaceSize720p,
+ DynamicRange.SDR,
SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
).get().bitrate
).isEqualTo(higherBitrate)
assertThat(
VideoEncoderConfigDefaultResolver(
- MIME_TYPE,
+ DEFAULT_MIME_TYPE,
TIMEBASE,
lowerVideoSpec,
surfaceSize720p,
+ DynamicRange.SDR,
SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
).get().bitrate
).isEqualTo(lowerBitrate)
@@ -146,10 +158,11 @@
assertThat(
VideoEncoderConfigDefaultResolver(
- MIME_TYPE,
+ DEFAULT_MIME_TYPE,
TIMEBASE,
DEFAULT_VIDEO_SPEC,
size,
+ DynamicRange.SDR,
SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
).get().frameRate
).isEqualTo(
@@ -166,14 +179,233 @@
// Expected frame rate range takes precedence over VideoSpec
assertThat(
VideoEncoderConfigDefaultResolver(
- MIME_TYPE,
+ DEFAULT_MIME_TYPE,
TIMEBASE,
DEFAULT_VIDEO_SPEC,
size,
+ DynamicRange.SDR,
expectedFrameRateRange
).get().frameRate
).isEqualTo(
FRAME_RATE_45
)
}
+
+ @Test
+ fun avcMimeType_producesNoProfile_forHdrDynamicRange() {
+ testMimeAndDynamicRangeResolveToProfile(
+ MediaFormat.MIMETYPE_VIDEO_AVC,
+ DynamicRange.HLG_10_BIT, // AVC does not support HLG10
+ EncoderProfilesProxy.CODEC_PROFILE_NONE
+ )
+ }
+
+ @Test
+ fun unsupportedDynamicRange_producesNoProfile() {
+ testMimeAndDynamicRangeResolveToProfile(
+ MediaFormat.MIMETYPE_VIDEO_HEVC,
+ DynamicRange.DOLBY_VISION_10_BIT, // Dolby vision not supported by HEVC
+ EncoderProfilesProxy.CODEC_PROFILE_NONE
+ )
+ }
+
+ @Test
+ fun unsupportedMime_producesNoProfile() {
+ testMimeAndDynamicRangeResolveToProfile(
+ UNSUPPORTED_MIME_TYPE,
+ DynamicRange.HLG_10_BIT,
+ EncoderProfilesProxy.CODEC_PROFILE_NONE
+ )
+ }
+
+ @Test
+ fun codecProfileIsChosenFromMimeAndDynamicRange_hevc() {
+ val dynamicRangeToExpectedProfiles = mapOf(
+ DynamicRange.SDR to CodecProfileLevel.HEVCProfileMain,
+ DynamicRange.HLG_10_BIT to CodecProfileLevel.HEVCProfileMain10,
+ DynamicRange.HDR10_10_BIT to CodecProfileLevel.HEVCProfileMain10HDR10,
+ DynamicRange.HDR10_PLUS_10_BIT to CodecProfileLevel.HEVCProfileMain10HDR10Plus
+ )
+
+ for (entry in dynamicRangeToExpectedProfiles) {
+ testMimeAndDynamicRangeResolveToProfile(
+ MediaFormat.MIMETYPE_VIDEO_HEVC,
+ entry.key,
+ entry.value
+ )
+ }
+ }
+
+ @Test
+ fun codecProfileIsChosenFromMimeAndDynamicRange_av1() {
+ val dynamicRangeToExpectedProfiles = mapOf(
+ DynamicRange.SDR to CodecProfileLevel.AV1ProfileMain8,
+ DynamicRange.HLG_10_BIT to CodecProfileLevel.AV1ProfileMain10,
+ DynamicRange.HDR10_10_BIT to CodecProfileLevel.AV1ProfileMain10HDR10,
+ DynamicRange.HDR10_PLUS_10_BIT to CodecProfileLevel.AV1ProfileMain10HDR10Plus
+ )
+
+ for (entry in dynamicRangeToExpectedProfiles) {
+ testMimeAndDynamicRangeResolveToProfile(
+ MediaFormat.MIMETYPE_VIDEO_HEVC,
+ entry.key,
+ entry.value
+ )
+ }
+ }
+
+ @Test
+ fun codecProfileIsChosenFromMimeAndDynamicRange_vp9() {
+ val dynamicRangeToExpectedProfiles = mapOf(
+ DynamicRange.SDR to CodecProfileLevel.VP9Profile0,
+ DynamicRange.HLG_10_BIT to CodecProfileLevel.VP9Profile2,
+ DynamicRange.HDR10_10_BIT to CodecProfileLevel.VP9Profile2HDR,
+ DynamicRange.HDR10_PLUS_10_BIT to CodecProfileLevel.VP9Profile2HDR10Plus
+ )
+
+ for (entry in dynamicRangeToExpectedProfiles) {
+ testMimeAndDynamicRangeResolveToProfile(
+ MediaFormat.MIMETYPE_VIDEO_VP9,
+ entry.key,
+ entry.value
+ )
+ }
+ }
+
+ @Test
+ fun codecProfileIsChosenFromMimeAndDynamicRange_dolbyVision() {
+ val dynamicRangeToExpectedProfiles = mapOf(
+ DynamicRange.DOLBY_VISION_10_BIT to CodecProfileLevel.DolbyVisionProfileDvheSt,
+ DynamicRange.DOLBY_VISION_8_BIT to CodecProfileLevel.DolbyVisionProfileDvavSe,
+ )
+
+ for (entry in dynamicRangeToExpectedProfiles) {
+ testMimeAndDynamicRangeResolveToProfile(
+ MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION,
+ entry.key,
+ entry.value
+ )
+ }
+ }
+
+ @Test
+ fun dataSpaceIsUnspecified_forUnsupportedMime() {
+ testMimeAndDynamicRangeResolvesToDataSpace(
+ UNSUPPORTED_MIME_TYPE,
+ DynamicRange.HLG_10_BIT,
+ VideoEncoderDataSpace.ENCODER_DATA_SPACE_UNSPECIFIED
+ )
+ }
+
+ @Test
+ fun dataSpaceIsChosenFromDynamicRange_hevc() {
+ val dynamicRangeToExpectedDataSpaces = mapOf(
+ // For backward compatibility, SDR maps to UNSPECIFIED
+ DynamicRange.SDR to VideoEncoderDataSpace.ENCODER_DATA_SPACE_UNSPECIFIED,
+ DynamicRange.HLG_10_BIT to VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_HLG,
+ DynamicRange.HDR10_10_BIT to VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_PQ,
+ DynamicRange.HDR10_PLUS_10_BIT to VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_PQ,
+ )
+
+ for (entry in dynamicRangeToExpectedDataSpaces) {
+ testMimeAndDynamicRangeResolvesToDataSpace(
+ MediaFormat.MIMETYPE_VIDEO_HEVC,
+ entry.key,
+ entry.value
+ )
+ }
+ }
+
+ @Test
+ fun dataSpaceIsChosenFromDynamicRange_av1() {
+ val dynamicRangeToExpectedDataSpaces = mapOf(
+ // For backward compatibility, SDR maps to UNSPECIFIED
+ DynamicRange.SDR to VideoEncoderDataSpace.ENCODER_DATA_SPACE_UNSPECIFIED,
+ DynamicRange.HLG_10_BIT to VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_HLG,
+ DynamicRange.HDR10_10_BIT to VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_PQ,
+ DynamicRange.HDR10_PLUS_10_BIT to VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_PQ,
+ )
+
+ for (entry in dynamicRangeToExpectedDataSpaces) {
+ testMimeAndDynamicRangeResolvesToDataSpace(
+ MediaFormat.MIMETYPE_VIDEO_AV1,
+ entry.key,
+ entry.value
+ )
+ }
+ }
+
+ @Test
+ fun dataSpaceIsChosenFromDynamicRange_vp9() {
+ val dynamicRangeToExpectedDataSpaces = mapOf(
+ // For backward compatibility, SDR maps to UNSPECIFIED
+ DynamicRange.SDR to VideoEncoderDataSpace.ENCODER_DATA_SPACE_UNSPECIFIED,
+ DynamicRange.HLG_10_BIT to VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_HLG,
+ DynamicRange.HDR10_10_BIT to VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_PQ,
+ DynamicRange.HDR10_PLUS_10_BIT to VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_PQ,
+ )
+
+ for (entry in dynamicRangeToExpectedDataSpaces) {
+ testMimeAndDynamicRangeResolvesToDataSpace(
+ MediaFormat.MIMETYPE_VIDEO_VP9,
+ entry.key,
+ entry.value
+ )
+ }
+ }
+
+ @Test
+ fun dataSpaceIsChosenFromDynamicRange_dolbyVision() {
+ val dynamicRangeToExpectedDataSpaces = mapOf(
+ DynamicRange.DOLBY_VISION_10_BIT to VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_HLG,
+ DynamicRange.DOLBY_VISION_8_BIT to VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT709,
+ )
+
+ for (entry in dynamicRangeToExpectedDataSpaces) {
+ testMimeAndDynamicRangeResolvesToDataSpace(
+ MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION,
+ entry.key,
+ entry.value
+ )
+ }
+ }
+
+ private fun testMimeAndDynamicRangeResolveToProfile(
+ mime: String,
+ dynamicRange: DynamicRange,
+ expectedProfile: Int
+ ) {
+ // Expected frame rate range takes precedence over VideoSpec
+ assertThat(
+ VideoEncoderConfigDefaultResolver(
+ mime,
+ TIMEBASE,
+ DEFAULT_VIDEO_SPEC,
+ EncoderProfilesUtil.RESOLUTION_1080P,
+ dynamicRange,
+ SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
+ ).get().profile
+ ).isEqualTo(
+ expectedProfile
+ )
+ }
+
+ private fun testMimeAndDynamicRangeResolvesToDataSpace(
+ mime: String,
+ dynamicRange: DynamicRange,
+ expectedDataSpace: VideoEncoderDataSpace,
+ ) {
+ assertThat(
+ VideoEncoderConfigDefaultResolver(
+ mime,
+ TIMEBASE,
+ DEFAULT_VIDEO_SPEC,
+ EncoderProfilesUtil.RESOLUTION_1080P,
+ dynamicRange,
+ SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
+ ).get().dataSpace
+ ).isEqualTo(
+ expectedDataSpace
+ )
+ }
}
\ No newline at end of file
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolverTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolverTest.kt
index 8bd09e7..9a321d4 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolverTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolverTest.kt
@@ -34,6 +34,7 @@
import androidx.camera.video.Recorder
import androidx.camera.video.VideoCapabilities
import androidx.camera.video.VideoSpec
+import androidx.camera.video.internal.encoder.VideoEncoderDataSpace
import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
@@ -75,9 +76,7 @@
private val defaultVideoSpec = VideoSpec.builder().build()
private val timebase = Timebase.UPTIME
- // TODO(b/278168212): Only SDR is checked by now. Need to extend to HDR dynamic ranges.
- private val dynamicRange = DynamicRange.SDR
-
+ private lateinit var dynamicRanges: Set<DynamicRange>
private lateinit var cameraUseCaseAdapter: CameraUseCaseAdapter
private lateinit var videoCapabilities: VideoCapabilities
@@ -92,7 +91,10 @@
val cameraInfo = CameraUtil.createCameraUseCaseAdapter(context, cameraSelector).cameraInfo
videoCapabilities = Recorder.getVideoCapabilities(cameraInfo)
- Assume.assumeTrue(videoCapabilities.getSupportedQualities(dynamicRange).isNotEmpty())
+ dynamicRanges = videoCapabilities.supportedDynamicRanges
+ dynamicRanges.forEach {
+ Assume.assumeTrue(videoCapabilities.getSupportedQualities(it).isNotEmpty())
+ }
}
@After
@@ -108,190 +110,277 @@
@Test
fun defaultVideoSpecProducesValidSettings_forSurfaceSizeEquivalentToQuality() {
- val supportedProfiles = videoCapabilities.getSupportedQualities(dynamicRange).map {
- videoCapabilities.getProfiles(it, dynamicRange)!!
- }
+ dynamicRanges.forEach { dynamicRange ->
+ val supportedProfiles = videoCapabilities.getSupportedQualities(dynamicRange).map {
+ videoCapabilities.getProfiles(it, dynamicRange)!!
+ }
- supportedProfiles.forEach {
- val videoProfile = it.defaultVideoProfile
- val config = VideoEncoderConfigVideoProfileResolver(
- videoProfile.mediaType,
- timebase,
- defaultVideoSpec,
- Size(videoProfile.width, videoProfile.height),
- videoProfile,
- SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
- ).get()
+ supportedProfiles.forEach {
+ val videoProfile = it.defaultVideoProfile
+ val config = VideoEncoderConfigVideoProfileResolver(
+ videoProfile.mediaType,
+ timebase,
+ defaultVideoSpec,
+ Size(videoProfile.width, videoProfile.height),
+ videoProfile,
+ dynamicRange,
+ SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
+ ).get()
- assertThat(config.mimeType).isEqualTo(videoProfile.mediaType)
- assertThat(config.bitrate).isEqualTo(videoProfile.bitrate)
- assertThat(config.resolution).isEqualTo(Size(videoProfile.width, videoProfile.height))
- assertThat(config.frameRate).isEqualTo(videoProfile.frameRate)
+ assertThat(config.mimeType).isEqualTo(videoProfile.mediaType)
+ assertThat(config.bitrate).isEqualTo(videoProfile.bitrate)
+ assertThat(config.resolution).isEqualTo(
+ Size(
+ videoProfile.width,
+ videoProfile.height
+ )
+ )
+ assertThat(config.frameRate).isEqualTo(videoProfile.frameRate)
+ }
}
}
@Test
fun bitrateIncreasesOrDecreasesWithIncreaseOrDecreaseInSurfaceSize() {
- val profile =
- videoCapabilities.getProfiles(Quality.HIGHEST, dynamicRange)!!.defaultVideoProfile
- val surfaceSize = Size(profile.width, profile.height)
+ dynamicRanges.forEach { dynamicRange ->
+ val profile =
+ videoCapabilities.getProfiles(Quality.HIGHEST, dynamicRange)!!.defaultVideoProfile
+ val surfaceSize = Size(profile.width, profile.height)
- val defaultBitrate = VideoEncoderConfigVideoProfileResolver(
- profile.mediaType,
- timebase,
- defaultVideoSpec,
- surfaceSize,
- profile,
- SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
- ).get().bitrate
-
- val increasedSurfaceSize = Size(surfaceSize.width + 100, surfaceSize.height + 100)
- val decreasedSurfaceSize = Size(surfaceSize.width - 100, surfaceSize.height - 100)
-
- assertThat(
- VideoEncoderConfigVideoProfileResolver(
+ val defaultBitrate = VideoEncoderConfigVideoProfileResolver(
profile.mediaType,
timebase,
defaultVideoSpec,
- increasedSurfaceSize,
+ surfaceSize,
profile,
+ dynamicRange,
SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
).get().bitrate
- ).isGreaterThan(defaultBitrate)
- assertThat(
- VideoEncoderConfigVideoProfileResolver(
- profile.mediaType,
- timebase,
- defaultVideoSpec,
- decreasedSurfaceSize,
- profile,
- SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
- ).get().bitrate
- ).isLessThan(defaultBitrate)
+ val increasedSurfaceSize = Size(surfaceSize.width + 100, surfaceSize.height + 100)
+ val decreasedSurfaceSize = Size(surfaceSize.width - 100, surfaceSize.height - 100)
+
+ assertThat(
+ VideoEncoderConfigVideoProfileResolver(
+ profile.mediaType,
+ timebase,
+ defaultVideoSpec,
+ increasedSurfaceSize,
+ profile,
+ dynamicRange,
+ SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
+ ).get().bitrate
+ ).isGreaterThan(defaultBitrate)
+
+ assertThat(
+ VideoEncoderConfigVideoProfileResolver(
+ profile.mediaType,
+ timebase,
+ defaultVideoSpec,
+ decreasedSurfaceSize,
+ profile,
+ dynamicRange,
+ SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
+ ).get().bitrate
+ ).isLessThan(defaultBitrate)
+ }
}
@Test
fun bitrateRangeInVideoSpecClampsBitrate() {
- val profile =
- videoCapabilities.getProfiles(Quality.HIGHEST, dynamicRange)!!.defaultVideoProfile
- val surfaceSize = Size(profile.width, profile.height)
+ dynamicRanges.forEach { dynamicRange ->
+ val profile =
+ videoCapabilities.getProfiles(Quality.HIGHEST, dynamicRange)!!.defaultVideoProfile
+ val surfaceSize = Size(profile.width, profile.height)
- val defaultBitrate = VideoEncoderConfigVideoProfileResolver(
- profile.mediaType,
- timebase,
- defaultVideoSpec,
- surfaceSize,
- profile,
- SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
- ).get().bitrate
-
- // Create video spec with limit 20% higher than default.
- val higherBitrate = (defaultBitrate * 1.2).toInt()
- val higherVideoSpec =
- VideoSpec.builder().setBitrate(Range(higherBitrate, Int.MAX_VALUE)).build()
-
- // Create video spec with limit 20% lower than default.
- val lowerBitrate = (defaultBitrate * 0.8).toInt()
- val lowerVideoSpec = VideoSpec.builder().setBitrate(Range(0, lowerBitrate)).build()
-
- assertThat(
- VideoEncoderConfigVideoProfileResolver(
+ val defaultBitrate = VideoEncoderConfigVideoProfileResolver(
profile.mediaType,
timebase,
- higherVideoSpec,
+ defaultVideoSpec,
surfaceSize,
profile,
+ dynamicRange,
SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
).get().bitrate
- ).isEqualTo(higherBitrate)
- assertThat(
- VideoEncoderConfigVideoProfileResolver(
- profile.mediaType,
- timebase,
- lowerVideoSpec,
- surfaceSize,
- profile,
- SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
- ).get().bitrate
- ).isEqualTo(lowerBitrate)
+ // Create video spec with limit 20% higher than default.
+ val higherBitrate = (defaultBitrate * 1.2).toInt()
+ val higherVideoSpec =
+ VideoSpec.builder().setBitrate(Range(higherBitrate, Int.MAX_VALUE)).build()
+
+ // Create video spec with limit 20% lower than default.
+ val lowerBitrate = (defaultBitrate * 0.8).toInt()
+ val lowerVideoSpec = VideoSpec.builder().setBitrate(Range(0, lowerBitrate)).build()
+
+ assertThat(
+ VideoEncoderConfigVideoProfileResolver(
+ profile.mediaType,
+ timebase,
+ higherVideoSpec,
+ surfaceSize,
+ profile,
+ dynamicRange,
+ SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
+ ).get().bitrate
+ ).isEqualTo(higherBitrate)
+
+ assertThat(
+ VideoEncoderConfigVideoProfileResolver(
+ profile.mediaType,
+ timebase,
+ lowerVideoSpec,
+ surfaceSize,
+ profile,
+ dynamicRange,
+ SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
+ ).get().bitrate
+ ).isEqualTo(lowerBitrate)
+ }
}
@Test
fun resolvedFrameRateIsClampedToOperatingRate() {
- val profile =
- videoCapabilities.getProfiles(Quality.HIGHEST, dynamicRange)!!.defaultVideoProfile
- val surfaceSize = Size(profile.width, profile.height)
+ dynamicRanges.forEach { dynamicRange ->
+ val profile =
+ videoCapabilities.getProfiles(Quality.HIGHEST, dynamicRange)!!.defaultVideoProfile
+ val surfaceSize = Size(profile.width, profile.height)
- // Construct operating ranges that are both lower and higher than the profile FPS
- val lowerOperatingRange = Range(profile.frameRate / 4, profile.frameRate / 2)
- val higherOperatingRange = Range(profile.frameRate * 2, profile.frameRate * 4)
+ // Construct operating ranges that are both lower and higher than the profile FPS
+ val lowerOperatingRange = Range(profile.frameRate / 4, profile.frameRate / 2)
+ val higherOperatingRange = Range(profile.frameRate * 2, profile.frameRate * 4)
- val clampedDownFrameRate = VideoEncoderConfigVideoProfileResolver(
- profile.mediaType,
- timebase,
- defaultVideoSpec,
- surfaceSize,
- profile,
- lowerOperatingRange
- ).get().frameRate
+ val clampedDownFrameRate = VideoEncoderConfigVideoProfileResolver(
+ profile.mediaType,
+ timebase,
+ defaultVideoSpec,
+ surfaceSize,
+ profile,
+ dynamicRange,
+ lowerOperatingRange
+ ).get().frameRate
- val clampedUpFrameRate = VideoEncoderConfigVideoProfileResolver(
- profile.mediaType,
- timebase,
- defaultVideoSpec,
- surfaceSize,
- profile,
- higherOperatingRange
- ).get().frameRate
+ val clampedUpFrameRate = VideoEncoderConfigVideoProfileResolver(
+ profile.mediaType,
+ timebase,
+ defaultVideoSpec,
+ surfaceSize,
+ profile,
+ dynamicRange,
+ higherOperatingRange
+ ).get().frameRate
- assertThat(clampedDownFrameRate).isEqualTo(lowerOperatingRange.upper)
- assertThat(clampedUpFrameRate).isEqualTo(higherOperatingRange.lower)
+ assertThat(clampedDownFrameRate).isEqualTo(lowerOperatingRange.upper)
+ assertThat(clampedUpFrameRate).isEqualTo(higherOperatingRange.lower)
+ }
}
@Test
fun resolvedFrameRateInsideOperatingRangeIsUnchanged() {
- val profile =
- videoCapabilities.getProfiles(Quality.HIGHEST, dynamicRange)!!.defaultVideoProfile
- val surfaceSize = Size(profile.width, profile.height)
+ dynamicRanges.forEach { dynamicRange ->
+ val profile =
+ videoCapabilities.getProfiles(Quality.HIGHEST, dynamicRange)!!.defaultVideoProfile
+ val surfaceSize = Size(profile.width, profile.height)
- // Construct a range that includes the profile FPS
- val operatingRange = Range(profile.frameRate / 2, profile.frameRate * 2)
+ // Construct a range that includes the profile FPS
+ val operatingRange = Range(profile.frameRate / 2, profile.frameRate * 2)
- val resolvedFrameRate = VideoEncoderConfigVideoProfileResolver(
- profile.mediaType,
- timebase,
- defaultVideoSpec,
- surfaceSize,
- profile,
- operatingRange
- ).get().frameRate
+ val resolvedFrameRate = VideoEncoderConfigVideoProfileResolver(
+ profile.mediaType,
+ timebase,
+ defaultVideoSpec,
+ surfaceSize,
+ profile,
+ dynamicRange,
+ operatingRange
+ ).get().frameRate
- assertThat(resolvedFrameRate).isEqualTo(profile.frameRate)
+ assertThat(resolvedFrameRate).isEqualTo(profile.frameRate)
+ }
}
@Test
fun bitrateScalesWithFrameRateOperatingRange() {
- val profile =
- videoCapabilities.getProfiles(Quality.HIGHEST, dynamicRange)!!.defaultVideoProfile
- val surfaceSize = Size(profile.width, profile.height)
+ dynamicRanges.forEach { dynamicRange ->
+ val profile =
+ videoCapabilities.getProfiles(Quality.HIGHEST, dynamicRange)!!.defaultVideoProfile
+ val surfaceSize = Size(profile.width, profile.height)
- // Construct a range which is constant and half the profile FPS
- val operatingFrameRate = profile.frameRate / 2
- val operatingRange = Range(operatingFrameRate, operatingFrameRate)
+ // Construct a range which is constant and half the profile FPS
+ val operatingFrameRate = profile.frameRate / 2
+ val operatingRange = Range(operatingFrameRate, operatingFrameRate)
- val resolvedBitrate = VideoEncoderConfigVideoProfileResolver(
- profile.mediaType,
- timebase,
- defaultVideoSpec,
- surfaceSize,
- profile,
- operatingRange
- ).get().bitrate
+ val resolvedBitrate = VideoEncoderConfigVideoProfileResolver(
+ profile.mediaType,
+ timebase,
+ defaultVideoSpec,
+ surfaceSize,
+ profile,
+ dynamicRange,
+ operatingRange
+ ).get().bitrate
- assertThat(resolvedBitrate).isEqualTo(
- (profile.bitrate * (operatingFrameRate.toDouble() / profile.frameRate)).toInt()
- )
+ assertThat(resolvedBitrate).isEqualTo(
+ (profile.bitrate * (operatingFrameRate.toDouble() / profile.frameRate)).toInt()
+ )
+ }
+ }
+
+ @Test
+ fun codecProfileLevel_isResolvedFromVideoProfile() {
+ dynamicRanges.forEach { dynamicRange ->
+ val supportedProfiles = videoCapabilities.getSupportedQualities(dynamicRange).flatMap {
+ videoCapabilities.getProfiles(it, dynamicRange)!!.videoProfiles
+ }
+
+ supportedProfiles.forEach { videoProfile ->
+ val surfaceSize = Size(videoProfile.width, videoProfile.height)
+
+ val resolvedProfile = VideoEncoderConfigVideoProfileResolver(
+ videoProfile.mediaType,
+ timebase,
+ defaultVideoSpec,
+ surfaceSize,
+ videoProfile,
+ dynamicRange,
+ Range(videoProfile.frameRate, videoProfile.frameRate)
+ ).get().profile
+
+ assertThat(resolvedProfile).isEqualTo(videoProfile.profile)
+ }
+ }
+ }
+
+ @Test
+ fun supportedHdrDynamicRanges_mapToSpecifiedVideoEncoderDataSpace() {
+ dynamicRanges.forEach { dynamicRange ->
+ val supportedProfiles = videoCapabilities.getSupportedQualities(dynamicRange).flatMap {
+ videoCapabilities.getProfiles(it, dynamicRange)!!.videoProfiles
+ }.toSet()
+
+ supportedProfiles.forEach { videoProfile ->
+ val surfaceSize = Size(videoProfile.width, videoProfile.height)
+
+ val resolvedDataSpace = VideoEncoderConfigVideoProfileResolver(
+ videoProfile.mediaType,
+ timebase,
+ defaultVideoSpec,
+ surfaceSize,
+ videoProfile,
+ dynamicRange,
+ Range(videoProfile.frameRate, videoProfile.frameRate)
+ ).get().dataSpace
+
+ // SDR should always map to UNSPECIFIED, while others should not
+ if (dynamicRange == DynamicRange.SDR) {
+ assertThat(resolvedDataSpace).isEqualTo(
+ VideoEncoderDataSpace.ENCODER_DATA_SPACE_UNSPECIFIED
+ )
+ } else {
+ assertThat(resolvedDataSpace).isNotEqualTo(
+ VideoEncoderDataSpace.ENCODER_DATA_SPACE_UNSPECIFIED
+ )
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt
index d6c35d2..16c14bb 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt
@@ -169,6 +169,7 @@
videoSpec,
resolution,
videoProfile,
+ dynamicRange,
SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
).get().toMediaFormat()
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/QualitySelector.java b/camera/camera-video/src/main/java/androidx/camera/video/QualitySelector.java
index 14b257a..19cefa9 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/QualitySelector.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/QualitySelector.java
@@ -96,7 +96,10 @@
* in the returned list, but their corresponding qualities are included.
*
* @param cameraInfo the cameraInfo
+ *
+ * @deprecated use {@link VideoCapabilities#getSupportedQualities(DynamicRange)} instead.
*/
+ @Deprecated
@NonNull
public static List<Quality> getSupportedQualities(@NonNull CameraInfo cameraInfo) {
return Recorder.getVideoCapabilities(cameraInfo).getSupportedQualities(SDR);
@@ -119,7 +122,10 @@
* @param quality one of the quality constants.
* @return {@code true} if the quality is supported; {@code false} otherwise.
* @see #getSupportedQualities(CameraInfo)
+ *
+ * @deprecated use {@link VideoCapabilities#isQualitySupported(Quality, DynamicRange)} instead.
*/
+ @Deprecated
public static boolean isQualitySupported(@NonNull CameraInfo cameraInfo,
@NonNull Quality quality) {
return Recorder.getVideoCapabilities(cameraInfo).isQualitySupported(quality, SDR);
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java b/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java
index d14e237..542578e 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java
@@ -2727,9 +2727,15 @@
}
/**
- * Gets the {@link VideoCapabilities} of Recorder.
+ * Returns the {@link VideoCapabilities} of Recorder with respect to input camera information.
+ *
+ * <p>{@link VideoCapabilities} provides methods to query supported dynamic ranges and
+ * qualities. This information can be used for things like checking if HDR is supported for
+ * configuring VideoCapture to record HDR video.
+ *
+ * @param cameraInfo info about the camera.
+ * @return VideoCapabilities with respect to the input camera info.
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY)
@NonNull
public static VideoCapabilities getVideoCapabilities(@NonNull CameraInfo cameraInfo) {
return RecorderVideoCapabilities.from(cameraInfo);
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapabilities.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapabilities.java
index 0d8521c..02b857e 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapabilities.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapabilities.java
@@ -32,8 +32,19 @@
/**
* VideoCapabilities is used to query video recording capabilities on the device.
+ *
+ * <p>Take {@link Recorder} as an example, the supported {@link DynamicRange}s can be queried with
+ * the following code:
+ * <pre>{@code
+ * VideoCapabilities videoCapabilities = Recorder.getVideoCapabilities(cameraInfo);
+ * Set<DynamicRange> supportedDynamicRanges = videoCapabilities.getSupportedDynamicRanges();
+ * }</pre>
+ * <p>The query result can be used to check if high dynamic range (HDR) recording is
+ * supported, and to get the supported qualities of the target {@link DynamicRange}:
+ * <pre>{@code
+ * List<Quality> supportedQualities = videoCapabilities.getSupportedQualities(dynamicRange);
+ * }</pre>
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
public interface VideoCapabilities {
@@ -45,6 +56,8 @@
* {@link DynamicRange}s such as {@link DynamicRange#HDR_UNSPECIFIED_10_BIT} will not be
* included, but they can be used in other methods, such as checking for quality support with
* {@link #isQualitySupported(Quality, DynamicRange)}.
+ *
+ * @return a set of supported dynamic ranges.
*/
@NonNull
Set<DynamicRange> getSupportedDynamicRanges();
@@ -52,9 +65,25 @@
/**
* Gets all supported qualities for the input dynamic range.
*
- * <p>The returned list is sorted by quality size from large to small.
+ * <p>The returned list is sorted by quality size from largest to smallest. For the qualities in
+ * the returned list, with the same input dynamicRange,
+ * {@link #isQualitySupported(Quality, DynamicRange)} will return {@code true}.
*
- * <p>Note: Constants {@link Quality#HIGHEST} and {@link Quality#LOWEST} are not included.
+ * <p>When the {@code dynamicRange} is not fully specified, e.g.
+ * {@link DynamicRange#HDR_UNSPECIFIED_10_BIT}, the returned list is the union of the
+ * qualities supported by the matching fully specified dynamic ranges. This does not mean
+ * that all returned qualities are available for every matching dynamic range. Therefore, it
+ * is not recommended to rely on any one particular quality to work if mixing use cases with
+ * other dynamic ranges.
+ *
+ * <p>Note: Constants {@link Quality#HIGHEST} and {@link Quality#LOWEST} are not included in
+ * the returned list, but their corresponding qualities are included. For example: when the
+ * returned list consists of {@link Quality#UHD}, {@link Quality#FHD} and {@link Quality#HD},
+ * {@link Quality#HIGHEST} corresponds to {@link Quality#UHD}, which is the highest quality,
+ * and {@link Quality#LOWEST} corresponds to {@link Quality#HD}.
+ *
+ * @param dynamicRange the dynamicRange.
+ * @return a list of supported qualities sorted by size from large to small.
*/
@NonNull
List<Quality> getSupportedQualities(@NonNull DynamicRange dynamicRange);
@@ -62,11 +91,25 @@
/**
* Checks if the quality is supported for the input dynamic range.
*
- * @param quality one of the quality constants. Possible values include
- * {@link Quality#LOWEST}, {@link Quality#HIGHEST}, {@link Quality#SD},
- * {@link Quality#HD}, {@link Quality#FHD}, or {@link Quality#UHD}.
- * @param dynamicRange the target dynamicRange.
+ * <p>Calling this method with one of the qualities contained in the returned list of
+ * {@link #getSupportedQualities(DynamicRange)} will return {@code true}.
+ *
+ * <p>Possible values for {@code quality} include {@link Quality#LOWEST},
+ * {@link Quality#HIGHEST}, {@link Quality#SD}, {@link Quality#HD}, {@link Quality#FHD}
+ * and {@link Quality#UHD}.
+ *
+ * <p>If this method is called with {@link Quality#LOWEST} or {@link Quality#HIGHEST}, it
+ * will return {@code true} except the case that none of the qualities can be supported.
+ *
+ * <p>When the {@code dynamicRange} is not fully specified, e.g.
+ * {@link DynamicRange#HDR_UNSPECIFIED_10_BIT}, {@code true} will be returned if there is any
+ * matching fully specified dynamic range supporting the {@code quality}, otherwise {@code
+ * false} will be returned.
+ *
+ * @param quality one of the quality constants.
+ * @param dynamicRange the dynamicRange.
* @return {@code true} if the quality is supported; {@code false} otherwise.
+ * @see #getSupportedQualities(DynamicRange)
*/
boolean isQualitySupported(@NonNull Quality quality, @NonNull DynamicRange dynamicRange);
@@ -130,6 +173,8 @@
}
/** An empty implementation. */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @NonNull
VideoCapabilities EMPTY = new VideoCapabilities() {
@NonNull
@Override
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
index a10d019..3632b07 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
@@ -38,7 +38,6 @@
import static androidx.camera.core.impl.UseCaseConfig.OPTION_ZSL_DISABLED;
import static androidx.camera.core.impl.utils.Threads.isMainThread;
import static androidx.camera.core.impl.utils.TransformUtils.rectToString;
-import static androidx.camera.core.impl.utils.TransformUtils.within360;
import static androidx.camera.core.internal.TargetConfig.OPTION_TARGET_CLASS;
import static androidx.camera.core.internal.TargetConfig.OPTION_TARGET_NAME;
import static androidx.camera.core.internal.ThreadConfig.OPTION_BACKGROUND_EXECUTOR;
@@ -324,79 +323,6 @@
}
/**
- * Sets the desired rotation of the output video in degrees.
- *
- * <p>In general, it is best to use an {@link android.view.OrientationEventListener} to set
- * the target rotation. This way, the rotation output will indicate which way is down for a
- * given video. This is important since display orientation may be locked by device default,
- * user setting, or app configuration, and some devices may not transition to a
- * reverse-portrait display orientation. In these cases, use
- * {@code setTargetRotationDegrees()} to set target rotation dynamically according
- * to the {@link android.view.OrientationEventListener}, without re-creating the use case.
- * The sample code is as below:
- * <pre>{@code
- * public class CameraXActivity extends AppCompatActivity {
- *
- * private OrientationEventListener mOrientationEventListener;
- *
- * @Override
- * protected void onStart() {
- * super.onStart();
- * if (mOrientationEventListener == null) {
- * mOrientationEventListener = new OrientationEventListener(this) {
- * @Override
- * public void onOrientationChanged(int orientation) {
- * if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
- * return;
- * }
- * mVideoCapture.setTargetRotationDegrees(orientation);
- * }
- * };
- * }
- * mOrientationEventListener.enable();
- * }
- *
- * @Override
- * protected void onStop() {
- * super.onStop();
- * mOrientationEventListener.disable();
- * }
- * }
- * }</pre>
- *
- * <p>{@code setTargetRotationDegrees()} cannot rotate the camera image to an arbitrary angle,
- * instead it maps the angle to one of {@link Surface#ROTATION_0},
- * {@link Surface#ROTATION_90}, {@link Surface#ROTATION_180} and {@link Surface#ROTATION_270}
- * as the input of {@link #setTargetRotation(int)}. The rule is as follows:
- * <p>If the input degrees is not in the range [0..359], it will be converted to the equivalent
- * degrees in the range [0..359]. And then take the following mapping based on the input
- * degrees.
- * <p>degrees >= 315 || degrees < 45 -> {@link Surface#ROTATION_0}
- * <p>degrees >= 225 && degrees < 315 -> {@link Surface#ROTATION_90}
- * <p>degrees >= 135 && degrees < 225 -> {@link Surface#ROTATION_180}
- * <p>degrees >= 45 && degrees < 135 -> {@link Surface#ROTATION_270}
- * <p>The rotation value can be obtained by {@link #getTargetRotation()}. This means the
- * rotation previously set by {@link #setTargetRotation(int)} will be overridden by
- * {@code setTargetRotationDegrees(int)}, and vice versa.
- *
- * <p>For a {@link Recorder} output, calling this method has no effect on the ongoing
- * recording, but will affect recordings started after calling this method. The final
- * rotation degrees of the video, including the degrees set by this method and the orientation
- * of the camera sensor, will be reflected by several possibilities, 1) the rotation degrees is
- * written into the video metadata, 2) the video content is directly rotated, 3) both, i.e.
- * rotation metadata and rotated video content which combines to the target rotation. CameraX
- * will choose a strategy according to the use case.
- *
- * @param degrees Desired rotation degree of the output video.
- * @deprecated Use {@link UseCase#snapToSurfaceRotation(int)} and
- * {@link #setTargetRotation(int)} to convert and set the rotation.
- */
- @Deprecated // TODO(b/277999375): Remove API setTargetRotationDegrees.
- public void setTargetRotationDegrees(int degrees) {
- setTargetRotation(snapToSurfaceRotation(within360(degrees)));
- }
-
- /**
* Returns the mirror mode.
*
* <p>The mirror mode is set by {@link VideoCapture.Builder#setMirrorMode(int)}. If not set,
@@ -443,7 +369,6 @@
// that will be sent to the VideoOutput. That should always be retrieved from the StreamSpec
// since that will be the final DynamicRange chosen by the camera based on other use case
// combinations.
- @RestrictTo(Scope.LIBRARY)
@NonNull
public DynamicRange getDynamicRange() {
return getCurrentConfig().hasDynamicRange() ? getCurrentConfig().getDynamicRange() :
@@ -452,7 +377,6 @@
/**
* {@inheritDoc}
- *
*/
@SuppressWarnings("unchecked")
@RestrictTo(Scope.LIBRARY_GROUP)
@@ -480,7 +404,6 @@
/**
* {@inheritDoc}
- *
*/
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@@ -491,7 +414,6 @@
/**
* {@inheritDoc}
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Override
@@ -530,7 +452,6 @@
/**
* {@inheritDoc}
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Override
@@ -551,7 +472,6 @@
/**
* {@inheritDoc}
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@@ -566,7 +486,6 @@
/**
* {@inheritDoc}
- *
*/
@NonNull
@RestrictTo(Scope.LIBRARY_GROUP)
@@ -577,19 +496,11 @@
private void sendTransformationInfoIfReady() {
CameraInternal cameraInternal = getCamera();
- SurfaceRequest surfaceRequest = mSurfaceRequest;
- Rect cropRect = mCropRect;
- if (cameraInternal != null && surfaceRequest != null && cropRect != null) {
+ SurfaceEdge cameraEdge = mCameraEdge;
+ if (cameraInternal != null && cameraEdge != null) {
int relativeRotation = getRelativeRotation(cameraInternal,
isMirroringRequired(cameraInternal));
- int targetRotation = getAppTargetRotation();
- if (mCameraEdge != null) {
- mCameraEdge.setRotationDegrees(relativeRotation);
- } else {
- surfaceRequest.updateTransformationInfo(
- SurfaceRequest.TransformationInfo.of(cropRect, relativeRotation,
- targetRotation, cameraInternal.getHasTransform()));
- }
+ cameraEdge.updateTransformation(relativeRotation, getAppTargetRotation());
}
}
@@ -650,7 +561,7 @@
VideoEncoderInfo videoEncoderInfo = getVideoEncoderInfo(config.getVideoEncoderInfoFinder(),
videoCapabilities, dynamicRange, mediaSpec, resolution, expectedFrameRate);
mCropRect = calculateCropRect(resolution, videoEncoderInfo);
- mNode = createNodeIfNeeded(camera, mCropRect, resolution);
+ mNode = createNodeIfNeeded(camera, mCropRect, resolution, dynamicRange);
// Choose Timebase based on the whether the buffer is copied.
Timebase timebase;
if (mNode != null || !camera.getHasTransform()) {
@@ -663,34 +574,34 @@
// UPTIME when encoder surface is directly sent to camera.
timebase = Timebase.UPTIME;
}
+ StreamSpec updatedStreamSpec =
+ streamSpec.toBuilder().setExpectedFrameRateRange(expectedFrameRate).build();
+ // Make sure the previously created camera edge is cleared before creating a new one.
+ checkState(mCameraEdge == null);
+ mCameraEdge = new SurfaceEdge(
+ VIDEO_CAPTURE,
+ INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
+ updatedStreamSpec,
+ getSensorToBufferTransformMatrix(),
+ camera.getHasTransform(),
+ mCropRect,
+ getRelativeRotation(camera, isMirroringRequired(camera)),
+ getAppTargetRotation(),
+ shouldMirror(camera));
+ mCameraEdge.addOnInvalidatedListener(onSurfaceInvalidated);
if (mNode != null) {
- // Make sure the previously created camera edge is cleared before creating a new one.
- checkState(mCameraEdge == null);
// Update the StreamSpec to use the frame rate range that is not unspecified.
- StreamSpec updatedStreamSpec =
- streamSpec.toBuilder().setExpectedFrameRateRange(expectedFrameRate).build();
- SurfaceEdge cameraEdge = new SurfaceEdge(
- VIDEO_CAPTURE,
- INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
- updatedStreamSpec,
- getSensorToBufferTransformMatrix(),
- camera.getHasTransform(),
- mCropRect,
- getRelativeRotation(camera, isMirroringRequired(camera)),
- shouldMirror(camera));
- cameraEdge.addOnInvalidatedListener(onSurfaceInvalidated);
- mCameraEdge = cameraEdge;
SurfaceProcessorNode.OutConfig outConfig =
- SurfaceProcessorNode.OutConfig.of(cameraEdge);
+ SurfaceProcessorNode.OutConfig.of(mCameraEdge);
SurfaceProcessorNode.In nodeInput = SurfaceProcessorNode.In.of(
- cameraEdge,
+ mCameraEdge,
singletonList(outConfig));
SurfaceProcessorNode.Out nodeOutput = mNode.transform(nodeInput);
SurfaceEdge appEdge = requireNonNull(nodeOutput.get(outConfig));
appEdge.addOnInvalidatedListener(
() -> onAppEdgeInvalidated(appEdge, camera, config, timebase));
mSurfaceRequest = appEdge.createSurfaceRequest(camera);
- mDeferrableSurface = cameraEdge.getDeferrableSurface();
+ mDeferrableSurface = mCameraEdge.getDeferrableSurface();
DeferrableSurface latestDeferrableSurface = mDeferrableSurface;
mDeferrableSurface.getTerminationFuture().addListener(() -> {
// If camera surface is the latest one, it means this pipeline can be abandoned.
@@ -700,12 +611,7 @@
}
}, CameraXExecutors.mainThreadExecutor());
} else {
- mSurfaceRequest = new SurfaceRequest(
- resolution,
- camera,
- dynamicRange,
- expectedFrameRate,
- onSurfaceInvalidated);
+ mSurfaceRequest = mCameraEdge.createSurfaceRequest(camera);
mDeferrableSurface = mSurfaceRequest.getDeferrableSurface();
}
@@ -800,7 +706,6 @@
*
* <p>These values may be overridden by the implementation. They only provide a minimum set of
* defaults that are implementation independent.
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public static final class Defaults implements ConfigProvider<VideoCaptureConfig<?>> {
@@ -941,7 +846,8 @@
@Nullable
private SurfaceProcessorNode createNodeIfNeeded(@NonNull CameraInternal camera,
@NonNull Rect cropRect,
- @NonNull Size resolution) {
+ @NonNull Size resolution,
+ @NonNull DynamicRange dynamicRange) {
if (getEffect() != null
|| shouldEnableSurfaceProcessingByQuirk(camera)
|| shouldCrop(cropRect, resolution)
@@ -949,7 +855,7 @@
Logger.d(TAG, "Surface processing is enabled.");
return new SurfaceProcessorNode(requireNonNull(getCamera()),
getEffect() != null ? getEffect().createSurfaceProcessorInternal() :
- DefaultSurfaceProcessor.Factory.newInstance());
+ DefaultSurfaceProcessor.Factory.newInstance(dynamicRange));
}
return null;
}
@@ -1179,6 +1085,7 @@
Timebase.UPTIME,
mediaSpec.getVideoSpec(),
resolution,
+ dynamicRange,
expectedFrameRate);
return videoEncoderInfoFinder.apply(videoEncoderConfig);
@@ -1447,7 +1354,6 @@
/**
* {@inheritDoc}
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Override
@@ -1458,7 +1364,6 @@
/**
* {@inheritDoc}
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@@ -1530,7 +1435,6 @@
* setTargetAspectRatio is not supported on VideoCapture
*
* <p>To set aspect ratio, see {@link Recorder.Builder#setAspectRatio(int)}.
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@@ -1598,7 +1502,6 @@
* setTargetResolution is not supported on VideoCapture
*
* <p>To set resolution, see {@link Recorder.Builder#setQualitySelector(QualitySelector)}.
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@@ -1681,7 +1584,6 @@
* @return The current Builder.
* @see DynamicRange
*/
- @RestrictTo(Scope.LIBRARY)
@NonNull
@Override
public Builder<T> setDynamicRange(@NonNull DynamicRange dynamicRange) {
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoEncoderSession.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoEncoderSession.java
index c908b8a..1985020 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoEncoderSession.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoEncoderSession.java
@@ -24,6 +24,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
+import androidx.camera.core.DynamicRange;
import androidx.camera.core.Logger;
import androidx.camera.core.SurfaceRequest;
import androidx.camera.core.impl.Timebase;
@@ -288,8 +289,9 @@
@Nullable VideoValidatedEncoderProfilesProxy resolvedEncoderProfiles,
@NonNull MediaSpec mediaSpec,
@NonNull CallbackToFutureAdapter.Completer<Encoder> configureCompleter) {
- VideoMimeInfo videoMimeInfo = resolveVideoMimeInfo(mediaSpec,
- surfaceRequest.getDynamicRange(), resolvedEncoderProfiles);
+ DynamicRange dynamicRange = surfaceRequest.getDynamicRange();
+ VideoMimeInfo videoMimeInfo = resolveVideoMimeInfo(mediaSpec, dynamicRange,
+ resolvedEncoderProfiles);
// The VideoSpec from mediaSpec only contains settings requested by the recorder, but
// the actual settings may need to differ depending on the FPS chosen by the camera.
@@ -299,6 +301,7 @@
timebase,
mediaSpec.getVideoSpec(),
surfaceRequest.getResolution(),
+ dynamicRange,
surfaceRequest.getExpectedFrameRate());
try {
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoConfigUtil.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoConfigUtil.java
index 3d10c5b..ec866e1 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoConfigUtil.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoConfigUtil.java
@@ -16,6 +16,30 @@
package androidx.camera.video.internal.config;
+import static android.media.MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10;
+import static android.media.MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10HDR10;
+import static android.media.MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10HDR10Plus;
+import static android.media.MediaCodecInfo.CodecProfileLevel.AV1ProfileMain8;
+import static android.media.MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvavSe;
+import static android.media.MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheSt;
+import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCProfileMain;
+import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10;
+import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10;
+import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10Plus;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile0;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile1;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile2;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile2HDR;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile2HDR10Plus;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile3;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile3HDR;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile3HDR10Plus;
+
+import static androidx.camera.video.internal.encoder.VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_HLG;
+import static androidx.camera.video.internal.encoder.VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT2020_PQ;
+import static androidx.camera.video.internal.encoder.VideoEncoderDataSpace.ENCODER_DATA_SPACE_BT709;
+import static androidx.camera.video.internal.encoder.VideoEncoderDataSpace.ENCODER_DATA_SPACE_UNSPECIFIED;
+
import android.media.MediaFormat;
import android.util.Range;
import android.util.Rational;
@@ -32,10 +56,13 @@
import androidx.camera.video.VideoSpec;
import androidx.camera.video.internal.VideoValidatedEncoderProfilesProxy;
import androidx.camera.video.internal.encoder.VideoEncoderConfig;
+import androidx.camera.video.internal.encoder.VideoEncoderDataSpace;
import androidx.camera.video.internal.utils.DynamicRangeUtil;
import androidx.core.util.Preconditions;
import androidx.core.util.Supplier;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -46,10 +73,58 @@
public final class VideoConfigUtil {
private static final String TAG = "VideoConfigUtil";
+ private static final Map<String, Map<Integer, VideoEncoderDataSpace>> MIME_TO_DATA_SPACE_MAP =
+ new HashMap<>();
+
// Should not be instantiated.
private VideoConfigUtil() {
}
+ static {
+ //--------------------------------------------------------------------------------------//
+ // Mime and profile level to encoder data space map //
+ //--------------------------------------------------------------------------------------//
+ Map<Integer, VideoEncoderDataSpace> profHevcMap = new HashMap<>();
+ // We treat SDR (main profile) as unspecified. Allow the encoder to use default data space.
+ profHevcMap.put(HEVCProfileMain, ENCODER_DATA_SPACE_UNSPECIFIED);
+ profHevcMap.put(HEVCProfileMain10, ENCODER_DATA_SPACE_BT2020_HLG);
+ profHevcMap.put(HEVCProfileMain10HDR10, ENCODER_DATA_SPACE_BT2020_PQ);
+ profHevcMap.put(HEVCProfileMain10HDR10Plus, ENCODER_DATA_SPACE_BT2020_PQ);
+
+ Map<Integer, VideoEncoderDataSpace> profAv1Map = new HashMap<>();
+ // We treat SDR (main 8 profile) as unspecified. Allow the encoder to use default data
+ // space.
+ profAv1Map.put(AV1ProfileMain8, ENCODER_DATA_SPACE_UNSPECIFIED);
+ profAv1Map.put(AV1ProfileMain10, ENCODER_DATA_SPACE_BT2020_HLG);
+ profAv1Map.put(AV1ProfileMain10HDR10, ENCODER_DATA_SPACE_BT2020_PQ);
+ profAv1Map.put(AV1ProfileMain10HDR10Plus, ENCODER_DATA_SPACE_BT2020_PQ);
+
+ Map<Integer, VideoEncoderDataSpace> profVp9Map = new HashMap<>();
+ // We treat SDR (profile 0) as unspecified. Allow the encoder to use default data space.
+ profVp9Map.put(VP9Profile0, ENCODER_DATA_SPACE_UNSPECIFIED);
+ profVp9Map.put(VP9Profile2, ENCODER_DATA_SPACE_BT2020_HLG);
+ profVp9Map.put(VP9Profile2HDR, ENCODER_DATA_SPACE_BT2020_PQ);
+ profVp9Map.put(VP9Profile2HDR10Plus, ENCODER_DATA_SPACE_BT2020_PQ);
+ // Vp9 4:2:2 profiles
+ profVp9Map.put(VP9Profile1, ENCODER_DATA_SPACE_UNSPECIFIED);
+ profVp9Map.put(VP9Profile3, ENCODER_DATA_SPACE_BT2020_HLG);
+ profVp9Map.put(VP9Profile3HDR, ENCODER_DATA_SPACE_BT2020_PQ);
+ profVp9Map.put(VP9Profile3HDR10Plus, ENCODER_DATA_SPACE_BT2020_PQ);
+
+ Map<Integer, VideoEncoderDataSpace> profDvMap = new HashMap<>();
+ // For Dolby Vision profile 8, we only support 8.4 (10-bit HEVC HLG)
+ profDvMap.put(DolbyVisionProfileDvheSt, ENCODER_DATA_SPACE_BT2020_HLG);
+ // For Dolby Vision profile 9, we only support 9.2 (8-bit AVC SDR BT.709)
+ profDvMap.put(DolbyVisionProfileDvavSe, ENCODER_DATA_SPACE_BT709);
+
+ // Combine all mime type maps
+ MIME_TO_DATA_SPACE_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, profHevcMap);
+ MIME_TO_DATA_SPACE_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, profAv1Map);
+ MIME_TO_DATA_SPACE_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, profVp9Map);
+ MIME_TO_DATA_SPACE_MAP.put(MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION, profDvMap);
+ //--------------------------------------------------------------------------------------//
+ }
+
/**
* Resolves the video mime information into a {@link VideoMimeInfo}.
*
@@ -171,16 +246,18 @@
@NonNull
public static VideoEncoderConfig resolveVideoEncoderConfig(@NonNull VideoMimeInfo videoMimeInfo,
@NonNull Timebase inputTimebase, @NonNull VideoSpec videoSpec,
- @NonNull Size surfaceSize, @NonNull Range<Integer> expectedFrameRateRange) {
+ @NonNull Size surfaceSize, @NonNull DynamicRange dynamicRange,
+ @NonNull Range<Integer> expectedFrameRateRange
+ ) {
Supplier<VideoEncoderConfig> configSupplier;
VideoProfileProxy videoProfile = videoMimeInfo.getCompatibleVideoProfile();
if (videoProfile != null) {
configSupplier = new VideoEncoderConfigVideoProfileResolver(
videoMimeInfo.getMimeType(), inputTimebase, videoSpec, surfaceSize,
- videoProfile, expectedFrameRateRange);
+ videoProfile, dynamicRange, expectedFrameRateRange);
} else {
configSupplier = new VideoEncoderConfigDefaultResolver(videoMimeInfo.getMimeType(),
- inputTimebase, videoSpec, surfaceSize, expectedFrameRateRange);
+ inputTimebase, videoSpec, surfaceSize, dynamicRange, expectedFrameRateRange);
}
return configSupplier.get();
@@ -188,10 +265,13 @@
static int scaleAndClampBitrate(
int baseBitrate,
+ int actualBitDepth, int baseBitDepth,
int actualFrameRate, int baseFrameRate,
int actualWidth, int baseWidth,
int actualHeight, int baseHeight,
@NonNull Range<Integer> clampedRange) {
+ // Scale bit depth to match new bit depth
+ Rational bitDepthRatio = new Rational(actualBitDepth, baseBitDepth);
// Scale bitrate to match current frame rate
Rational frameRateRatio = new Rational(actualFrameRate, baseFrameRate);
// Scale bitrate depending on number of actual pixels relative to profile's
@@ -201,14 +281,15 @@
Rational widthRatio = new Rational(actualWidth, baseWidth);
Rational heightRatio = new Rational(actualHeight, baseHeight);
int resolvedBitrate =
- (int) (baseBitrate * frameRateRatio.doubleValue() * widthRatio.doubleValue()
- * heightRatio.doubleValue());
+ (int) (baseBitrate * bitDepthRatio.doubleValue() * frameRateRatio.doubleValue()
+ * widthRatio.doubleValue() * heightRatio.doubleValue());
String debugString = "";
if (Logger.isDebugEnabled(TAG)) {
- debugString = String.format("Base Bitrate(%dbps) * Frame Rate Ratio(%d / %d) * Width "
- + "Ratio(%d / %d) * Height Ratio(%d / %d) = %d", baseBitrate,
- actualFrameRate,
+ debugString = String.format("Base Bitrate(%dbps) * Bit Depth Ratio (%d / %d) * "
+ + "Frame Rate Ratio(%d / %d) * Width Ratio(%d / %d) * "
+ + "Height Ratio(%d / %d) = %d", baseBitrate,
+ actualBitDepth, baseBitDepth, actualFrameRate,
baseFrameRate, actualWidth, baseWidth, actualHeight, baseHeight,
resolvedBitrate);
}
@@ -224,4 +305,27 @@
Logger.d(TAG, debugString);
return resolvedBitrate;
}
+
+ /**
+ * Returns the encoder data space for the given mime and profile.
+ *
+ * @return The data space for the given mime type and profile, or
+ * {@link VideoEncoderDataSpace#ENCODER_DATA_SPACE_UNSPECIFIED} if the profile represents SDR or is unsupported.
+ */
+ @NonNull
+ public static VideoEncoderDataSpace mimeAndProfileToEncoderDataSpace(@NonNull String mimeType,
+ int codecProfileLevel) {
+ Map<Integer, VideoEncoderDataSpace> profileToDataSpaceMap =
+ MIME_TO_DATA_SPACE_MAP.get(mimeType);
+ if (profileToDataSpaceMap != null) {
+ VideoEncoderDataSpace dataSpace = profileToDataSpaceMap.get(codecProfileLevel);
+ if (dataSpace != null) {
+ return dataSpace;
+ }
+ }
+
+ Logger.w(TAG, String.format("Unsupported mime type %s or profile level %d. Data space is "
+ + "unspecified.", mimeType, codecProfileLevel));
+ return ENCODER_DATA_SPACE_UNSPECIFIED;
+ }
}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolver.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolver.java
index 7d09ed2..a77d6f2 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolver.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolver.java
@@ -21,11 +21,14 @@
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
+import androidx.camera.core.DynamicRange;
import androidx.camera.core.Logger;
import androidx.camera.core.SurfaceRequest;
import androidx.camera.core.impl.Timebase;
import androidx.camera.video.VideoSpec;
import androidx.camera.video.internal.encoder.VideoEncoderConfig;
+import androidx.camera.video.internal.encoder.VideoEncoderDataSpace;
+import androidx.camera.video.internal.utils.DynamicRangeUtil;
import androidx.core.util.Supplier;
import java.util.Objects;
@@ -45,6 +48,7 @@
private static final Size VIDEO_SIZE_BASE = new Size(1280, 720);
private static final int VIDEO_FRAME_RATE_BASE = 30;
static final int VIDEO_FRAME_RATE_FIXED_DEFAULT = 30;
+ private static final int VIDEO_BIT_DEPTH_BASE = 8;
private static final Range<Integer> VALID_FRAME_RATE_RANGE = new Range<>(1, 60);
private final String mMimeType;
@@ -52,6 +56,7 @@
private final Timebase mInputTimebase;
private final VideoSpec mVideoSpec;
private final Size mSurfaceSize;
+ private final DynamicRange mDynamicRange;
private final Range<Integer> mExpectedFrameRateRange;
/**
@@ -63,6 +68,7 @@
* be used with the video encoder.
* @param surfaceSize The size of the surface required by the camera for the video
* encoder.
+ * @param dynamicRange The dynamic range of input frames.
* @param expectedFrameRateRange The expected source frame rate range. This should act as an
* envelope for any frame rate calculated from {@code videoSpec
* } and {@code videoProfile} since the source should not
@@ -73,11 +79,13 @@
*/
public VideoEncoderConfigDefaultResolver(@NonNull String mimeType,
@NonNull Timebase inputTimebase, @NonNull VideoSpec videoSpec,
- @NonNull Size surfaceSize, @NonNull Range<Integer> expectedFrameRateRange) {
+ @NonNull Size surfaceSize, @NonNull DynamicRange dynamicRange,
+ @NonNull Range<Integer> expectedFrameRateRange) {
mMimeType = mimeType;
mInputTimebase = inputTimebase;
mVideoSpec = videoSpec;
mSurfaceSize = surfaceSize;
+ mDynamicRange = dynamicRange;
mExpectedFrameRateRange = expectedFrameRateRange;
}
@@ -92,17 +100,25 @@
// We have no other information to go off of. Scale based on fallback defaults.
int resolvedBitrate = VideoConfigUtil.scaleAndClampBitrate(
VIDEO_BITRATE_BASE,
+ mDynamicRange.getBitDepth(), VIDEO_BIT_DEPTH_BASE,
resolvedFrameRate, VIDEO_FRAME_RATE_BASE,
mSurfaceSize.getWidth(), VIDEO_SIZE_BASE.getWidth(),
mSurfaceSize.getHeight(), VIDEO_SIZE_BASE.getHeight(),
videoSpecBitrateRange);
+ int resolvedProfile = DynamicRangeUtil.dynamicRangeToCodecProfileLevelForMime(
+ mMimeType, mDynamicRange);
+ VideoEncoderDataSpace dataSpace =
+ VideoConfigUtil.mimeAndProfileToEncoderDataSpace(mMimeType, resolvedProfile);
+
return VideoEncoderConfig.builder()
.setMimeType(mMimeType)
.setInputTimebase(mInputTimebase)
.setResolution(mSurfaceSize)
.setBitrate(resolvedBitrate)
.setFrameRate(resolvedFrameRate)
+ .setProfile(resolvedProfile)
+ .setDataSpace(dataSpace)
.build();
}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolver.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolver.java
index dc374ae..974ef81 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolver.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolver.java
@@ -21,12 +21,14 @@
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
+import androidx.camera.core.DynamicRange;
import androidx.camera.core.Logger;
import androidx.camera.core.SurfaceRequest;
import androidx.camera.core.impl.EncoderProfilesProxy.VideoProfileProxy;
import androidx.camera.core.impl.Timebase;
import androidx.camera.video.VideoSpec;
import androidx.camera.video.internal.encoder.VideoEncoderConfig;
+import androidx.camera.video.internal.encoder.VideoEncoderDataSpace;
import androidx.core.util.Supplier;
import java.util.Objects;
@@ -38,7 +40,6 @@
*/
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
public class VideoEncoderConfigVideoProfileResolver implements Supplier<VideoEncoderConfig> {
-
private static final String TAG = "VidEncVdPrflRslvr";
private final String mMimeType;
@@ -46,6 +47,7 @@
private final VideoSpec mVideoSpec;
private final Size mSurfaceSize;
private final VideoProfileProxy mVideoProfile;
+ private final DynamicRange mDynamicRange;
private final Range<Integer> mExpectedFrameRateRange;
/**
@@ -58,6 +60,7 @@
* @param surfaceSize The size of the surface required by the camera for the video encoder.
* @param videoProfile The {@link VideoProfileProxy} used to resolve automatic and range
* settings.
+ * @param dynamicRange The dynamic range of input frames.
* @param expectedFrameRateRange The expected source frame rate range. This should act as an
* envelope for any frame rate calculated from {@code videoSpec}
* and {@code videoProfile} since the source should not
@@ -71,12 +74,14 @@
@NonNull VideoSpec videoSpec,
@NonNull Size surfaceSize,
@NonNull VideoProfileProxy videoProfile,
+ @NonNull DynamicRange dynamicRange,
@NonNull Range<Integer> expectedFrameRateRange) {
mMimeType = mimeType;
mInputTimebase = inputTimebase;
mVideoSpec = videoSpec;
mSurfaceSize = surfaceSize;
mVideoProfile = videoProfile;
+ mDynamicRange = dynamicRange;
mExpectedFrameRateRange = expectedFrameRateRange;
}
@@ -90,17 +95,24 @@
Logger.d(TAG, "Using resolved VIDEO bitrate from EncoderProfiles");
int resolvedBitrate = VideoConfigUtil.scaleAndClampBitrate(
mVideoProfile.getBitrate(),
+ mDynamicRange.getBitDepth(), mVideoProfile.getBitDepth(),
resolvedFrameRate, mVideoProfile.getFrameRate(),
mSurfaceSize.getWidth(), mVideoProfile.getWidth(),
mSurfaceSize.getHeight(), mVideoProfile.getHeight(),
videoSpecBitrateRange);
+ int resolvedProfile = mVideoProfile.getProfile();
+ VideoEncoderDataSpace dataSpace =
+ VideoConfigUtil.mimeAndProfileToEncoderDataSpace(mMimeType, resolvedProfile);
+
return VideoEncoderConfig.builder()
.setMimeType(mMimeType)
.setInputTimebase(mInputTimebase)
.setResolution(mSurfaceSize)
.setBitrate(resolvedBitrate)
.setFrameRate(resolvedFrameRate)
+ .setProfile(resolvedProfile)
+ .setDataSpace(dataSpace)
.build();
}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/encoder/VideoEncoderConfig.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/encoder/VideoEncoderConfig.java
index dfe5a49..42e3618 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/encoder/VideoEncoderConfig.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/encoder/VideoEncoderConfig.java
@@ -45,7 +45,8 @@
return new AutoValue_VideoEncoderConfig.Builder()
.setProfile(EncoderConfig.CODEC_PROFILE_NONE)
.setIFrameInterval(VIDEO_INTRA_FRAME_INTERVAL_DEFAULT)
- .setColorFormat(VIDEO_COLOR_FORMAT_DEFAULT);
+ .setColorFormat(VIDEO_COLOR_FORMAT_DEFAULT)
+ .setDataSpace(VideoEncoderDataSpace.ENCODER_DATA_SPACE_UNSPECIFIED);
}
@Override
@@ -66,6 +67,10 @@
/** Gets the color format. */
public abstract int getColorFormat();
+ /** Gets the color data space. */
+ @NonNull
+ public abstract VideoEncoderDataSpace getDataSpace();
+
/** Gets the frame rate. */
public abstract int getFrameRate();
@@ -89,6 +94,16 @@
if (getProfile() != EncoderConfig.CODEC_PROFILE_NONE) {
format.setInteger(MediaFormat.KEY_PROFILE, getProfile());
}
+ VideoEncoderDataSpace dataSpace = getDataSpace();
+ if (dataSpace.getStandard() != VideoEncoderDataSpace.VIDEO_COLOR_STANDARD_UNSPECIFIED) {
+ format.setInteger(MediaFormat.KEY_COLOR_STANDARD, dataSpace.getStandard());
+ }
+ if (dataSpace.getTransfer() != VideoEncoderDataSpace.VIDEO_COLOR_TRANSFER_UNSPECIFIED) {
+ format.setInteger(MediaFormat.KEY_COLOR_TRANSFER, dataSpace.getTransfer());
+ }
+ if (dataSpace.getRange() != VideoEncoderDataSpace.VIDEO_COLOR_RANGE_UNSPECIFIED) {
+ format.setInteger(MediaFormat.KEY_COLOR_RANGE, dataSpace.getRange());
+ }
return format;
}
@@ -119,6 +134,10 @@
@NonNull
public abstract Builder setColorFormat(int colorFormat);
+ /** Sets the color data space. */
+ @NonNull
+ public abstract Builder setDataSpace(@NonNull VideoEncoderDataSpace dataSpace);
+
/** Sets the frame rate. */
@NonNull
public abstract Builder setFrameRate(int frameRate);
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/encoder/VideoEncoderDataSpace.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/encoder/VideoEncoderDataSpace.java
new file mode 100644
index 0000000..4fd914b
--- /dev/null
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/encoder/VideoEncoderDataSpace.java
@@ -0,0 +1,117 @@
+/*
+ * 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.video.internal.encoder;
+
+import android.media.MediaFormat;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+
+import com.google.auto.value.AutoValue;
+
+/**
+ * Defines the three components of colors used by an encoder.
+ *
+ * <p>This is the encoder equivalent of {@link android.hardware.DataSpace}, and should be used to
+ * communicate the {@link MediaFormat} keys needed by the encoder.
+ */
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+@AutoValue
+public abstract class VideoEncoderDataSpace {
+
+ /** Standard characteristics that are unknown or specified by the device defaults. */
+ public static final int VIDEO_COLOR_STANDARD_UNSPECIFIED = 0;
+
+ /** Color transfer function that is unknown or specified by the device defaults. */
+ public static final int VIDEO_COLOR_TRANSFER_UNSPECIFIED = 0;
+
+ /** Range characteristics that are unknown or specified by the device defaults. */
+ public static final int VIDEO_COLOR_RANGE_UNSPECIFIED = 0;
+
+ /** A data space where all components are unspecified. */
+ public static final VideoEncoderDataSpace ENCODER_DATA_SPACE_UNSPECIFIED =
+ create(VIDEO_COLOR_STANDARD_UNSPECIFIED,
+ VIDEO_COLOR_TRANSFER_UNSPECIFIED,
+ VIDEO_COLOR_RANGE_UNSPECIFIED);
+
+ /**
+ * Color standard BT.709 with SDR video transfer function.
+ *
+ * <p>This mirrors the data space from {@link android.hardware.DataSpace#DATASPACE_BT709}.
+ */
+ public static final VideoEncoderDataSpace ENCODER_DATA_SPACE_BT709 =
+ create(MediaFormat.COLOR_STANDARD_BT709,
+ MediaFormat.COLOR_TRANSFER_SDR_VIDEO,
+ MediaFormat.COLOR_RANGE_LIMITED);
+
+ /**
+ * Color standard BT.2020 with HLG transfer function.
+ *
+ * <p>This mirrors the data space from {@link android.hardware.DataSpace#DATASPACE_BT2020_HLG}.
+ */
+ public static final VideoEncoderDataSpace ENCODER_DATA_SPACE_BT2020_HLG =
+ create(MediaFormat.COLOR_STANDARD_BT2020,
+ MediaFormat.COLOR_TRANSFER_HLG,
+ MediaFormat.COLOR_RANGE_FULL);
+
+ /**
+ * Color standard BT.2020 with PQ (ST2084) transfer function.
+ *
+ * <p>This mirrors the data space from {@link android.hardware.DataSpace#DATASPACE_BT2020_PQ}.
+ */
+ public static final VideoEncoderDataSpace ENCODER_DATA_SPACE_BT2020_PQ =
+ create(MediaFormat.COLOR_STANDARD_BT2020,
+ MediaFormat.COLOR_TRANSFER_ST2084,
+ MediaFormat.COLOR_RANGE_FULL);
+
+ // Restrict constructor to same package
+ VideoEncoderDataSpace() {
+ }
+
+ /** Creates a data space from the three primaries. */
+ @NonNull
+ public static VideoEncoderDataSpace create(int standard, int transfer, int range) {
+ return new AutoValue_VideoEncoderDataSpace(standard, transfer, range);
+ }
+
+ /**
+ * Returns the color standard.
+ *
+ * <p>This will be one of {@link #VIDEO_COLOR_STANDARD_UNSPECIFIED} or one of the color
+ * standard constants defined in {@link MediaFormat}, such as
+ * {@link MediaFormat#COLOR_STANDARD_BT2020}.
+ */
+ public abstract int getStandard();
+
+ /**
+ * Returns the color transfer function.
+ *
+ * <p>This will be one of {@link #VIDEO_COLOR_TRANSFER_UNSPECIFIED} or one of the color
+ * transfer function constants defined in {@link MediaFormat}, such as
+ * {@link MediaFormat#COLOR_TRANSFER_HLG}.
+ */
+ public abstract int getTransfer();
+
+ /**
+ * Returns the color range.
+ *
+ * <p>This will be one of {@link #VIDEO_COLOR_RANGE_UNSPECIFIED} or one of the color
+ * range constants defined in {@link MediaFormat}, such as
+ * {@link MediaFormat#COLOR_RANGE_LIMITED}.
+ */
+ public abstract int getRange();
+}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/utils/DynamicRangeUtil.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/utils/DynamicRangeUtil.java
index 0f27e50..3cd26a3 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/utils/DynamicRangeUtil.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/utils/DynamicRangeUtil.java
@@ -21,10 +21,26 @@
import static android.media.EncoderProfiles.VideoProfile.HDR_HDR10PLUS;
import static android.media.EncoderProfiles.VideoProfile.HDR_HLG;
import static android.media.EncoderProfiles.VideoProfile.HDR_NONE;
+import static android.media.MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10;
+import static android.media.MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10HDR10;
+import static android.media.MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10HDR10Plus;
+import static android.media.MediaCodecInfo.CodecProfileLevel.AV1ProfileMain8;
+import static android.media.MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvavSe;
+import static android.media.MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheSt;
+import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCProfileMain;
+import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10;
+import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10;
+import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10Plus;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile0;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile2;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile2HDR;
+import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile2HDR10Plus;
import static androidx.camera.core.DynamicRange.BIT_DEPTH_10_BIT;
import static androidx.camera.core.DynamicRange.BIT_DEPTH_8_BIT;
import static androidx.camera.core.DynamicRange.BIT_DEPTH_UNSPECIFIED;
+import static androidx.camera.core.DynamicRange.DOLBY_VISION_10_BIT;
+import static androidx.camera.core.DynamicRange.DOLBY_VISION_8_BIT;
import static androidx.camera.core.DynamicRange.ENCODING_DOLBY_VISION;
import static androidx.camera.core.DynamicRange.ENCODING_HDR10;
import static androidx.camera.core.DynamicRange.ENCODING_HDR10_PLUS;
@@ -32,15 +48,22 @@
import static androidx.camera.core.DynamicRange.ENCODING_HLG;
import static androidx.camera.core.DynamicRange.ENCODING_SDR;
import static androidx.camera.core.DynamicRange.ENCODING_UNSPECIFIED;
+import static androidx.camera.core.DynamicRange.HDR10_10_BIT;
+import static androidx.camera.core.DynamicRange.HDR10_PLUS_10_BIT;
+import static androidx.camera.core.DynamicRange.HLG_10_BIT;
+import static androidx.camera.core.DynamicRange.SDR;
import static androidx.camera.core.impl.EncoderProfilesProxy.VideoProfileProxy.BIT_DEPTH_10;
import static androidx.camera.core.impl.EncoderProfilesProxy.VideoProfileProxy.BIT_DEPTH_8;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
+import android.media.MediaFormat;
+
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.camera.core.DynamicRange;
+import androidx.camera.core.impl.EncoderProfilesProxy;
import java.util.Collections;
import java.util.HashMap;
@@ -53,10 +76,11 @@
*/
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
public class DynamicRangeUtil {
-
public static final Map<Integer, Set<Integer>> DR_TO_VP_BIT_DEPTH_MAP = new HashMap<>();
public static final Map<Integer, Set<Integer>> DR_TO_VP_FORMAT_MAP = new HashMap<>();
public static final Map<Integer, Integer> VP_TO_DR_FORMAT_MAP = new HashMap<>();
+ private static final Map<String, Map<DynamicRange, Integer>> MIME_TO_DEFAULT_PROFILE_LEVEL_MAP =
+ new HashMap<>();
private DynamicRangeUtil() {
}
@@ -86,6 +110,46 @@
VP_TO_DR_FORMAT_MAP.put(HDR_HDR10, ENCODING_HDR10);
VP_TO_DR_FORMAT_MAP.put(HDR_HDR10PLUS, ENCODING_HDR10_PLUS);
VP_TO_DR_FORMAT_MAP.put(HDR_DOLBY_VISION, ENCODING_DOLBY_VISION);
+
+ //--------------------------------------------------------------------------------------//
+ // Default CodecProfileLevel mappings from //
+ // frameworks/av/media/codec2/sfplugin/utils/Codec2Mapper.cpp //
+ //--------------------------------------------------------------------------------------//
+ // DynamicRange encodings to HEVC profiles
+ Map<DynamicRange, Integer> hevcMap = new HashMap<>();
+ hevcMap.put(SDR, HEVCProfileMain);
+ hevcMap.put(HLG_10_BIT, HEVCProfileMain10);
+ hevcMap.put(HDR10_10_BIT, HEVCProfileMain10HDR10);
+ hevcMap.put(HDR10_PLUS_10_BIT, HEVCProfileMain10HDR10Plus);
+
+ // DynamicRange encodings to AV1 profiles for YUV 4:2:0 chroma subsampling
+ Map<DynamicRange, Integer> av1420Map = new HashMap<>();
+ av1420Map.put(SDR, AV1ProfileMain8);
+ av1420Map.put(HLG_10_BIT, AV1ProfileMain10);
+ av1420Map.put(HDR10_10_BIT, AV1ProfileMain10HDR10);
+ av1420Map.put(HDR10_PLUS_10_BIT, AV1ProfileMain10HDR10Plus);
+
+ // DynamicRange encodings to VP9 profile for YUV 4:2:0 chroma subsampling
+ Map<DynamicRange, Integer> vp9420Map = new HashMap<>();
+ vp9420Map.put(SDR, VP9Profile0);
+ vp9420Map.put(HLG_10_BIT, VP9Profile2);
+ vp9420Map.put(HDR10_10_BIT, VP9Profile2HDR);
+ vp9420Map.put(HDR10_PLUS_10_BIT, VP9Profile2HDR10Plus);
+
+ // Dolby vision encodings to dolby vision profiles
+ Map<DynamicRange, Integer> dvMap = new HashMap<>();
+ // Taken from the (now deprecated) Dolby Vision Profile Specification 1.3.3
+ // DV Profile 8 (10-bit HEVC)
+ dvMap.put(DOLBY_VISION_10_BIT, DolbyVisionProfileDvheSt);
+ // DV Profile 9 (8-bit AVC)
+ dvMap.put(DOLBY_VISION_8_BIT, DolbyVisionProfileDvavSe);
+
+ // Combine all mime type maps
+ MIME_TO_DEFAULT_PROFILE_LEVEL_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, hevcMap);
+ MIME_TO_DEFAULT_PROFILE_LEVEL_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, av1420Map);
+ MIME_TO_DEFAULT_PROFILE_LEVEL_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, vp9420Map);
+ MIME_TO_DEFAULT_PROFILE_LEVEL_MAP.put(MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION, dvMap);
+ //--------------------------------------------------------------------------------------//
}
/**
@@ -126,4 +190,26 @@
}
return bitDepths;
}
+
+ /**
+ * Returns a codec profile level for a given mime type and dynamic range.
+ *
+ * <p>If the mime type or dynamic range is not supported, returns
+ * {@link EncoderProfilesProxy#CODEC_PROFILE_NONE}.
+ *
+ * <p>Only fully-specified dynamic ranges are supported. All other dynamic ranges will return
+ * {@link EncoderProfilesProxy#CODEC_PROFILE_NONE}.
+ */
+ public static int dynamicRangeToCodecProfileLevelForMime(@NonNull String mimeType,
+ @NonNull DynamicRange dynamicRange) {
+ Map<DynamicRange, Integer> hdrToProfile = MIME_TO_DEFAULT_PROFILE_LEVEL_MAP.get(mimeType);
+ if (hdrToProfile != null) {
+ Integer profile = hdrToProfile.get(dynamicRange);
+ if (profile != null) {
+ return profile;
+ }
+ }
+
+ return EncoderProfilesProxy.CODEC_PROFILE_NONE;
+ }
}
diff --git a/camera/camera-video/src/test/java/androidx/camera/video/QualitySelectorTest.kt b/camera/camera-video/src/test/java/androidx/camera/video/QualitySelectorTest.kt
index d65651c..dd06e80 100644
--- a/camera/camera-video/src/test/java/androidx/camera/video/QualitySelectorTest.kt
+++ b/camera/camera-video/src/test/java/androidx/camera/video/QualitySelectorTest.kt
@@ -42,6 +42,7 @@
@RunWith(RobolectricTestRunner::class)
@DoNotInstrument
+@Suppress("DEPRECATION")
@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
class QualitySelectorTest {
diff --git a/camera/camera-video/src/test/java/androidx/camera/video/internal/encoder/VideoEncoderDataSpaceTest.kt b/camera/camera-video/src/test/java/androidx/camera/video/internal/encoder/VideoEncoderDataSpaceTest.kt
new file mode 100644
index 0000000..a7ef9c0
--- /dev/null
+++ b/camera/camera-video/src/test/java/androidx/camera/video/internal/encoder/VideoEncoderDataSpaceTest.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.video.internal.encoder
+
+import android.media.MediaFormat
+import android.os.Build
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+
+private const val TEST_COLOR_STANDARD = MediaFormat.COLOR_STANDARD_BT2020
+private const val TEST_TRANSFER_FN = MediaFormat.COLOR_TRANSFER_HLG
+private const val TEST_COLOR_RANGE = MediaFormat.COLOR_RANGE_LIMITED
+
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class VideoEncoderDataSpaceTest {
+
+ @Test
+ fun canRetrieveFields() {
+ val dataSpace = VideoEncoderDataSpace.create(
+ TEST_COLOR_STANDARD,
+ TEST_TRANSFER_FN,
+ TEST_COLOR_RANGE
+ )
+
+ assertThat(dataSpace.standard).isEqualTo(TEST_COLOR_STANDARD)
+ assertThat(dataSpace.transfer).isEqualTo(TEST_TRANSFER_FN)
+ assertThat(dataSpace.range).isEqualTo(TEST_COLOR_RANGE)
+ }
+}
\ No newline at end of file
diff --git a/camera/camera-view/lint.xml b/camera/camera-view/lint.xml
deleted file mode 100644
index 0843ecf..0000000
--- a/camera/camera-view/lint.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
- <!-- Disable NewApi lint check temporarily for unit tests.
- This file can be removed once b/200599470 is resolved. -->
- <issue id="NewApi">
- <ignore path="src/test/**" />
- </issue>
-</lint>
\ No newline at end of file
diff --git a/camera/camera-view/src/test/java/androidx/camera/view/FakeProcessCameraProviderWrapper.kt b/camera/camera-view/src/test/java/androidx/camera/view/FakeProcessCameraProviderWrapper.kt
index d33b63e..082b4f4 100644
--- a/camera/camera-view/src/test/java/androidx/camera/view/FakeProcessCameraProviderWrapper.kt
+++ b/camera/camera-view/src/test/java/androidx/camera/view/FakeProcessCameraProviderWrapper.kt
@@ -16,6 +16,7 @@
package androidx.camera.view
+import androidx.annotation.RequiresApi
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.UseCase
@@ -31,6 +32,7 @@
* @param bindToLifecycleException the [Exception] to throw when [bindToLifecycle] is called.
* If null, [bindToLifecycle] will not throw any error.
*/
+@RequiresApi(21)
class FakeProcessCameraProviderWrapper(
private val camera: Camera = FakeCamera(),
private val bindToLifecycleException: Throwable? = null
@@ -68,4 +70,4 @@
override fun shutdown(): ListenableFuture<Void> {
return Futures.immediateFuture(null)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-view/src/test/java/androidx/camera/view/PreviewTransformationTest.kt b/camera/camera-view/src/test/java/androidx/camera/view/PreviewTransformationTest.kt
index bacd6d4..27bbd0d 100644
--- a/camera/camera-view/src/test/java/androidx/camera/view/PreviewTransformationTest.kt
+++ b/camera/camera-view/src/test/java/androidx/camera/view/PreviewTransformationTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.view
import android.graphics.Rect
@@ -22,6 +24,7 @@
import android.util.Size
import android.view.Surface
import android.view.View
+import androidx.annotation.RequiresApi
import androidx.camera.core.SurfaceRequest
import androidx.camera.core.impl.ImageOutputConfig.ROTATION_NOT_SPECIFIED
import androidx.camera.core.impl.ImageOutputConfig.RotationValue
@@ -489,4 +492,4 @@
)
mPreviewTransform.transformView(previewViewSize, LayoutDirection.LTR, mView)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-view/src/test/java/androidx/camera/view/internal/compat/quirk/DeviceQuirks.java b/camera/camera-view/src/test/java/androidx/camera/view/internal/compat/quirk/DeviceQuirks.java
index d9f5964..62f2027 100644
--- a/camera/camera-view/src/test/java/androidx/camera/view/internal/compat/quirk/DeviceQuirks.java
+++ b/camera/camera-view/src/test/java/androidx/camera/view/internal/compat/quirk/DeviceQuirks.java
@@ -19,6 +19,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.camera.core.impl.Quirk;
import java.util.List;
@@ -46,6 +47,7 @@
* @return A device {@link Quirk} instance of the provided type, or {@code null} if it isn't
* found.
*/
+ @RequiresApi(21)
@SuppressWarnings("unchecked")
@Nullable
public static <T extends Quirk> T get(@NonNull final Class<T> quirkClass) {
diff --git a/camera/camera-view/src/test/java/androidx/camera/view/transform/TransformTestUtils.java b/camera/camera-view/src/test/java/androidx/camera/view/transform/TransformTestUtils.java
index 1843b7a..5c860cb 100644
--- a/camera/camera-view/src/test/java/androidx/camera/view/transform/TransformTestUtils.java
+++ b/camera/camera-view/src/test/java/androidx/camera/view/transform/TransformTestUtils.java
@@ -18,6 +18,7 @@
import android.graphics.Rect;
+import androidx.annotation.RequiresApi;
import androidx.camera.core.ImageProxy;
import androidx.camera.testing.fakes.FakeImageInfo;
import androidx.camera.testing.fakes.FakeImageProxy;
@@ -26,6 +27,7 @@
/**
* Shared code for transform tests.
*/
+@RequiresApi(21)
class TransformTestUtils {
static ImageProxy createFakeImageProxy(int width, int height,
diff --git a/camera/camera-viewfinder/lint.xml b/camera/camera-viewfinder/lint.xml
deleted file mode 100644
index bf94f9f..0000000
--- a/camera/camera-viewfinder/lint.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
- <!-- Disable NewApi lint check temporarily for unit tests.
- This file can be removed once b/200599470 is resolved. -->
- <issue id="NewApi">
- <ignore path="src/test/**" />
- </issue>
-
- <issue id="UnsafeOptInUsageError">
- <ignore path="src/main/**" />
- </issue>
-</lint>
\ No newline at end of file
diff --git a/camera/camera-viewfinder/src/test/java/androidx/camera/viewfinder/ViewfinderTransformationTest.kt b/camera/camera-viewfinder/src/test/java/androidx/camera/viewfinder/ViewfinderTransformationTest.kt
index f24e5cd..31fc6d0 100644
--- a/camera/camera-viewfinder/src/test/java/androidx/camera/viewfinder/ViewfinderTransformationTest.kt
+++ b/camera/camera-viewfinder/src/test/java/androidx/camera/viewfinder/ViewfinderTransformationTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:RequiresApi(21)
+
package androidx.camera.viewfinder
import android.graphics.Rect
@@ -22,6 +24,7 @@
import android.util.Size
import android.view.Surface
import android.view.View
+import androidx.annotation.RequiresApi
import androidx.camera.viewfinder.CameraViewfinder.ScaleType
import androidx.camera.viewfinder.internal.transform.Rotation.RotationValue
import androidx.camera.viewfinder.internal.transform.TransformationInfo
@@ -444,4 +447,4 @@
)
mPreviewTransform.transformView(previewViewSize, LayoutDirection.LTR, mView)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-viewfinder/src/test/java/androidx/camera/viewfinder/internal/quirk/DeviceQuirks.java b/camera/camera-viewfinder/src/test/java/androidx/camera/viewfinder/internal/quirk/DeviceQuirks.java
index f39ee16..18c9d1e 100644
--- a/camera/camera-viewfinder/src/test/java/androidx/camera/viewfinder/internal/quirk/DeviceQuirks.java
+++ b/camera/camera-viewfinder/src/test/java/androidx/camera/viewfinder/internal/quirk/DeviceQuirks.java
@@ -19,6 +19,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import java.util.List;
@@ -45,6 +46,7 @@
* @return A device {@link Quirk} instance of the provided type, or {@code null} if it isn't
* found.
*/
+ @RequiresApi(21)
@SuppressWarnings("unchecked")
@Nullable
public static <T extends Quirk> T get(@NonNull final Class<T> quirkClass) {
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
index 09c42a4..a7977aa 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
@@ -17,15 +17,14 @@
package androidx.camera.integration.camera2.pipe
import android.Manifest
-import android.hardware.camera2.CameraCharacteristics
import android.os.Bundle
import android.os.Trace
import android.util.Log
+import android.util.Size
import android.view.View
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.CameraId
import androidx.camera.camera2.pipe.CameraPipe
-import kotlinx.coroutines.runBlocking
/**
* This is the main activity for the CameraPipe test application.
@@ -34,9 +33,10 @@
private lateinit var cameraPipe: CameraPipe
private lateinit var dataVisualizations: DataVisualizations
private lateinit var ui: CameraPipeUi
+ private lateinit var cameraIdGroups: List<List<CameraId>>
- private var lastCameraId: CameraId? = null
- private var currentCamera: SimpleCamera? = null
+ private var lastCameraIds: List<CameraId>? = null
+ private var currentCameras: List<SimpleCamera>? = null
private var operatingMode: CameraGraph.OperatingMode = CameraGraph.OperatingMode.NORMAL
override fun onCreate(savedInstanceState: Bundle?) {
@@ -58,6 +58,10 @@
ui.switchButton.setOnClickListener { startNextCamera() }
Trace.endSection()
+ val cameraDevices = cameraPipe.cameras()
+ cameraIdGroups = cameraDevices.awaitCameraIds()!!.map { listOf(it) } +
+ cameraDevices.awaitConcurrentCameraIds()!!.filter { it.size <= 2 }.map { it.toList() }
+
// TODO: Update this to work with newer versions of the visualizations and to accept
// the CameraPipeUi object as a parameter.
dataVisualizations = DataVisualizations(this)
@@ -73,11 +77,13 @@
Manifest.permission.RECORD_AUDIO
)
) {
- val camera = currentCamera
- if (camera == null) {
+ val cameras = currentCameras
+ if (cameras == null) {
startNextCamera()
} else {
- camera.start()
+ for (camera in cameras) {
+ camera.start()
+ }
}
}
}
@@ -85,25 +91,41 @@
override fun onResume() {
super.onResume()
Log.i("CXCP-App", "Activity onResume")
- currentCamera?.resume()
+ currentCameras?.let {
+ for (camera in it) {
+ camera.resume()
+ }
+ }
}
override fun onPause() {
super.onPause()
Log.i("CXCP-App", "Activity onPause")
- currentCamera?.pause()
+ currentCameras?.let {
+ for (camera in it) {
+ camera.pause()
+ }
+ }
}
override fun onStop() {
super.onStop()
Log.i("CXCP-App", "Activity onStop")
- currentCamera?.stop()
+ currentCameras?.let {
+ for (camera in it) {
+ camera.stop()
+ }
+ }
}
override fun onDestroy() {
super.onDestroy()
Log.i("CXCP-App", "Activity onDestroy")
- currentCamera?.close()
+ currentCameras?.let {
+ for (camera in it) {
+ camera.close()
+ }
+ }
dataVisualizations.close()
}
@@ -111,49 +133,67 @@
Trace.beginSection("CXCP-App#startNextCamera")
Trace.beginSection("CXCP-App#stopCamera")
- var camera = currentCamera
- camera?.stop()
+ var cameras = currentCameras
+ cameras?.let {
+ for (camera in it) {
+ camera.stop()
+ }
+ }
Trace.endSection()
Trace.beginSection("CXCP-App#findNextCamera")
- val cameraId = runBlocking { findNextCamera(lastCameraId) }
+ val cameraIds = findNextCameraIdGroup(lastCameraIds)
Trace.endSection()
Trace.beginSection("CXCP-App#startCameraGraph")
- camera = SimpleCamera.create(cameraPipe, cameraId, ui.viewfinder, listOf(), operatingMode)
+ if (cameraIds.size == 1) {
+ cameras = listOf(
+ SimpleCamera.create(
+ cameraPipe,
+ cameraIds.first(),
+ ui.viewfinder,
+ emptyList(),
+ operatingMode
+ )
+ )
+ ui.viewfinderText.text = cameras[0].cameraInfoString()
+ ui.viewfinder2.visibility = View.INVISIBLE
+ ui.viewfinderText2.visibility = View.INVISIBLE
+ } else {
+ cameras = SimpleCamera.create(
+ cameraPipe,
+ cameraIds,
+ listOf(ui.viewfinder, ui.viewfinder2),
+ listOf(Size(1280, 720), Size(1280, 720))
+ )
+ ui.viewfinderText.text = cameras[0].cameraInfoString()
+ ui.viewfinderText2.text = cameras[1].cameraInfoString()
+ ui.viewfinder2.visibility = View.VISIBLE
+ ui.viewfinderText2.visibility = View.VISIBLE
+ }
Trace.endSection()
- currentCamera = camera
- lastCameraId = cameraId
- ui.viewfinderText.text = camera.cameraInfoString()
+ currentCameras = cameras
+ lastCameraIds = cameraIds
- camera.start()
+ for (camera in cameras) {
+ camera.start()
+ }
Trace.endSection()
Trace.endSection()
}
- private suspend fun findNextCamera(lastCameraId: CameraId?): CameraId {
- val cameras = cameraPipe.cameras().getCameraIds()
- checkNotNull(cameras) { "Unable to load CameraIds from CameraPipe" }
-
+ private fun findNextCameraIdGroup(lastCameraIdGroup: List<CameraId>?): List<CameraId> {
// By default, open the first back facing camera if no camera was previously configured.
- if (lastCameraId == null) {
- for (id in cameras) {
- val metadata = cameraPipe.cameras().getCameraMetadata(id)
- if (metadata != null && metadata[CameraCharacteristics.LENS_FACING] ==
- CameraCharacteristics.LENS_FACING_BACK
- ) {
- return id
- }
- }
- return cameras.first()
+ if (lastCameraIdGroup == null) {
+ return cameraIdGroups.first()
}
// If a camera was previously opened and the operating mode is NORMAL, return the same
// camera but switch to HIGH_SPEED operating mode
- if (operatingMode == CameraGraph.OperatingMode.NORMAL) {
+ if (lastCameraIdGroup.size == 1 && operatingMode == CameraGraph.OperatingMode.NORMAL) {
operatingMode = CameraGraph.OperatingMode.HIGH_SPEED
- return lastCameraId
+ return lastCameraIdGroup
}
// If the operating mode is not NORMAL, continue finding the next camera, which will
@@ -164,13 +204,13 @@
// possible that the list of cameras contains only one camera, in which case this will return
// the same camera as "currentCameraId"
- val lastCameraIndex = cameras.indexOf(lastCameraId)
- if (cameras.isEmpty() || lastCameraIndex == -1) {
+ val lastCamerasIndex = cameraIdGroups.indexOf(lastCameraIdGroup)
+ if (lastCamerasIndex == -1) {
Log.e("CXCP-App", "Failed to find matching camera!")
- return cameras.first()
+ return cameraIdGroups.first()
}
// When we reach the end of the list of cameras, loop.
- return cameras[(lastCameraIndex + 1) % cameras.size]
+ return cameraIdGroups[(lastCamerasIndex + 1) % cameraIdGroups.size]
}
}
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeUi.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeUi.kt
index feb1ac4..8aa0eb8 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeUi.kt
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeUi.kt
@@ -36,7 +36,9 @@
}
val viewfinder: Viewfinder = activity.findViewById(R.id.viewfinder)
+ val viewfinder2: Viewfinder = activity.findViewById(R.id.viewfinder_secondary)
val viewfinderText: TextView = activity.findViewById(R.id.viewfinder_text)
+ val viewfinderText2: TextView = activity.findViewById(R.id.viewfinder_secondary_text)
val switchButton: ImageButton = activity.findViewById(R.id.switch_button)
val captureButton: ImageButton = activity.findViewById(R.id.capture_button)
val infoButton: ImageButton = activity.findViewById(R.id.info_button)
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt
index e852046..21e97c2 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt
@@ -56,7 +56,7 @@
private val cameraConfig: CameraGraph.Config,
private val cameraGraph: CameraGraph,
private val cameraMetadata: CameraMetadata,
- private val imageReader: ImageReader
+ private val imageReader: ImageReader? = null
) {
companion object {
fun create(
@@ -72,6 +72,15 @@
return createNormalCamera(cameraPipe, cameraId, viewfinder, listeners)
}
+ fun create(
+ cameraPipe: CameraPipe,
+ cameraIds: List<CameraId>,
+ viewfinders: List<Viewfinder>,
+ sizes: List<Size>
+ ): List<SimpleCamera> {
+ return createConcurrentCameras(cameraPipe, cameraIds, viewfinders, sizes)
+ }
+
private fun createHighSpeedCamera(
cameraPipe: CameraPipe,
cameraId: CameraId,
@@ -298,6 +307,76 @@
)
}
+ private fun createConcurrentCameras(
+ cameraPipe: CameraPipe,
+ cameraIds: List<CameraId>,
+ viewfinders: List<Viewfinder>,
+ sizes: List<Size>,
+ ): List<SimpleCamera> {
+ check(cameraIds.size <= 2)
+ check(cameraIds.size == viewfinders.size)
+ check(cameraIds.size == sizes.size)
+
+ Log.i("CXCP-App", "Selected $cameraIds to open.")
+ val cameraMetadatas = cameraIds.map { cameraId ->
+ val cameraMetadata = cameraPipe.cameras().awaitCameraMetadata(cameraId)
+ checkNotNull(cameraMetadata) { "Failed to load CameraMetadata for $cameraId" }
+ cameraMetadata
+ }
+
+ val viewfinderSteamConfigs = sizes.map { size ->
+ Config.create(
+ size,
+ StreamFormat.PRIVATE,
+ outputType = OutputStream.OutputType.SURFACE_VIEW,
+ )
+ }
+
+ val configs =
+ cameraIds.zip(viewfinderSteamConfigs).map { (cameraId, viewfinderStreamConfig) ->
+ CameraGraph.Config(
+ camera = cameraId,
+ streams = listOf(viewfinderStreamConfig),
+ defaultTemplate = RequestTemplate(CameraDevice.TEMPLATE_PREVIEW),
+ )
+ }
+ check(cameraIds.size == configs.size)
+
+ val cameraGraphs = cameraPipe.createCameraGraphs(configs)
+
+ val viewfinderStreams = cameraGraphs.zip(viewfinderSteamConfigs)
+ .map { (cameraGraph, viewfinderStreamConfig) ->
+ cameraGraph.streams[viewfinderStreamConfig]!!
+ }
+ val viewfinderOutputs = viewfinderStreams.map { it.outputs.single() }
+
+ for ((i, viewfinder) in viewfinders.withIndex()) {
+ viewfinder.configure(
+ viewfinderOutputs[i].size,
+ object : Viewfinder.SurfaceListener {
+ override fun onSurfaceChanged(surface: Surface?, size: Size?) {
+ Log.i("CXCP-App", "Viewfinder$i surface changed to $surface at $size")
+ cameraGraphs[i].setSurface(viewfinderStreams[i].id, surface)
+ }
+ }
+ )
+ }
+
+ cameraGraphs.zip(viewfinderStreams).map { (cameraGraph, viewfinderStream) ->
+ cameraGraph.acquireSessionOrNull()!!.use {
+ it.startRepeating(
+ Request(
+ streams = listOf(viewfinderStream.id)
+ )
+ )
+ }
+ }
+
+ return configs.mapIndexed { i, config ->
+ SimpleCamera(config, cameraGraphs[i], cameraMetadatas[i])
+ }
+ }
+
private fun Size.aspectRatio(): Double {
return this.width.toDouble() / this.height.toDouble()
}
@@ -318,7 +397,7 @@
init {
// This forces the image reader to cycle images (otherwise it might stall the camera)
@Suppress("DEPRECATION") val handler = Handler()
- imageReader.setOnImageAvailableListener(
+ imageReader?.setOnImageAvailableListener(
{
val image = imageReader.acquireNextImage()
image?.close()
@@ -348,7 +427,7 @@
fun close() {
Log.i("CXCP-App", "Closing $cameraGraph")
cameraGraph.close()
- imageReader.close()
+ imageReader?.close()
}
fun cameraInfoString(): String =
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml b/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml
index bcfe4ef..ab023f9 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml
@@ -15,7 +15,6 @@
<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="fill_parent"
android:layout_height="fill_parent"
android:background="@color/cameraPipeThemeBgDark100"
@@ -60,16 +59,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
- <androidx.camera.integration.camera2.pipe.Viewfinder
- android:id="@+id/viewfinder"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="#FFFFFF"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.5"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
<ImageButton
android:id="@+id/capture_button"
android:layout_width="150dp"
@@ -80,6 +69,7 @@
android:layout_marginTop="16dp"
android:adjustViewBounds="false"
android:background="@drawable/theme_round_button"
+ android:elevation="5dp"
android:src="@drawable/ic_baseline_photo_camera_24"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
@@ -92,6 +82,7 @@
android:layout_height="48dp"
android:layout_marginEnd="8dp"
android:background="@drawable/theme_round_button"
+ android:elevation="5dp"
android:src="@drawable/ic_baseline_flip_camera_android_24"
app:layout_constraintEnd_toStartOf="@+id/capture_button"
app:layout_constraintTop_toTopOf="@+id/capture_button" />
@@ -102,6 +93,7 @@
android:layout_height="48dp"
android:layout_marginStart="8dp"
android:background="@drawable/theme_round_button"
+ android:elevation="5dp"
android:src="@drawable/ic_outline_info_24"
app:layout_constraintStart_toEndOf="@+id/capture_button"
app:layout_constraintTop_toTopOf="@+id/capture_button" />
@@ -116,6 +108,7 @@
android:layout_marginTop="8dp"
android:background="@drawable/theme_info_panel"
android:clipToPadding="true"
+ android:elevation="5dp"
android:fillViewport="true"
android:scrollbarStyle="insideOverlay"
android:visibility="invisible"
@@ -141,6 +134,7 @@
android:textColor="@color/cameraPipeThemeFgLight800"
android:textSize="10sp"
android:typeface="monospace" />
+
</LinearLayout>
</ScrollView>
@@ -149,6 +143,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/cameraPipeThemeFgOverlay"
+ android:elevation="3dp"
android:fontFamily="sans-serif-condensed"
android:padding="8dp"
android:textColor="@color/cameraPipeThemeFgLight800"
@@ -158,6 +153,41 @@
app:layout_constraintStart_toStartOf="@id/viewfinder"
app:layout_constraintTop_toTopOf="@id/viewfinder" />
+ <TextView
+ android:id="@+id/viewfinder_secondary_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="@color/cameraPipeThemeFgOverlay"
+ android:elevation="3dp"
+ android:fontFamily="sans-serif-condensed"
+ android:padding="8dp"
+ android:textColor="@color/cameraPipeThemeFgLight800"
+ android:typeface="monospace"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toEndOf="@id/viewfinder_secondary"
+ app:layout_constraintStart_toStartOf="@id/viewfinder_secondary"
+ app:layout_constraintTop_toTopOf="@id/viewfinder_secondary" />
+
+ <androidx.camera.integration.camera2.pipe.Viewfinder
+ android:id="@+id/viewfinder"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="#FFFFFF"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.camera.integration.camera2.pipe.Viewfinder
+ android:id="@+id/viewfinder_secondary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="400dp"
+ android:background="#FFFFFF"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
index e2377a3..c9c7199 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
@@ -96,6 +96,7 @@
import kotlinx.coroutines.withTimeoutOrNull
import org.junit.After
import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeNoException
import org.junit.Assume.assumeNotNull
import org.junit.Assume.assumeTrue
import org.junit.Before
@@ -1579,28 +1580,9 @@
@Test
fun unbindVideoCaptureWithoutStartingRecorder_imageCapturingShouldSuccess() = runBlocking {
- assumeTrue(
- "b/280560222: takePicture request is discarded if UseCaseCamera is recreated",
- implName != CameraPipeConfig::class.simpleName
- )
-
// Arrange.
val imageCapture = ImageCapture.Builder().build()
- val videoStreamReceived = CompletableDeferred<Boolean>()
- val videoCapture = VideoCapture.Builder<Recorder>(Recorder.Builder().build()).also {
- CameraPipeUtil.setCameraCaptureSessionCallback(
- implName,
- it,
- object : CaptureCallback() {
- override fun onCaptureCompleted(
- session: CameraCaptureSession,
- request: CaptureRequest,
- result: TotalCaptureResult
- ) {
- videoStreamReceived.complete(true)
- }
- })
- }.build()
+ val videoCapture = VideoCapture.Builder<Recorder>(Recorder.Builder().build()).build()
withContext(Dispatchers.Main) {
cameraProvider.bindToLifecycle(
@@ -1608,19 +1590,24 @@
)
}
- assertWithMessage("VideoCapture doesn't start").that(
- videoStreamReceived.awaitWithTimeoutOrNull()
- ).isTrue()
+ // wait for camera to start by taking a picture
+ val callback1 = FakeImageCaptureCallback(capturesCount = 1)
+ imageCapture.takePicture(mainExecutor, callback1)
+ try {
+ callback1.awaitCapturesAndAssert(capturedImagesCount = 1)
+ } catch (e: AssertionError) {
+ assumeNoException("image capture failed, camera might not have started yet", e)
+ }
// Act.
- val callback = FakeImageCaptureCallback(capturesCount = 1)
+ val callback2 = FakeImageCaptureCallback(capturesCount = 1)
withContext(Dispatchers.Main) {
cameraProvider.unbind(videoCapture)
- imageCapture.takePicture(mainExecutor, callback)
+ imageCapture.takePicture(mainExecutor, callback2)
}
// Assert.
- callback.awaitCapturesAndAssert(capturedImagesCount = 1)
+ callback2.awaitCapturesAndAssert(capturedImagesCount = 1)
}
@Test
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt
index e63cd9c..827363f 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt
@@ -50,6 +50,7 @@
import org.junit.Assume
import org.junit.Assume.assumeTrue
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -140,6 +141,7 @@
}
/** Test Combination: Preview (no surface provider) + ImageCapture */
+ @Ignore("b/283959238")
@Test
fun previewCombinesImageCapture_withNoSurfaceProvider(): Unit = runBlocking {
// Arrange.
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/YuvToRgbConverterTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/YuvToRgbConverterTest.kt
deleted file mode 100644
index 07fc468..0000000
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/YuvToRgbConverterTest.kt
+++ /dev/null
@@ -1,140 +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.camera.integration.core
-
-import android.content.Context
-import android.graphics.Bitmap
-import androidx.camera.camera2.Camera2Config
-import androidx.camera.camera2.pipe.integration.CameraPipeConfig
-import androidx.camera.core.CameraSelector
-import androidx.camera.core.CameraXConfig
-import androidx.camera.core.ImageAnalysis
-import androidx.camera.integration.core.util.YuvToRgbConverter
-import androidx.camera.lifecycle.ProcessCameraProvider
-import androidx.camera.testing.CameraPipeConfigTestRule
-import androidx.camera.testing.CameraUtil
-import androidx.camera.testing.LabTestRule
-import androidx.camera.testing.fakes.FakeLifecycleOwner
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.filters.LargeTest
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.asExecutor
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withContext
-import org.junit.After
-import org.junit.Assert.assertTrue
-import org.junit.Assume
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-// Test the YubToRgbConverter to convert the input image from CameraX
-@LargeTest
-@RunWith(Parameterized::class)
-class YuvToRgbConverterTest(
- private val implName: String,
- private val cameraXConfig: CameraXConfig
-) {
-
- @get:Rule
- val cameraPipeConfigTestRule = CameraPipeConfigTestRule(
- active = implName == CameraPipeConfig::class.simpleName,
- )
-
- @get:Rule
- val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
- CameraUtil.PreTestCameraIdList(cameraXConfig)
- )
-
- @get:Rule
- val labTest: LabTestRule = LabTestRule()
-
- private val context = ApplicationProvider.getApplicationContext<Context>()
- private lateinit var cameraProvider: ProcessCameraProvider
- private lateinit var fakeLifecycleOwner: FakeLifecycleOwner
-
- companion object {
- @JvmStatic
- @Parameterized.Parameters(name = "{0}")
- fun data() = listOf(
- arrayOf(Camera2Config::class.simpleName, Camera2Config.defaultConfig()),
- arrayOf(CameraPipeConfig::class.simpleName, CameraPipeConfig.defaultConfig())
- )
- }
-
- @Before
- fun setUp(): Unit = runBlocking {
- Assume.assumeTrue(CameraUtil.deviceHasCamera())
- ProcessCameraProvider.configureInstance(cameraXConfig)
- cameraProvider = ProcessCameraProvider.getInstance(context)[10, TimeUnit.SECONDS]
-
- withContext(Dispatchers.Main) {
- fakeLifecycleOwner = FakeLifecycleOwner()
- fakeLifecycleOwner.startAndResume()
- }
- }
-
- @After
- fun tearDown(): Unit = runBlocking {
- if (::cameraProvider.isInitialized) {
- withContext(Dispatchers.Main) {
- cameraProvider.shutdown()[10, TimeUnit.SECONDS]
- }
- }
- }
-
- @LabTestRule.LabTestOnly
- @Test
- fun yubToRgbConverterTest(): Unit = runBlocking {
- val yuvToRgbConverter = YuvToRgbConverter(context)
- val countDownLatch = CountDownLatch(30)
- val imageAnalyzer = ImageAnalysis.Builder().build().also {
- it.setAnalyzer(
- Dispatchers.Main.asExecutor(),
- { image ->
- var bitmap: Bitmap? = null
- try {
- bitmap = Bitmap.createBitmap(
- image.width, image.height, Bitmap.Config.ARGB_8888
- )
- yuvToRgbConverter.yuvToRgb(image.image!!, bitmap)
-
- // Test the YuvToRgbConverter#yuvToRgb can convert the image to bitmap
- // successfully without any exception.
- countDownLatch.countDown()
- } finally {
- bitmap?.recycle()
- image.close()
- }
- }
- )
- }
- withContext(Dispatchers.Main) {
- cameraProvider.bindToLifecycle(
- fakeLifecycleOwner,
- CameraSelector.DEFAULT_BACK_CAMERA,
- imageAnalyzer
- )
- }
-
- assertTrue(countDownLatch.await(60, TimeUnit.SECONDS))
- }
-}
\ No newline at end of file
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/PreviewTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/PreviewTest.kt
index f3bba36..3cc62cf 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/PreviewTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/PreviewTest.kt
@@ -88,6 +88,7 @@
companion object {
private const val ANY_THREAD_NAME = "any-thread-name"
private val DEFAULT_RESOLUTION: Size by lazy { Size(640, 480) }
+
@JvmStatic
@Parameterized.Parameters(name = "{0}")
fun data() = listOf(
@@ -143,20 +144,22 @@
// TODO(b/160261462) move off of main thread when setSurfaceProvider does not need to be
// done on the main thread
- instrumentation.runOnMainSync { preview.setSurfaceProvider { request ->
- val surfaceTexture = SurfaceTexture(0)
- surfaceTexture.setDefaultBufferSize(
- request.resolution.width,
- request.resolution.height
- )
- surfaceTexture.detachFromGLContext()
- val surface = Surface(surfaceTexture)
- request.provideSurface(surface, CameraXExecutors.directExecutor()) {
- surface.release()
- surfaceTexture.release()
+ instrumentation.runOnMainSync {
+ preview.setSurfaceProvider { request ->
+ val surfaceTexture = SurfaceTexture(0)
+ surfaceTexture.setDefaultBufferSize(
+ request.resolution.width,
+ request.resolution.height
+ )
+ surfaceTexture.detachFromGLContext()
+ val surface = Surface(surfaceTexture)
+ request.provideSurface(surface, CameraXExecutors.directExecutor()) {
+ surface.release()
+ surfaceTexture.release()
+ }
+ completableDeferred.complete(Unit)
}
- completableDeferred.complete(Unit)
- } }
+ }
camera = CameraUtil.createCameraAndAttachUseCase(context!!, cameraSelector, preview)
withTimeout(3_000) {
completableDeferred.await()
@@ -184,7 +187,9 @@
Truth.assertThat(surfaceFutureSemaphore!!.tryAcquire(5, TimeUnit.SECONDS)).isTrue()
// Remove the UseCase from the camera
- camera!!.removeUseCases(setOf<UseCase>(preview))
+ instrumentation.runOnMainSync {
+ camera!!.removeUseCases(setOf<UseCase>(preview))
+ }
// Assert.
Truth.assertThat(safeToReleaseSemaphore!!.tryAcquire(5, TimeUnit.SECONDS)).isTrue()
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/util/YuvToRgbConverter.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/util/YuvToRgbConverter.kt
deleted file mode 100644
index 2c0ba63..0000000
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/util/YuvToRgbConverter.kt
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://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.util
-
-import android.content.Context
-import android.graphics.Bitmap
-import android.graphics.ImageFormat
-import android.graphics.Rect
-import android.media.Image
-
-/**
- * Copy from the github for testing.
- * Please reference: https://github.com/android/camera-samples/
- *
- * Helper class used to efficiently convert a Media.Image object from
- * [ImageFormat.YUV_420_888] format to an RGB [Bitmap] object.
- *
- * The [yuvToRgb] method is able to achieve the same FPS as the CameraX image
- * analysis use case on a Pixel 3 XL device at the default analyzer resolution,
- * which is 30 FPS with 640x480.
- *
- * NOTE: This has been tested in a limited number of devices and is not
- * considered production-ready code. It was created for illustration purposes,
- * since this is not an efficient camera pipeline due to the multiple copies
- * required to convert each frame.
- */
-@Suppress("DEPRECATION")
-class YuvToRgbConverter(context: Context) {
- private val rs = android.renderscript.RenderScript.create(context)
- private val scriptYuvToRgb = android.renderscript.ScriptIntrinsicYuvToRGB.create(
- rs,
- android.renderscript.Element.U8_4(rs)
- )
-
- private var pixelCount: Int = -1
- private lateinit var yuvBuffer: ByteArray
- private lateinit var inputAllocation: android.renderscript.Allocation
- private lateinit var outputAllocation: android.renderscript.Allocation
-
- @Synchronized
- fun yuvToRgb(image: Image, output: Bitmap) {
-
- // Ensure that the intermediate output byte buffer is allocated
- if (!::yuvBuffer.isInitialized) {
- pixelCount = image.cropRect.width() * image.cropRect.height()
- // Bits per pixel is an average for the whole image, so it's useful to compute the size
- // of the full buffer but should not be used to determine pixel offsets
- val pixelSizeBits = ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888)
- yuvBuffer = ByteArray(pixelCount * pixelSizeBits / 8)
- }
-
- // Get the YUV data in byte array form using NV21 format
- imageToByteArray(image, yuvBuffer)
-
- // Ensure that the RenderScript inputs and outputs are allocated
- if (!::inputAllocation.isInitialized) {
- // Explicitly create an element with type NV21, since that's the pixel format we use
- val elemType =
- android.renderscript.Type.Builder(rs, android.renderscript.Element.YUV(rs))
- .setYuvFormat(ImageFormat.NV21).create()
- inputAllocation =
- android.renderscript.Allocation.createSized(rs, elemType.element, yuvBuffer.size)
- }
- if (!::outputAllocation.isInitialized) {
- outputAllocation = android.renderscript.Allocation.createFromBitmap(rs, output)
- }
-
- // Convert NV21 format YUV to RGB
- inputAllocation.copyFrom(yuvBuffer)
- scriptYuvToRgb.setInput(inputAllocation)
- scriptYuvToRgb.forEach(outputAllocation)
- outputAllocation.copyTo(output)
- }
-
- private fun imageToByteArray(image: Image, outputBuffer: ByteArray) {
- assert(image.format == ImageFormat.YUV_420_888)
-
- val imageCrop = image.cropRect
- val imagePlanes = image.planes
-
- imagePlanes.forEachIndexed { planeIndex, plane ->
- // How many values are read in input for each output value written
- // Only the Y plane has a value for every pixel, U and V have half the resolution i.e.
- //
- // Y Plane U Plane V Plane
- // =============== ======= =======
- // Y Y Y Y Y Y Y Y U U U U V V V V
- // Y Y Y Y Y Y Y Y U U U U V V V V
- // Y Y Y Y Y Y Y Y U U U U V V V V
- // Y Y Y Y Y Y Y Y U U U U V V V V
- // Y Y Y Y Y Y Y Y
- // Y Y Y Y Y Y Y Y
- // Y Y Y Y Y Y Y Y
- val outputStride: Int
-
- // The index in the output buffer the next value will be written at
- // For Y it's zero, for U and V we start at the end of Y and interleave them i.e.
- //
- // First chunk Second chunk
- // =============== ===============
- // Y Y Y Y Y Y Y Y V U V U V U V U
- // Y Y Y Y Y Y Y Y V U V U V U V U
- // Y Y Y Y Y Y Y Y V U V U V U V U
- // Y Y Y Y Y Y Y Y V U V U V U V U
- // Y Y Y Y Y Y Y Y
- // Y Y Y Y Y Y Y Y
- // Y Y Y Y Y Y Y Y
- var outputOffset: Int
-
- when (planeIndex) {
- 0 -> {
- outputStride = 1
- outputOffset = 0
- }
- 1 -> {
- outputStride = 2
- // For NV21 format, U is in odd-numbered indices
- outputOffset = pixelCount + 1
- }
- 2 -> {
- outputStride = 2
- // For NV21 format, V is in even-numbered indices
- outputOffset = pixelCount
- }
- else -> {
- // Image contains more than 3 planes, something strange is going on
- return@forEachIndexed
- }
- }
-
- val planeBuffer = plane.buffer
- val rowStride = plane.rowStride
- val pixelStride = plane.pixelStride
-
- // We have to divide the width and height by two if it's not the Y plane
- val planeCrop = if (planeIndex == 0) {
- imageCrop
- } else {
- Rect(
- imageCrop.left / 2,
- imageCrop.top / 2,
- imageCrop.right / 2,
- imageCrop.bottom / 2
- )
- }
-
- val planeWidth = planeCrop.width()
- val planeHeight = planeCrop.height()
-
- // Intermediate buffer used to store the bytes of each row
- val rowBuffer = ByteArray(plane.rowStride)
-
- // Size of each row in bytes
- val rowLength = if (pixelStride == 1 && outputStride == 1) {
- planeWidth
- } else {
- // Take into account that the stride may include data from pixels other than this
- // particular plane and row, and that could be between pixels and not after every
- // pixel:
- //
- // |---- Pixel stride ----| Row ends here --> |
- // | Pixel 1 | Other Data | Pixel 2 | Other Data | ... | Pixel N |
- //
- // We need to get (N-1) * (pixel stride bytes) per row + 1 byte for the last pixel
- (planeWidth - 1) * pixelStride + 1
- }
-
- for (row in 0 until planeHeight) {
- // Move buffer position to the beginning of this row
- planeBuffer.position(
- (row + planeCrop.top) * rowStride + planeCrop.left * pixelStride
- )
-
- if (pixelStride == 1 && outputStride == 1) {
- // When there is a single stride value for pixel and output, we can just copy
- // the entire row in a single step
- planeBuffer.get(outputBuffer, outputOffset, rowLength)
- outputOffset += rowLength
- } else {
- // When either pixel or output have a stride > 1 we must copy pixel by pixel
- planeBuffer.get(rowBuffer, 0, rowLength)
- for (col in 0 until planeWidth) {
- outputBuffer[outputOffset] = rowBuffer[col * pixelStride]
- outputOffset += outputStride
- }
- }
- }
- }
- }
-}
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
index 1721b14..ff31765 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
@@ -169,6 +169,7 @@
public class CameraXActivity extends AppCompatActivity {
private static final String TAG = "CameraXActivity";
private static final String[] REQUIRED_PERMISSIONS;
+ private static final List<DynamicRangeUiData> DYNAMIC_RANGE_UI_DATA = new ArrayList<>();
static {
// From Android T, skips the permission check of WRITE_EXTERNAL_STORAGE since it won't be
@@ -185,6 +186,35 @@
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
}
+
+ DYNAMIC_RANGE_UI_DATA.add(new DynamicRangeUiData(
+ DynamicRange.SDR,
+ "SDR",
+ R.string.toggle_video_dyn_rng_sdr));
+ DYNAMIC_RANGE_UI_DATA.add(new DynamicRangeUiData(
+ DynamicRange.HDR_UNSPECIFIED_10_BIT,
+ "HDR (Auto, 10-bit)",
+ R.string.toggle_video_dyn_rng_hdr_auto));
+ DYNAMIC_RANGE_UI_DATA.add(new DynamicRangeUiData(
+ DynamicRange.HLG_10_BIT,
+ "HDR (HLG, 10-bit)",
+ R.string.toggle_video_dyn_rng_hlg));
+ DYNAMIC_RANGE_UI_DATA.add(new DynamicRangeUiData(
+ DynamicRange.HDR10_10_BIT,
+ "HDR (HDR10, 10-bit)",
+ R.string.toggle_video_dyn_rng_hdr_ten));
+ DYNAMIC_RANGE_UI_DATA.add(new DynamicRangeUiData(
+ DynamicRange.HDR10_PLUS_10_BIT,
+ "HDR (HDR10+, 10-bit)",
+ R.string.toggle_video_dyn_rng_hdr_ten_plus));
+ DYNAMIC_RANGE_UI_DATA.add(new DynamicRangeUiData(
+ DynamicRange.DOLBY_VISION_8_BIT,
+ "HDR (Dolby Vision, 8-bit)",
+ R.string.toggle_video_dyn_rng_hdr_dolby_vision_8));
+ DYNAMIC_RANGE_UI_DATA.add(new DynamicRangeUiData(
+ DynamicRange.DOLBY_VISION_10_BIT,
+ "HDR (Dolby Vision, 10-bit)",
+ R.string.toggle_video_dyn_rng_hdr_dolby_vision_10));
}
//Use this activity title when Camera Pipe configuration is used by core test app
@@ -250,7 +280,6 @@
// The target aspect ratio of Preview and ImageCapture. It can be adjusted by setting
// INTENT_EXTRA_TARGET_ASPECT_RATIO for the e2e testing.
private int mTargetAspectRatio = AspectRatio.RATIO_DEFAULT;
-
private Recording mActiveRecording;
/** The camera to use */
CameraSelector mCurrentCameraSelector = BACK_SELECTOR;
@@ -292,9 +321,8 @@
private DisplayManager.DisplayListener mDisplayListener;
private RecordUi mRecordUi;
private Quality mVideoQuality;
- // TODO: Use SDR by now. A UI for selecting different dynamic ranges will be added when the
- // related functionality is complete.
- private final DynamicRange mDynamicRange = DynamicRange.SDR;
+ private DynamicRange mDynamicRange = DynamicRange.SDR;
+ private final Set<DynamicRange> mSelectableDynamicRanges = new HashSet<>();
SessionMediaUriSet mSessionImagesUriSet = new SessionMediaUriSet();
SessionMediaUriSet mSessionVideosUriSet = new SessionMediaUriSet();
@@ -615,6 +643,40 @@
}
});
+ // Final reference to this record UI
+ mRecordUi.getButtonDynamicRange().setText(getDynamicRangeIconName(mDynamicRange));
+ mRecordUi.getButtonDynamicRange().setOnClickListener(view -> {
+ PopupMenu popup = new PopupMenu(this, view);
+ Menu menu = popup.getMenu();
+
+ final int groupId = Menu.NONE;
+ for (DynamicRange dynamicRange : mSelectableDynamicRanges) {
+ int itemId = dynamicRangeToItemId(dynamicRange);
+ menu.add(groupId, itemId, itemId, getDynamicRangeMenuItemName(dynamicRange));
+ if (Objects.equals(dynamicRange, mDynamicRange)) {
+ // Apply the checked item for the selected dynamic range to the menu.
+ menu.findItem(itemId).setChecked(true);
+ }
+ }
+
+ // Make menu single checkable
+ menu.setGroupCheckable(groupId, true, true);
+
+ popup.setOnMenuItemClickListener(item -> {
+ DynamicRange dynamicRange = itemIdToDynamicRange(item.getItemId());
+ if (!Objects.equals(dynamicRange, mDynamicRange)) {
+ mDynamicRange = dynamicRange;
+ mRecordUi.getButtonDynamicRange()
+ .setText(getDynamicRangeIconName(mDynamicRange));
+ // Dynamic range changed, rebind UseCases
+ tryBindUseCases();
+ }
+ return true;
+ });
+
+ popup.show();
+ });
+
mRecordUi.getButtonQuality().setText(getQualityIconName(mVideoQuality));
mRecordUi.getButtonQuality().setOnClickListener(view -> {
PopupMenu popup = new PopupMenu(this, view);
@@ -662,6 +724,15 @@
});
}
+ private static boolean hasTenBitDynamicRange(@NonNull Set<DynamicRange> dynamicRanges) {
+ for (DynamicRange dynamicRange : dynamicRanges) {
+ if (dynamicRange.getBitDepth() == DynamicRange.BIT_DEPTH_10_BIT) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private final Consumer<VideoRecordEvent> mVideoRecordEventListener = event -> {
updateRecordingStats(event.getRecordingStats());
@@ -1202,7 +1273,8 @@
findViewById(R.id.video_pause),
findViewById(R.id.video_stats),
findViewById(R.id.video_quality),
- findViewById(R.id.video_persistent)
+ findViewById(R.id.video_persistent),
+ findViewById(R.id.video_dynamic_range)
);
setUpButtonEvents();
@@ -1408,6 +1480,7 @@
&& mLaunchingCameraLensFacing == CameraSelector.LENS_FACING_UNKNOWN) {
mLaunchingCameraLensFacing = getLensFacing(mCamera.getCameraInfo());
}
+
List<UseCase> useCases = buildUseCases();
mCamera = bindToLifecycleSafely(useCases);
@@ -1417,10 +1490,12 @@
String msg;
if (mVideoQuality != QUALITY_AUTO) {
msg = "Bind too many use cases or video quality is too large.";
+ } else if (!Objects.equals(mDynamicRange, DynamicRange.SDR)) {
+ msg = "Bind too many use cases or unsupported dynamic range combination.";
} else {
msg = "Bind too many use cases.";
}
- Log.e(TAG, "bindToLifecycle() failed. " + msg);
+ Log.e(TAG, "bindToLifecycle() failed. " + msg, ex);
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
// Restore toggle buttons to the previous state if the bind failed.
@@ -1432,6 +1507,9 @@
}
// Reset video quality to avoid always fail by quality too large.
mRecordUi.getButtonQuality().setText(getQualityIconName(mVideoQuality = QUALITY_AUTO));
+ // Reset video dynamic range to avoid failure
+ mRecordUi.getButtonDynamicRange().setText(
+ getDynamicRangeIconName(mDynamicRange = DynamicRange.SDR));
reduceUseCaseToFindSupportedCombination();
@@ -1532,6 +1610,9 @@
}
if (mVideoToggle.isChecked()) {
+ // Update possible dynamic ranges for current camera
+ updateDynamicRangeConfiguration();
+
// Recreate the Recorder except there's a running persistent recording, existing
// Recorder. We may later consider reuse the Recorder everytime if the quality didn't
// change.
@@ -1544,12 +1625,39 @@
}
VideoCapture<Recorder> videoCapture = new VideoCapture.Builder<>(mRecorder)
.setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY)
+ .setDynamicRange(mDynamicRange)
.build();
useCases.add(videoCapture);
}
return useCases;
}
+ private void updateDynamicRangeConfiguration() {
+ mSelectableDynamicRanges.clear();
+
+ // Get the list of available dynamic ranges for the current quality
+ VideoCapabilities videoCapabilities = Recorder.getVideoCapabilities(
+ mCamera.getCameraInfo());
+ Set<DynamicRange> supportedDynamicRanges =
+ videoCapabilities.getSupportedDynamicRanges();
+
+ if (supportedDynamicRanges.size() > 1) {
+ mRecordUi.setDynamicRangeConfigurable(true);
+ if (hasTenBitDynamicRange(supportedDynamicRanges)) {
+ mSelectableDynamicRanges.add(DynamicRange.HDR_UNSPECIFIED_10_BIT);
+ }
+ } else {
+ mRecordUi.setDynamicRangeConfigurable(false);
+ }
+ mSelectableDynamicRanges.addAll(supportedDynamicRanges);
+
+ // In case the previous dynamic range held in mDynamicRange isn't supported, reset
+ // to SDR.
+ if (!mSelectableDynamicRanges.contains(mDynamicRange)) {
+ mDynamicRange = DynamicRange.SDR;
+ }
+ }
+
/**
* Request permission if missing.
*/
@@ -1871,17 +1979,22 @@
private final TextView mTextStats;
private final Button mButtonQuality;
private final ToggleButton mButtonPersistent;
+ private final Button mButtonDynamicRange;
+ private boolean mDynamicRangeConfigurable = false;
+
private boolean mEnabled = false;
private State mState = State.IDLE;
RecordUi(@NonNull Button buttonRecord, @NonNull Button buttonPause,
@NonNull TextView textStats, @NonNull Button buttonQuality,
- @NonNull ToggleButton buttonPersistent) {
+ @NonNull ToggleButton buttonPersistent,
+ @NonNull Button buttonDynamicRange) {
mButtonRecord = buttonRecord;
mButtonPause = buttonPause;
mTextStats = textStats;
mButtonQuality = buttonQuality;
mButtonPersistent = buttonPersistent;
+ mButtonDynamicRange = buttonDynamicRange;
}
void setEnabled(boolean enabled) {
@@ -1891,12 +2004,14 @@
mTextStats.setVisibility(View.VISIBLE);
mButtonQuality.setVisibility(View.VISIBLE);
mButtonPersistent.setVisibility(View.VISIBLE);
+ mButtonDynamicRange.setVisibility(View.VISIBLE);
updateUi();
} else {
mButtonRecord.setText("Record");
mButtonRecord.setEnabled(false);
mButtonPause.setVisibility(View.INVISIBLE);
mButtonQuality.setVisibility(View.INVISIBLE);
+ mButtonDynamicRange.setVisibility(View.INVISIBLE);
mTextStats.setVisibility(View.GONE);
mButtonPersistent.setVisibility(View.INVISIBLE);
}
@@ -1919,6 +2034,14 @@
mButtonPersistent.setVisibility(View.GONE);
}
+ private void setDynamicRangeConfigurable(boolean configurable) {
+ if (configurable != mDynamicRangeConfigurable) {
+ mDynamicRangeConfigurable = configurable;
+ boolean buttonEnabled = mButtonDynamicRange.isEnabled();
+ mButtonDynamicRange.setEnabled(buttonEnabled && mDynamicRangeConfigurable);
+ }
+ }
+
private void updateUi() {
if (!mEnabled) {
return;
@@ -1929,32 +2052,36 @@
mButtonRecord.setEnabled(true);
mButtonPause.setText("Pause");
mButtonPause.setVisibility(View.INVISIBLE);
- mButtonPersistent.setClickable(true);
- mButtonQuality.setClickable(true);
+ mButtonPersistent.setEnabled(true);
+ mButtonQuality.setEnabled(true);
+ mButtonDynamicRange.setEnabled(mDynamicRangeConfigurable);
break;
case RECORDING:
mButtonRecord.setText("Stop");
mButtonRecord.setEnabled(true);
mButtonPause.setText("Pause");
mButtonPause.setVisibility(View.VISIBLE);
- mButtonPersistent.setClickable(false);
- mButtonQuality.setClickable(false);
+ mButtonPersistent.setEnabled(false);
+ mButtonQuality.setEnabled(false);
+ mButtonDynamicRange.setEnabled(false);
break;
case STOPPING:
mButtonRecord.setText("Saving");
mButtonRecord.setEnabled(false);
mButtonPause.setText("Pause");
mButtonPause.setVisibility(View.INVISIBLE);
- mButtonPersistent.setClickable(false);
- mButtonQuality.setClickable(true);
+ mButtonPersistent.setEnabled(false);
+ mButtonQuality.setEnabled(true);
+ mButtonDynamicRange.setEnabled(mDynamicRangeConfigurable);
break;
case PAUSED:
mButtonRecord.setText("Stop");
mButtonRecord.setEnabled(true);
mButtonPause.setText("Resume");
mButtonPause.setVisibility(View.VISIBLE);
- mButtonPersistent.setClickable(false);
- mButtonQuality.setClickable(true);
+ mButtonPersistent.setEnabled(false);
+ mButtonQuality.setEnabled(true);
+ mButtonDynamicRange.setEnabled(mDynamicRangeConfigurable);
break;
}
}
@@ -1979,6 +2106,10 @@
ToggleButton getButtonPersistent() {
return mButtonPersistent;
}
+ @NonNull
+ Button getButtonDynamicRange() {
+ return mButtonDynamicRange;
+ }
}
Preview getPreview() {
@@ -2117,6 +2248,54 @@
}
}
+ @NonNull
+ private String getDynamicRangeIconName(@NonNull DynamicRange dynamicRange) {
+ int resId = R.string.toggle_video_dyn_rng_unknown;
+ for (DynamicRangeUiData uiData : DYNAMIC_RANGE_UI_DATA) {
+ if (Objects.equals(dynamicRange, uiData.mDynamicRange)) {
+ resId = uiData.mToggleLabelRes;
+ break;
+ }
+ }
+
+ return getString(resId);
+ }
+
+ @NonNull
+ private static String getDynamicRangeMenuItemName(@NonNull DynamicRange dynamicRange) {
+ String menuItemName = dynamicRange.toString();
+ for (DynamicRangeUiData uiData : DYNAMIC_RANGE_UI_DATA) {
+ if (Objects.equals(dynamicRange, uiData.mDynamicRange)) {
+ menuItemName = uiData.mMenuItemName;
+ break;
+ }
+ }
+ return menuItemName;
+ }
+
+ private static int dynamicRangeToItemId(@NonNull DynamicRange dynamicRange) {
+ int itemId = -1;
+ for (int i = 0; i < DYNAMIC_RANGE_UI_DATA.size(); i++) {
+ DynamicRangeUiData uiData = DYNAMIC_RANGE_UI_DATA.get(i);
+ if (Objects.equals(dynamicRange, uiData.mDynamicRange)) {
+ itemId = i;
+ break;
+ }
+ }
+ if (itemId == -1) {
+ throw new IllegalArgumentException("Unsupported dynamic range: " + dynamicRange);
+ }
+ return itemId;
+ }
+
+ @NonNull
+ private static DynamicRange itemIdToDynamicRange(int itemId) {
+ if (itemId < 0 || itemId >= DYNAMIC_RANGE_UI_DATA.size()) {
+ throw new IllegalArgumentException("Undefined item id: " + itemId);
+ }
+ return DYNAMIC_RANGE_UI_DATA.get(itemId).mDynamicRange;
+ }
+
private static CameraSelector createCameraSelectorById(@Nullable String cameraId) {
return new CameraSelector.Builder().addCameraFilter(cameraInfos -> {
for (CameraInfo cameraInfo : cameraInfos) {
@@ -2181,4 +2360,19 @@
return androidx.camera.camera2.pipe.integration.interop.Camera2CameraInfo.from(
cameraInfo).getCameraId();
}
+
+ private static final class DynamicRangeUiData {
+ private DynamicRangeUiData(
+ @NonNull DynamicRange dynamicRange,
+ @NonNull String menuItemName,
+ int toggleLabelRes) {
+ mDynamicRange = dynamicRange;
+ mMenuItemName = menuItemName;
+ mToggleLabelRes = toggleLabelRes;
+ }
+
+ DynamicRange mDynamicRange;
+ String mMenuItemName;
+ int mToggleLabelRes;
+ }
}
diff --git a/camera/integration-tests/coretestapp/src/main/res/drawable/round_button.xml b/camera/integration-tests/coretestapp/src/main/res/drawable/round_button.xml
index 2672c0e..b2035f7 100644
--- a/camera/integration-tests/coretestapp/src/main/res/drawable/round_button.xml
+++ b/camera/integration-tests/coretestapp/src/main/res/drawable/round_button.xml
@@ -14,6 +14,11 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false">
+ <shape android:shape="oval">
+ <solid android:color="#66888888"/>
+ </shape>
+ </item>
<item android:state_pressed="false">
<shape android:shape="oval">
<solid android:color="#AA2255FF"/>
diff --git a/camera/integration-tests/coretestapp/src/main/res/drawable/round_toggle_button.xml b/camera/integration-tests/coretestapp/src/main/res/drawable/round_toggle_button.xml
index e25beb0..2053e18 100644
--- a/camera/integration-tests/coretestapp/src/main/res/drawable/round_toggle_button.xml
+++ b/camera/integration-tests/coretestapp/src/main/res/drawable/round_toggle_button.xml
@@ -15,6 +15,11 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false">
+ <shape android:shape="oval">
+ <solid android:color="#66888888"/>
+ </shape>
+ </item>
<item android:state_checked="true">
<shape android:shape="oval">
<solid android:color="#41ABFF"/>
diff --git a/camera/integration-tests/coretestapp/src/main/res/layout/activity_camera_xmain.xml b/camera/integration-tests/coretestapp/src/main/res/layout/activity_camera_xmain.xml
index 928d8b2..a1e8f19 100644
--- a/camera/integration-tests/coretestapp/src/main/res/layout/activity_camera_xmain.xml
+++ b/camera/integration-tests/coretestapp/src/main/res/layout/activity_camera_xmain.xml
@@ -323,6 +323,21 @@
app:layout_constraintRight_toRightOf="parent"
/>
+ <Button
+ android:id="@+id/video_dynamic_range"
+ android:layout_width="46dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="1dp"
+ android:layout_marginRight="5dp"
+ android:background="@drawable/round_button"
+ android:scaleType="fitXY"
+ android:textColor="#EEEEEE"
+ android:textSize="14dp"
+ android:visibility="invisible"
+ app:layout_constraintTop_toBottomOf="@id/video_persistent"
+ app:layout_constraintRight_toRightOf="parent"
+ />
+
<SeekBar
android:id="@+id/seekBar"
android:layout_width="250dp"
diff --git a/camera/integration-tests/coretestapp/src/main/res/values/donottranslate-strings.xml b/camera/integration-tests/coretestapp/src/main/res/values/donottranslate-strings.xml
index 8b2777e..e835bfa 100644
--- a/camera/integration-tests/coretestapp/src/main/res/values/donottranslate-strings.xml
+++ b/camera/integration-tests/coretestapp/src/main/res/values/donottranslate-strings.xml
@@ -35,4 +35,13 @@
<string name="toggle_zoom_reset">1X</string>
<string name="toggle_video_persistent_on">Pers. On</string>
<string name="toggle_video_persistent_off">Pers. Off</string>
+ <string name="toggle_video_dyn_rng_sdr">SDR</string>
+ <string name="toggle_video_dyn_rng_hdr_auto">HDR\nAuto</string>
+ <string name="toggle_video_dyn_rng_hlg">HLG</string>
+ <string name="toggle_video_dyn_rng_hdr_ten">HDR10</string>
+ <string name="toggle_video_dyn_rng_hdr_ten_plus">HDR10+</string>
+ <string name="toggle_video_dyn_rng_hdr_dolby_vision_10">Dlby\n10bit</string>
+ <string name="toggle_video_dyn_rng_hdr_dolby_vision_8">Dlby\n8bit</string>
+ <string name="toggle_video_dyn_rng_unknown">\?</string>
+
</resources>
\ No newline at end of file
diff --git a/camera/integration-tests/extensionstestapp/build.gradle b/camera/integration-tests/extensionstestapp/build.gradle
index b37efba..ccc1eab 100644
--- a/camera/integration-tests/extensionstestapp/build.gradle
+++ b/camera/integration-tests/extensionstestapp/build.gradle
@@ -78,3 +78,10 @@
debugImplementation(libs.testCore)
}
+androidx {
+ deviceTests {
+ // These tests only work on devices that ship extensions
+ // and androidx test infrastructure has no such devices b/284404606
+ enabled = false
+ }
+}
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ClientVersionBackwardCompatibilityTest.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ClientVersionBackwardCompatibilityTest.kt
new file mode 100644
index 0000000..76bea88
--- /dev/null
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ClientVersionBackwardCompatibilityTest.kt
@@ -0,0 +1,262 @@
+/*
+ * 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.extensions
+
+import android.content.Context
+import android.hardware.camera2.CaptureResult
+import androidx.camera.camera2.Camera2Config
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.Preview
+import androidx.camera.core.impl.SessionProcessor
+import androidx.camera.core.impl.SessionProcessor.CaptureCallback
+import androidx.camera.extensions.ExtensionsManager
+import androidx.camera.extensions.internal.ExtensionVersion
+import androidx.camera.extensions.internal.Version
+import androidx.camera.integration.extensions.util.CameraXExtensionsTestUtil
+import androidx.camera.integration.extensions.utils.CameraIdExtensionModePair
+import androidx.camera.integration.extensions.utils.CameraSelectorUtil
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.SurfaceTextureProvider
+import androidx.camera.testing.fakes.FakeLifecycleOwner
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+import org.junit.After
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * These tests ensures OEM Extensions implementation can work with earlier Extensions-Interface
+ * clients. For example, OEM implements v1.4.0 Extensions-Interface, these tests ensure it works
+ * well not only on CameraX app with v1.4.0 Extensions-Interface but also on apps with v1.3.0 and
+ * prior versions.
+ *
+ * There are two types of tests:
+ * - Client supplied callback being invoked properly: Apps with older version of
+ * Extensions-Interface might lack some of the methods in these client supplied callback such as
+ * [SessionProcessorImpl#CaptureCallback]. So it's important that OEM extensions doesn't
+ * invoke these new methods on the client that uses older version.
+ * - Variants of the APIs should work properly: some methods such as
+ * [androidx.camera.extensions.imp.CaptureProcessorImpl#process]has two overloaded methods.
+ * While client with latest version will invoke the newer version,
+ * the older one will invoke another version. So it's important to have both version working as
+ * expected.
+ *
+ * This class tests these compatibility issues by verifying some high-level functions on top of
+ * CameraX full Extensions implementations because it's difficult and wasted to create a full
+ * functional fake implementation and difficult to monitor the call to the low level
+ * Extensions-Interface instances.
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@SdkSuppress(minSdkVersion = 21)
+class ClientVersionBackwardCompatibilityTest(private val config: CameraIdExtensionModePair) {
+ companion object {
+ @JvmStatic
+ @get:Parameterized.Parameters(name = "config = {0}")
+ val parameters: Collection<CameraIdExtensionModePair>
+ get() = CameraXExtensionsTestUtil.getAllCameraIdExtensionModeCombinations()
+ }
+
+ @get:Rule
+ val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+ CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+ )
+
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+
+ private lateinit var cameraProvider: ProcessCameraProvider
+ private lateinit var extensionsManager: ExtensionsManager
+ private lateinit var baseCameraSelector: CameraSelector
+ private lateinit var extensionCameraSelector: CameraSelector
+ private lateinit var lifecycleOwner: FakeLifecycleOwner
+
+ @Before
+ fun setUp(): Unit = runBlocking(Dispatchers.Main) {
+ cameraProvider = ProcessCameraProvider.getInstance(context)[10, TimeUnit.SECONDS]
+ lifecycleOwner = FakeLifecycleOwner()
+ lifecycleOwner.startAndResume()
+ baseCameraSelector = CameraSelectorUtil.createCameraSelectorById(config.cameraId)
+ }
+
+ @After
+ fun tearDown() = runBlocking {
+ if (::cameraProvider.isInitialized) {
+ withContext(Dispatchers.Main) {
+ cameraProvider.shutdown()[10, TimeUnit.SECONDS]
+ }
+ }
+
+ if (::extensionsManager.isInitialized) {
+ withContext(Dispatchers.Main) {
+ extensionsManager.shutdown()[10, TimeUnit.SECONDS]
+ }
+ }
+ }
+
+ private suspend fun startCameraAndGetSessionProcessor(
+ clientVersion: String,
+ minRuntimeVersion: Version? = null
+ ): SessionProcessor {
+ extensionsManager = ExtensionsManager.getInstanceAsync(
+ context,
+ cameraProvider,
+ clientVersion
+ )[10000, TimeUnit.MILLISECONDS]
+ assumeTrue(extensionsManager.isExtensionAvailable(baseCameraSelector, config.extensionMode))
+ minRuntimeVersion?.let {
+ assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(minRuntimeVersion))
+ }
+ extensionCameraSelector = extensionsManager
+ .getExtensionEnabledCameraSelector(baseCameraSelector, config.extensionMode)
+
+ val previewFrameLatch = CountDownLatch(1)
+ val camera = withContext(Dispatchers.Main) {
+ val preview = Preview.Builder().build()
+ val imageCapture = ImageCapture.Builder().build()
+
+ preview.setSurfaceProvider(
+ SurfaceTextureProvider.createAutoDrainingSurfaceTextureProvider {
+ previewFrameLatch.countDown()
+ }
+ )
+ cameraProvider.bindToLifecycle(
+ lifecycleOwner, extensionCameraSelector,
+ preview, imageCapture
+ )
+ }
+ assertThat(previewFrameLatch.await(3, TimeUnit.SECONDS)).isTrue()
+ return camera.extendedConfig.sessionProcessor
+ }
+
+ private suspend fun verifyOnCaptureCompletedInvoked_stillCapture(
+ clientVersion: String,
+ shouldInvoke: Boolean
+ ) {
+ val sessionProcessor = startCameraAndGetSessionProcessor(
+ clientVersion = clientVersion,
+ minRuntimeVersion = Version.VERSION_1_3
+ )
+
+ val latchSequenceCompleted = CountDownLatch(1)
+ var isOnCaptureCompletedInvoked = false
+ sessionProcessor.startCapture(object : CaptureCallback {
+ override fun onCaptureSequenceCompleted(captureSequenceId: Int) {
+ latchSequenceCompleted.countDown()
+ }
+
+ override fun onCaptureCompleted(
+ timestamp: Long,
+ captureSequenceId: Int,
+ result: MutableMap<CaptureResult.Key<Any>, Any>
+ ) {
+ isOnCaptureCompletedInvoked = true
+ }
+ })
+
+ assertThat(latchSequenceCompleted.await(3, TimeUnit.SECONDS)).isTrue()
+ assertThat(isOnCaptureCompletedInvoked).isEqualTo(shouldInvoke)
+ }
+
+ private suspend fun verifyOnCaptureCompletedInvoked_repeating(
+ clientVersion: String,
+ shouldInvoke: Boolean
+ ) {
+ val sessionProcessor = startCameraAndGetSessionProcessor(
+ clientVersion = clientVersion,
+ minRuntimeVersion = Version.VERSION_1_3
+ )
+
+ val latchSequenceCompleted = CountDownLatch(1)
+ var isOnCaptureCompletedInvoked = false
+
+ sessionProcessor.startRepeating(object : CaptureCallback {
+ override fun onCaptureSequenceCompleted(captureSequenceId: Int) {
+ latchSequenceCompleted.countDown()
+ }
+
+ override fun onCaptureCompleted(
+ timestamp: Long,
+ captureSequenceId: Int,
+ result: MutableMap<CaptureResult.Key<Any>, Any>
+ ) {
+ isOnCaptureCompletedInvoked = true
+ }
+ })
+
+ assertThat(latchSequenceCompleted.await(3, TimeUnit.SECONDS)).isTrue()
+ assertThat(isOnCaptureCompletedInvoked).isEqualTo(shouldInvoke)
+ }
+
+ /**
+ * For Advanced Extender, SessionProcessor.onCaptureCompleted is invoked when
+ * SessionProcessorImpl.onCaptureCompleted is invoked. So it's effective to verify just
+ * SessionProcessor.onCaptureCompleted.
+ *
+ * For Basic Extender, CaptureProcessorImpl#process(..) and
+ * CaptureProcessorImpl#process(.. ProcessResultImpl) will be invoked depending on the client and
+ * OEM versions. And only the process() with ProcessResultImpl version will trigger the
+ * SessionProcessor.onCaptureCompleted call. So we can verify if
+ * SessionProcessor.onCaptureCompleted is invoked or not to see if the correct version of the
+ * process() is invoked.
+ */
+ @Test
+ fun stillCapture_onCaptureCompletedInvoked_1_3_0() = runBlocking {
+ verifyOnCaptureCompletedInvoked_stillCapture(clientVersion = "1.3.0", shouldInvoke = true)
+ }
+
+ @Test
+ fun stillCapture_onCaptureCompletedInvoked_1_3_0_above() = runBlocking {
+ // use a significantly large version to see if the OEM appropriately implements the version
+ // comparison.
+ verifyOnCaptureCompletedInvoked_stillCapture(clientVersion = "1.7.0", shouldInvoke = true)
+ }
+
+ @Test
+ fun stillCapture_onCaptureCompletedNotInvoked_1_3_0_below() = runBlocking {
+ verifyOnCaptureCompletedInvoked_stillCapture(clientVersion = "1.2.0", shouldInvoke = false)
+ }
+
+ @Test
+ fun repeating_onCaptureCompletedInvoked_1_3_0() = runBlocking {
+ verifyOnCaptureCompletedInvoked_repeating(clientVersion = "1.3.0", shouldInvoke = true)
+ }
+
+ @Test
+ fun repeating_onCaptureCompletedInvoked_1_3_0_above() = runBlocking {
+ // use a significantly large version to see if the OEM appropriately implements the version
+ // comparison.
+ verifyOnCaptureCompletedInvoked_repeating(clientVersion = "1.7.0", shouldInvoke = true)
+ }
+
+ @Test
+ fun repeating_onCaptureCompletedNotInvoked_1_3_0_below() = runBlocking {
+ verifyOnCaptureCompletedInvoked_repeating(clientVersion = "1.2.0", shouldInvoke = false)
+ }
+}
\ No newline at end of file
diff --git a/camera/integration-tests/uiwidgetstestapp/src/main/java/androidx/camera/integration/uiwidgets/viewpager/CameraFragment.kt b/camera/integration-tests/uiwidgetstestapp/src/main/java/androidx/camera/integration/uiwidgets/viewpager/CameraFragment.kt
index d4b972fe..31e4643 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/main/java/androidx/camera/integration/uiwidgets/viewpager/CameraFragment.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/main/java/androidx/camera/integration/uiwidgets/viewpager/CameraFragment.kt
@@ -99,6 +99,7 @@
removeExtra(KEY_CAMERA_IMPLEMENTATION)
removeExtra(KEY_CAMERA_IMPLEMENTATION_NO_HISTORY)
}
+ cameraImpl = null
}
}
diff --git a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
index 17631cd..6634581 100644
--- a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
+++ b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
@@ -139,40 +139,7 @@
}
}
- @Test
- fun enableEffect_previewEffectIsEnabled() {
- // Arrange: launch app and verify effect is inactive.
- fragment.assertPreviewIsStreaming()
- val processor =
- fragment.mToneMappingSurfaceEffect.surfaceProcessor as ToneMappingSurfaceProcessor
- assertThat(processor.isSurfaceRequestedAndProvided()).isFalse()
-
- // Act: turn on effect.
- val effectToggleId = "androidx.camera.integration.view:id/effect_toggle"
- assumeObjectCanBeFound(UiSelector().resourceId(effectToggleId)).click()
- instrumentation.waitForIdleSync()
-
- // Assert: verify that effect is active.
- assertThat(processor.isSurfaceRequestedAndProvided()).isTrue()
- }
-
- @Test
- fun enableEffect_imageCaptureEffectIsEnabled() {
- // Arrange: launch app and verify effect is inactive.
- fragment.assertPreviewIsStreaming()
- val effect = fragment.mToneMappingImageEffect as ToneMappingImageEffect
- assertThat(effect.isInvoked()).isFalse()
-
- // Act: turn on effect.
- val effectToggleId = "androidx.camera.integration.view:id/effect_toggle"
- assumeObjectCanBeFound(UiSelector().resourceId(effectToggleId)).click()
- instrumentation.waitForIdleSync()
- fragment.assertCanTakePicture()
-
- // Assert: verify that effect is active.
- assertThat(effect.isInvoked()).isTrue()
- }
-
+ @Ignore("b/283308005")
@Test
fun controllerBound_canGetCameraControl() {
fragment.assertPreviewIsStreaming()
@@ -833,4 +800,4 @@
arrayOf(CameraPipeConfig::class.simpleName, CameraPipeConfig.defaultConfig())
)
}
-}
\ No newline at end of file
+}
diff --git a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/EffectsFragmentDeviceTest.kt b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/EffectsFragmentDeviceTest.kt
new file mode 100644
index 0000000..c99d03a
--- /dev/null
+++ b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/EffectsFragmentDeviceTest.kt
@@ -0,0 +1,183 @@
+/*
+ * 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.view
+
+import android.net.Uri
+import androidx.camera.camera2.Camera2Config
+import androidx.camera.camera2.pipe.integration.CameraPipeConfig
+import androidx.camera.core.CameraXConfig
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCaptureException
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.testing.CameraPipeConfigTestRule
+import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CoreAppTestUtil
+import androidx.camera.view.PreviewView
+import androidx.fragment.app.testing.FragmentScenario
+import androidx.lifecycle.Lifecycle
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.LargeTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.rule.GrantPermissionRule
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Instrument tests for {@link EffectsFragment}.
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+class EffectsFragmentDeviceTest(
+ private val implName: String,
+ private val cameraConfig: CameraXConfig
+) {
+ @get:Rule
+ val cameraPipeConfigTestRule = CameraPipeConfigTestRule(
+ active = implName == CameraPipeConfig::class.simpleName,
+ )
+
+ @get:Rule
+ val useCameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+ CameraControllerFragmentTest.testCameraRule,
+ CameraUtil.PreTestCameraIdList(cameraConfig)
+ )
+
+ @get:Rule
+ val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ android.Manifest.permission.RECORD_AUDIO
+ )
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private lateinit var cameraProvider: ProcessCameraProvider
+ private lateinit var fragment: EffectsFragment
+ private lateinit var fragmentScenario: FragmentScenario<EffectsFragment>
+
+ @Before
+ fun setup() {
+ // Clear the device UI and check if there is no dialog or lock screen on the top of the
+ // window before start the test.
+ CoreAppTestUtil.prepareDeviceUI(instrumentation)
+ ProcessCameraProvider.configureInstance(cameraConfig)
+ cameraProvider = ProcessCameraProvider.getInstance(
+ ApplicationProvider.getApplicationContext()
+ )[10000, TimeUnit.MILLISECONDS]
+ fragmentScenario = FragmentScenario.launchInContainer(
+ EffectsFragment::class.java, null, R.style.AppTheme,
+ null
+ )
+ fragment = fragmentScenario.getFragment()
+ }
+
+ @After
+ fun tearDown() {
+ if (::fragmentScenario.isInitialized) {
+ fragmentScenario.moveToState(Lifecycle.State.DESTROYED)
+ }
+ if (::cameraProvider.isInitialized) {
+ cameraProvider.shutdown()[10000, TimeUnit.MILLISECONDS]
+ }
+ }
+
+ @Test
+ fun launchFragment_surfaceProcessorIsActive() {
+ // Arrange.
+ fragment.assertPreviewStreaming()
+ // Assert.
+ assertThat(fragment.getSurfaceProcessor().isSurfaceRequestedAndProvided()).isTrue()
+ }
+
+ @Test
+ fun takePicture_imageEffectInvoked() {
+ // Arrange.
+ fragment.run {
+ assertPreviewStreaming()
+ // Act.
+ assertCanTakePicture()
+ }
+ // Assert.
+ assertThat(fragment.getImageEffect()!!.isInvoked()).isTrue()
+ }
+
+ @Test
+ fun shareToImageCapture_canTakePicture() {
+ // Act.
+ instrumentation.runOnMainSync {
+ fragment.surfaceEffectForImageCapture.isChecked = true
+ }
+ // Assert.
+ fragment.assertPreviewStreaming()
+ fragment.assertCanTakePicture()
+ assertThat(fragment.getImageEffect()).isNull()
+ }
+
+ private fun FragmentScenario<EffectsFragment>.getFragment(): EffectsFragment {
+ var fragment: EffectsFragment? = null
+ this.onFragment { newValue: EffectsFragment -> fragment = newValue }
+ return fragment!!
+ }
+
+ private fun EffectsFragment.assertCanTakePicture() {
+ val imageCallbackSemaphore = Semaphore(0)
+ var uri: Uri? = null
+ instrumentation.runOnMainSync {
+ this.takePicture(object : ImageCapture.OnImageSavedCallback {
+ override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
+ uri = outputFileResults.savedUri
+ imageCallbackSemaphore.release()
+ }
+
+ override fun onError(exception: ImageCaptureException) {
+ imageCallbackSemaphore.release()
+ }
+ })
+ }
+ assertThat(imageCallbackSemaphore.tryAcquire(TIMEOUT_SECONDS, TimeUnit.SECONDS)).isTrue()
+ assertThat(uri).isNotNull()
+ }
+
+ private fun EffectsFragment.assertPreviewStreaming() {
+ val previewStreaming = Semaphore(0)
+ instrumentation.runOnMainSync {
+ previewView.previewStreamState.observe(
+ this
+ ) {
+ if (it == PreviewView.StreamState.STREAMING) {
+ previewStreaming.release()
+ }
+ }
+ }
+ assertThat(previewStreaming.tryAcquire(TIMEOUT_SECONDS, TimeUnit.SECONDS)).isTrue()
+ }
+
+ companion object {
+ const val TIMEOUT_SECONDS = 10L
+
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun data() = listOf(
+ arrayOf(Camera2Config::class.simpleName, Camera2Config.defaultConfig()),
+ arrayOf(CameraPipeConfig::class.simpleName, CameraPipeConfig.defaultConfig())
+ )
+ }
+}
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
index 8a33987..ac558e5 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
@@ -20,8 +20,6 @@
import static androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor;
import static androidx.camera.video.VideoRecordEvent.Finalize.ERROR_NONE;
-import static java.util.Arrays.asList;
-
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Dialog;
@@ -85,7 +83,6 @@
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
-import java.util.HashSet;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
@@ -108,7 +105,6 @@
private FrameLayout mContainer;
private Button mFlashMode;
private ToggleButton mCameraToggle;
- private ToggleButton mEffectToggle;
private ExecutorService mExecutorService;
private ToggleButton mCaptureEnabledToggle;
private ToggleButton mAnalysisEnabledToggle;
@@ -146,10 +142,6 @@
@Nullable
private ImageAnalysis.Analyzer mWrappedAnalyzer;
- @VisibleForTesting
- ToneMappingSurfaceEffect mToneMappingSurfaceEffect;
- ToneMappingImageEffect mToneMappingImageEffect;
-
private final ImageAnalysis.Analyzer mAnalyzer = image -> {
byte[] bytes = new byte[image.getPlanes()[0].getBuffer().remaining()];
image.getPlanes()[0].getBuffer().get(bytes);
@@ -217,13 +209,6 @@
}
});
- // Set up post-processing effects.
- mToneMappingSurfaceEffect = new ToneMappingSurfaceEffect();
- mToneMappingImageEffect = new ToneMappingImageEffect();
- mEffectToggle = view.findViewById(R.id.effect_toggle);
- mEffectToggle.setOnCheckedChangeListener((compoundButton, isChecked) -> onEffectsToggled());
- onEffectsToggled();
-
// Set up the button to change the PreviewView's size.
view.findViewById(R.id.shrink).setOnClickListener(v -> {
// Shrinks PreviewView by 10% each time it's clicked.
@@ -366,16 +351,6 @@
mExecutorService.shutdown();
}
mRotationProvider.removeListener(mRotationListener);
- mToneMappingSurfaceEffect.release();
- }
-
- private void onEffectsToggled() {
- if (mEffectToggle.isChecked()) {
- mCameraController.setEffects(
- new HashSet<>(asList(mToneMappingSurfaceEffect, mToneMappingImageEffect)));
- } else {
- mCameraController.clearEffects();
- }
}
void checkFailedFuture(ListenableFuture<Void> voidFuture) {
@@ -388,7 +363,7 @@
@Override
public void onFailure(@NonNull Throwable t) {
- toast(t.getMessage());
+ toast(t.toString());
}
}, mainThreadExecutor());
}
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/EffectsFragment.kt b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/EffectsFragment.kt
new file mode 100644
index 0000000..e658411
--- /dev/null
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/EffectsFragment.kt
@@ -0,0 +1,256 @@
+/*
+ * 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.view
+
+import android.annotation.SuppressLint
+import android.content.ContentValues
+import android.os.Bundle
+import android.os.Environment
+import android.provider.MediaStore
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.RadioButton
+import android.widget.RadioGroup
+import android.widget.Toast
+import androidx.annotation.VisibleForTesting
+import androidx.camera.core.CameraEffect
+import androidx.camera.core.CameraEffect.IMAGE_CAPTURE
+import androidx.camera.core.CameraEffect.PREVIEW
+import androidx.camera.core.CameraEffect.VIDEO_CAPTURE
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.CameraSelector.LENS_FACING_BACK
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCapture.OutputFileOptions
+import androidx.camera.core.ImageCaptureException
+import androidx.camera.core.impl.utils.executor.CameraXExecutors.directExecutor
+import androidx.camera.video.MediaStoreOutputOptions
+import androidx.camera.video.Recording
+import androidx.camera.video.VideoRecordEvent
+import androidx.camera.video.VideoRecordEvent.Finalize.ERROR_DURATION_LIMIT_REACHED
+import androidx.camera.video.VideoRecordEvent.Finalize.ERROR_FILE_SIZE_LIMIT_REACHED
+import androidx.camera.video.VideoRecordEvent.Finalize.ERROR_INSUFFICIENT_STORAGE
+import androidx.camera.video.VideoRecordEvent.Finalize.ERROR_SOURCE_INACTIVE
+import androidx.camera.view.CameraController
+import androidx.camera.view.LifecycleCameraController
+import androidx.camera.view.PreviewView
+import androidx.camera.view.video.AudioConfig
+import androidx.fragment.app.Fragment
+
+/**
+ * Fragment for testing effects integration.
+ */
+class EffectsFragment : Fragment() {
+
+ private lateinit var cameraController: LifecycleCameraController
+ lateinit var previewView: PreviewView
+ private lateinit var surfaceEffectForPreviewVideo: RadioButton
+ lateinit var surfaceEffectForImageCapture: RadioButton
+ private lateinit var imageEffectForImageCapture: RadioButton
+ private lateinit var previewVideoGroup: RadioGroup
+ private lateinit var imageGroup: RadioGroup
+ private lateinit var capture: Button
+ private lateinit var record: Button
+ private lateinit var flip: Button
+ private var recording: Recording? = null
+ private lateinit var surfaceProcessor: ToneMappingSurfaceProcessor
+ private var imageEffect: ToneMappingImageEffect? = null
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ // Inflate the layout for this fragment.
+ val view = inflater.inflate(R.layout.effects_view, container, false)
+ previewView = view.findViewById(R.id.preview_view)
+ surfaceEffectForPreviewVideo = view.findViewById(R.id.surface_effect_for_preview_video)
+ surfaceEffectForImageCapture = view.findViewById(R.id.surface_effect_for_image_capture)
+ imageEffectForImageCapture = view.findViewById(R.id.image_effect_for_image_capture)
+ previewVideoGroup = view.findViewById(R.id.preview_and_video_effect_group)
+ imageGroup = view.findViewById(R.id.image_effect_group)
+ capture = view.findViewById(R.id.capture)
+ record = view.findViewById(R.id.record)
+ flip = view.findViewById(R.id.flip)
+ // Set up UI events.
+ // previewView.implementationMode = PreviewView.ImplementationMode.COMPATIBLE
+ previewVideoGroup.setOnCheckedChangeListener { _, _ -> updateEffects() }
+ imageGroup.setOnCheckedChangeListener { _, _ -> updateEffects() }
+ capture.setOnClickListener { takePicture() }
+ record.setOnClickListener {
+ if (recording == null) {
+ startRecording()
+ } else {
+ stopRecording()
+ }
+ }
+ flip.setOnClickListener {
+ if (cameraController.cameraSelector.lensFacing == LENS_FACING_BACK) {
+ cameraController.cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA
+ } else {
+ cameraController.cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+ }
+ }
+ // Set up the surface processor.
+ surfaceProcessor = ToneMappingSurfaceProcessor()
+ // Set up the camera controller.
+ cameraController = LifecycleCameraController(requireContext())
+ cameraController.setEnabledUseCases(
+ CameraController.IMAGE_CAPTURE or CameraController.VIDEO_CAPTURE
+ )
+ previewView.controller = cameraController
+ updateEffects()
+ cameraController.bindToLifecycle(viewLifecycleOwner)
+ return view
+ }
+
+ private fun updateEffects() {
+ try {
+ val effects = mutableSetOf<CameraEffect>()
+ var surfaceEffectTarget = 0
+ if (surfaceEffectForPreviewVideo.isChecked) {
+ surfaceEffectTarget = surfaceEffectTarget or PREVIEW or VIDEO_CAPTURE
+ }
+ if (surfaceEffectForImageCapture.isChecked) {
+ surfaceEffectTarget = surfaceEffectTarget or IMAGE_CAPTURE
+ }
+ if (surfaceEffectTarget != 0) {
+ effects.add(
+ ToneMappingSurfaceEffect(
+ surfaceEffectTarget,
+ surfaceProcessor
+ )
+ )
+ }
+ if (imageEffectForImageCapture.isChecked) {
+ // Use ImageEffect for image capture
+ imageEffect = ToneMappingImageEffect()
+ effects.add(imageEffect!!)
+ } else {
+ imageEffect = null
+ }
+ cameraController.setEffects(effects)
+ } catch (e: RuntimeException) {
+ toast("Failed to set effects: $e")
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ surfaceProcessor.release()
+ }
+
+ private fun toast(message: String?) {
+ requireActivity().runOnUiThread {
+ Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ private fun takePicture() {
+ takePicture(
+ object : ImageCapture.OnImageSavedCallback {
+ override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
+ toast("Image saved successfully.")
+ }
+
+ override fun onError(exception: ImageCaptureException) {
+ toast("Image capture failed. $exception")
+ }
+ }
+ )
+ }
+
+ fun takePicture(onImageSavedCallback: ImageCapture.OnImageSavedCallback) {
+ createDefaultPictureFolderIfNotExist()
+ val contentValues = ContentValues()
+ contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
+ val outputFileOptions = OutputFileOptions.Builder(
+ requireContext().contentResolver,
+ MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ contentValues
+ ).build()
+ cameraController.takePicture(
+ outputFileOptions,
+ directExecutor(),
+ onImageSavedCallback
+ )
+ }
+
+ @SuppressLint("MissingPermission")
+ private fun startRecording() {
+ record.text = "Stop recording"
+ val outputOptions: MediaStoreOutputOptions = getNewVideoOutputMediaStoreOptions()
+ val audioConfig = AudioConfig.create(true)
+ recording = cameraController.startRecording(
+ outputOptions, audioConfig,
+ directExecutor()
+ ) {
+ if (it is VideoRecordEvent.Finalize) {
+ val uri = it.outputResults.outputUri
+ when (it.error) {
+ VideoRecordEvent.Finalize.ERROR_NONE,
+ ERROR_FILE_SIZE_LIMIT_REACHED,
+ ERROR_DURATION_LIMIT_REACHED,
+ ERROR_INSUFFICIENT_STORAGE,
+ ERROR_SOURCE_INACTIVE -> toast("Video saved to: $uri")
+
+ else -> toast("Failed to save video: uri $uri with code (${it.error})")
+ }
+ }
+ }
+ }
+
+ private fun stopRecording() {
+ record.text = "Record"
+ recording?.stop()
+ }
+
+ private fun getNewVideoOutputMediaStoreOptions(): MediaStoreOutputOptions {
+ val videoFileName = "video_" + System.currentTimeMillis()
+ val resolver = requireContext().contentResolver
+ val contentValues = ContentValues()
+ contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
+ contentValues.put(MediaStore.Video.Media.TITLE, videoFileName)
+ contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, videoFileName)
+ return MediaStoreOutputOptions.Builder(
+ resolver,
+ MediaStore.Video.Media.EXTERNAL_CONTENT_URI
+ ).setContentValues(contentValues)
+ .build()
+ }
+
+ private fun createDefaultPictureFolderIfNotExist() {
+ val pictureFolder = Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES
+ )
+ if (!pictureFolder.exists()) {
+ if (!pictureFolder.mkdir()) {
+ toast("Failed to create directory: $pictureFolder")
+ }
+ }
+ }
+
+ @VisibleForTesting
+ fun getImageEffect(): ToneMappingImageEffect? {
+ return imageEffect
+ }
+
+ @VisibleForTesting
+ fun getSurfaceProcessor(): ToneMappingSurfaceProcessor {
+ return surfaceProcessor
+ }
+}
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java
index 970b5d8..6e40f89 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java
@@ -190,6 +190,9 @@
case R.id.mlkit:
mFragmentType = FragmentType.MLKIT;
break;
+ case R.id.effects:
+ mFragmentType = FragmentType.EFFECTS;
+ break;
}
startFragment();
return true;
@@ -222,6 +225,9 @@
case MLKIT:
startFragment(R.string.mlkit, new MlKitFragment());
break;
+ case EFFECTS:
+ startFragment(R.string.effects, new EffectsFragment());
+ break;
}
}
@@ -243,6 +249,6 @@
}
private enum FragmentType {
- PREVIEW_VIEW, CAMERA_CONTROLLER, TRANSFORM, COMPOSE_UI, MLKIT
+ PREVIEW_VIEW, CAMERA_CONTROLLER, TRANSFORM, COMPOSE_UI, MLKIT, EFFECTS
}
}
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingSurfaceProcessor.kt b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingSurfaceProcessor.kt
index 33ac70c..7f67745 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingSurfaceProcessor.kt
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingSurfaceProcessor.kt
@@ -22,6 +22,7 @@
import android.os.HandlerThread
import android.view.Surface
import androidx.annotation.VisibleForTesting
+import androidx.camera.core.DynamicRange
import androidx.camera.core.SurfaceOutput
import androidx.camera.core.SurfaceProcessor
import androidx.camera.core.SurfaceRequest
@@ -82,7 +83,7 @@
glHandler = Handler(glThread.looper)
glExecutor = newHandlerExecutor(glHandler)
glExecutor.execute {
- glRenderer.init(TONE_MAPPING_SHADER_PROVIDER)
+ glRenderer.init(DynamicRange.SDR, TONE_MAPPING_SHADER_PROVIDER)
}
}
diff --git a/camera/integration-tests/viewtestapp/src/main/res/layout-land/camera_controller_view.xml b/camera/integration-tests/viewtestapp/src/main/res/layout-land/camera_controller_view.xml
index 127eedd..f8cd281 100644
--- a/camera/integration-tests/viewtestapp/src/main/res/layout-land/camera_controller_view.xml
+++ b/camera/integration-tests/viewtestapp/src/main/res/layout-land/camera_controller_view.xml
@@ -51,12 +51,6 @@
android:layout_height="wrap_content"
android:textOff="@string/toggle_camera_front"
android:textOn="@string/toggle_camera_back" />
- <ToggleButton
- android:id="@+id/effect_toggle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textOff="@string/toggle_effect_off"
- android:textOn="@string/toggle_effect_on" />
</LinearLayout>
<LinearLayout
diff --git a/camera/integration-tests/viewtestapp/src/main/res/layout-land/effects_view.xml b/camera/integration-tests/viewtestapp/src/main/res/layout-land/effects_view.xml
new file mode 100644
index 0000000..cbf1b36
--- /dev/null
+++ b/camera/integration-tests/viewtestapp/src/main/res/layout-land/effects_view.xml
@@ -0,0 +1,120 @@
+<?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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="0dp">
+ <androidx.camera.view.PreviewView
+ android:id="@+id/preview_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:gravity="center_horizontal">
+ <Button
+ android:id="@+id/flip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/flip"
+ android:layout_margin="15dp"/>
+ <Button
+ android:id="@+id/capture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/btn_capture"
+ android:layout_margin="15dp"/>
+ <Button
+ android:id="@+id/record"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/btn_video_record"
+ android:layout_margin="15dp"/>
+ </LinearLayout>
+ </RelativeLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="20dp">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:text="@string/preview_and_video"/>
+ <RadioGroup
+ android:id="@+id/preview_and_video_effect_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <RadioButton
+ android:id="@+id/surface_effect_for_preview_video"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="@string/surface_effect"/>
+ <RadioButton
+ android:id="@+id/no_effect_for_preview_video"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="false"
+ android:text="@string/no_effect"/>
+ </RadioGroup>
+ </LinearLayout>
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:text="@string/image_capture"/>
+ <RadioGroup
+ android:id="@+id/image_effect_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <RadioButton
+ android:id="@+id/surface_effect_for_image_capture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="false"
+ android:text="@string/surface_effect"/>
+ <RadioButton
+ android:id="@+id/image_effect_for_image_capture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="@string/image_effect"/>
+ <RadioButton
+ android:id="@+id/no_effect_for_image_capture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="false"
+ android:text="@string/no_effect"/>
+ </RadioGroup>
+ </LinearLayout>
+ </LinearLayout>
+</LinearLayout>
diff --git a/camera/integration-tests/viewtestapp/src/main/res/layout/camera_controller_view.xml b/camera/integration-tests/viewtestapp/src/main/res/layout/camera_controller_view.xml
index abdbd23..d605440 100644
--- a/camera/integration-tests/viewtestapp/src/main/res/layout/camera_controller_view.xml
+++ b/camera/integration-tests/viewtestapp/src/main/res/layout/camera_controller_view.xml
@@ -48,12 +48,6 @@
android:layout_height="wrap_content"
android:textOff="@string/toggle_camera_front"
android:textOn="@string/toggle_camera_back" />
- <ToggleButton
- android:id="@+id/effect_toggle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textOff="@string/toggle_effect_off"
- android:textOn="@string/toggle_effect_on" />
</LinearLayout>
<LinearLayout
diff --git a/camera/integration-tests/viewtestapp/src/main/res/layout/effects_view.xml b/camera/integration-tests/viewtestapp/src/main/res/layout/effects_view.xml
new file mode 100644
index 0000000..10d7332
--- /dev/null
+++ b/camera/integration-tests/viewtestapp/src/main/res/layout/effects_view.xml
@@ -0,0 +1,121 @@
+<?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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="0dp">
+ <androidx.camera.view.PreviewView
+ android:id="@+id/preview_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:gravity="center_horizontal">
+ <Button
+ android:id="@+id/flip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/flip"
+ android:layout_margin="15dp"/>
+ <Button
+ android:id="@+id/capture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/btn_capture"
+ android:layout_margin="15dp"/>
+ <Button
+ android:id="@+id/record"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/btn_video_record"
+ android:layout_margin="15dp"/>
+ </LinearLayout>
+ </RelativeLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="20dp">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:text="@string/preview_and_video"/>
+ <RadioGroup
+ android:id="@+id/preview_and_video_effect_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <RadioButton
+ android:id="@+id/surface_effect_for_preview_video"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="@string/surface_effect"/>
+ <RadioButton
+ android:id="@+id/no_effect_for_preview_video"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="false"
+ android:text="@string/no_effect"/>
+ </RadioGroup>
+ </LinearLayout>
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:text="@string/image_capture"/>
+ <RadioGroup
+ android:id="@+id/image_effect_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <RadioButton
+ android:id="@+id/surface_effect_for_image_capture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="false"
+ android:text="@string/surface_effect"/>
+ <RadioButton
+ android:id="@+id/image_effect_for_image_capture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="@string/image_effect"/>
+ <RadioButton
+ android:id="@+id/no_effect_for_image_capture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="false"
+ android:text="@string/no_effect"/>
+ </RadioGroup>
+ </LinearLayout>
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/camera/integration-tests/viewtestapp/src/main/res/menu/actionbar_menu.xml b/camera/integration-tests/viewtestapp/src/main/res/menu/actionbar_menu.xml
index 4a8d889..b850fd4 100644
--- a/camera/integration-tests/viewtestapp/src/main/res/menu/actionbar_menu.xml
+++ b/camera/integration-tests/viewtestapp/src/main/res/menu/actionbar_menu.xml
@@ -33,6 +33,10 @@
android:title="@string/compose_ui"
app:showAsAction="never" />
<item
+ android:id="@+id/effects"
+ android:title="@string/effects"
+ app:showAsAction="never" />
+ <item
android:id="@+id/mlkit"
android:title="@string/mlkit"
app:showAsAction="never" />
diff --git a/camera/integration-tests/viewtestapp/src/main/res/values/donottranslate-strings.xml b/camera/integration-tests/viewtestapp/src/main/res/values/donottranslate-strings.xml
index 1c62930..ededb27 100644
--- a/camera/integration-tests/viewtestapp/src/main/res/values/donottranslate-strings.xml
+++ b/camera/integration-tests/viewtestapp/src/main/res/values/donottranslate-strings.xml
@@ -16,8 +16,14 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="app_name">CameraX Views Demo</string>
-
+ <string name="effects">Effects</string>
<string name="preview">Preview</string>
+ <string name="preview_and_video">Preview & Video</string>
+ <string name="surface_effect">Surface effect</string>
+ <string name="no_effect">No effect</string>
+ <string name="image_effect">Image effect</string>
+ <string name="image_capture">ImageCapture</string>
+ <string name="flip">flip</string>
<string name="btn_capture">Capture</string>
<string name="btn_video_record">Record</string>
<string name="btn_video_stop_recording">Stop recording</string>
diff --git a/car/app/app-automotive/src/main/res/values-et/strings.xml b/car/app/app-automotive/src/main/res/values-et/strings.xml
index 5fcc97b..407f920 100644
--- a/car/app/app-automotive/src/main/res/values-et/strings.xml
+++ b/car/app/app-automotive/src/main/res/values-et/strings.xml
@@ -18,7 +18,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="error_action_finish" msgid="7621130025103996211">"Sule rakendus"</string>
- <string name="error_action_update_host" msgid="4802951804749609593">"Otsige värskendusi"</string>
+ <string name="error_action_update_host" msgid="4802951804749609593">"Otsi värskendusi"</string>
<string name="error_action_retry" msgid="985347670495166517">"Proovi uuesti"</string>
<string name="error_message_client_side_error" msgid="3323186720368387787">"Rakenduse viga. Teavitage sellest veast rakenduse arendajat."</string>
<string name="error_message_host_error" msgid="5484419926049675696">"Süsteemi viga"</string>
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-bn/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-bn/strings.xml
index db5951c..b42e3d6 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-bn/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-bn/strings.xml
@@ -38,7 +38,7 @@
<string name="settings_action_title" msgid="8616900063253887861">"সেটিংস"</string>
<string name="accept_action_title" msgid="4899660585470647578">"সম্মতি দিন"</string>
<string name="reject_action_title" msgid="6730366705938402668">"বাতিল করুন"</string>
- <string name="ok_action_title" msgid="7128494973966098611">"ওকে"</string>
+ <string name="ok_action_title" msgid="7128494973966098611">"ঠিক আছে"</string>
<string name="throw_action_title" msgid="7163710562670220163">"থ্রো"</string>
<string name="commute_action_title" msgid="2585755255290185096">"যাতায়াত করুন"</string>
<string name="sign_out_action_title" msgid="1653943000866713010">"সাইন-আউট করুন"</string>
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-ky/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-ky/strings.xml
index e753de6..be2c89f 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-ky/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-ky/strings.xml
@@ -251,7 +251,7 @@
<string name="password_hint" msgid="2869107073860012864">"сырсөз"</string>
<string name="password_sign_in_instruction_prefix" msgid="9105788349198243508">"Колдонуучунун аты"</string>
<string name="pin_sign_in_instruction" msgid="2288691296234360441">"Телефонуңузда бул PIN кодду киргизиңиз"</string>
- <string name="qr_code_sign_in_title" msgid="8137070561006464518">"Кирүү үчүн QR кодун скандаңыз"</string>
+ <string name="qr_code_sign_in_title" msgid="8137070561006464518">"Кирүү үчүн QR кодду скандаңыз"</string>
<string name="sign_in_with_google_title" msgid="8043752000786977249">"Google аккаунту менен кирүү"</string>
<string name="provider_sign_in_instruction" msgid="7586815688292506743">"Google\'га кирүүңүздү аягына чыгаруу үчүн бул баскычты колдонуңуз"</string>
<string name="sign_in_complete_text" msgid="8423984266325680606">"Сиз кирдиңиз!"</string>
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-zh-rCN/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-zh-rCN/strings.xml
index 5a5455f..056b612 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-zh-rCN/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-zh-rCN/strings.xml
@@ -41,7 +41,7 @@
<string name="ok_action_title" msgid="7128494973966098611">"确定"</string>
<string name="throw_action_title" msgid="7163710562670220163">"抛出"</string>
<string name="commute_action_title" msgid="2585755255290185096">"通勤"</string>
- <string name="sign_out_action_title" msgid="1653943000866713010">"退出"</string>
+ <string name="sign_out_action_title" msgid="1653943000866713010">"退出帐号"</string>
<string name="try_anyway_action_title" msgid="7384500054249311718">"仍然尝试"</string>
<string name="yes_action_title" msgid="5507096013762092189">"是"</string>
<string name="no_action_title" msgid="1452124604210014010">"否"</string>
diff --git a/car/app/app/api/current.txt b/car/app/app/api/current.txt
index b28d7ca..4190465 100644
--- a/car/app/app/api/current.txt
+++ b/car/app/app/api/current.txt
@@ -1168,7 +1168,7 @@
@androidx.car.app.annotations.CarProtocol public final class GridTemplate implements androidx.car.app.model.Template {
method public androidx.car.app.model.ActionStrip? getActionStrip();
- method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+ method @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 @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemImageShape();
method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemSize();
@@ -1184,7 +1184,7 @@
public static final class GridTemplate.Builder {
ctor public GridTemplate.Builder();
- method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.GridTemplate.Builder addAction(androidx.car.app.model.Action);
+ method @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);
@@ -1253,7 +1253,7 @@
@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.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+ 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();
@@ -1264,7 +1264,7 @@
public static final class ListTemplate.Builder {
ctor public ListTemplate.Builder();
- method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.ListTemplate.Builder addAction(androidx.car.app.model.Action);
+ 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 @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ListTemplate.Builder clearSectionedLists();
diff --git a/car/app/app/api/restricted_current.txt b/car/app/app/api/restricted_current.txt
index b28d7ca..4190465 100644
--- a/car/app/app/api/restricted_current.txt
+++ b/car/app/app/api/restricted_current.txt
@@ -1168,7 +1168,7 @@
@androidx.car.app.annotations.CarProtocol public final class GridTemplate implements androidx.car.app.model.Template {
method public androidx.car.app.model.ActionStrip? getActionStrip();
- method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+ method @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 @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemImageShape();
method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemSize();
@@ -1184,7 +1184,7 @@
public static final class GridTemplate.Builder {
ctor public GridTemplate.Builder();
- method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.GridTemplate.Builder addAction(androidx.car.app.model.Action);
+ method @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);
@@ -1253,7 +1253,7 @@
@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.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+ 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();
@@ -1264,7 +1264,7 @@
public static final class ListTemplate.Builder {
ctor public ListTemplate.Builder();
- method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.ListTemplate.Builder addAction(androidx.car.app.model.Action);
+ 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 @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ListTemplate.Builder clearSectionedLists();
diff --git a/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java
index b7b6314..04100f8 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java
@@ -217,7 +217,7 @@
*/
@ExperimentalCarApi
@NonNull
- @RequiresCarApi(6)
+ @RequiresCarApi(7)
public List<Action> getActions() {
return mActions;
}
@@ -418,7 +418,7 @@
*/
@ExperimentalCarApi
@NonNull
- @RequiresCarApi(6)
+ @RequiresCarApi(7)
public Builder addAction(@NonNull Action action) {
List<Action> mActionsCopy = new ArrayList<>(mActions);
mActionsCopy.add(requireNonNull(action));
diff --git a/car/app/app/src/main/java/androidx/car/app/model/ListTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/ListTemplate.java
index 012b791..ebfa5fc 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/ListTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/ListTemplate.java
@@ -140,7 +140,6 @@
*
* @see ListTemplate.Builder#addAction(Action)
*/
- @ExperimentalCarApi
@NonNull
@RequiresCarApi(6)
public List<Action> getActions() {
@@ -385,7 +384,6 @@
* background {@link CarColor}, or if exceeds the
* maximum number of allowed actions (1) for the template.
*/
- @ExperimentalCarApi
@NonNull
@RequiresCarApi(6)
public Builder addAction(@NonNull Action action) {
diff --git a/car/app/app/src/main/java/androidx/car/app/model/TabContents.java b/car/app/app/src/main/java/androidx/car/app/model/TabContents.java
index b16cbd3..84c1a68 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/TabContents.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/TabContents.java
@@ -18,8 +18,6 @@
import static java.util.Objects.requireNonNull;
-import android.annotation.SuppressLint;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.car.app.annotations.CarProtocol;
@@ -123,7 +121,6 @@
* @throws NullPointerException if {@code template} is null
* @throws IllegalArgumentException if {@code template} does not meet the requirements
*/
- @SuppressLint("ExecutorRegistration")
public Builder(@NonNull Template template) {
TabContentsConstraints.DEFAULT.validateOrThrow(requireNonNull(template));
mTemplate = template;
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
index e729d44..434a88d 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
@@ -39,6 +39,7 @@
import androidx.compose.animation.demos.lookahead.CraneDemo
import androidx.compose.animation.demos.lookahead.LookaheadLayoutWithAlignmentLinesDemo
import androidx.compose.animation.demos.lookahead.LookaheadSamplesDemo
+import androidx.compose.animation.demos.lookahead.LookaheadWithAnimatedContentSize
import androidx.compose.animation.demos.lookahead.LookaheadWithBoxWithConstraints
import androidx.compose.animation.demos.lookahead.LookaheadWithDisappearingMovableContentDemo
import androidx.compose.animation.demos.lookahead.LookaheadWithFlowRowDemo
@@ -112,6 +113,9 @@
},
ComposableDemo("Crane Nested Shared Element") { CraneDemo() },
ComposableDemo("Screen Size Change Demo") { ScreenSizeChangeDemo() },
+ ComposableDemo("LookaheadWithAnimatedContentSize") {
+ LookaheadWithAnimatedContentSize()
+ },
ComposableDemo("Lookahead Samples Demo") {
LookaheadSamplesDemo()
},
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/AnimatedVisibilityDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/AnimatedVisibilityDemo.kt
index 0f679fd..efb8e8f 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/AnimatedVisibilityDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/AnimatedVisibilityDemo.kt
@@ -225,7 +225,6 @@
}
}
-@OptIn(ExperimentalAnimationApi::class)
@Composable
fun FullyLoadedTransition(visible: Boolean, content: @Composable () -> Unit) {
AnimatedVisibility(
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithAnimatedContentSize.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithAnimatedContentSize.kt
new file mode 100644
index 0000000..feb0fd75
--- /dev/null
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithAnimatedContentSize.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.animation.demos.lookahead
+
+import androidx.compose.animation.animateContentSize
+import androidx.compose.animation.demos.gesture.pastelColors
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.produceState
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.LookaheadScope
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.zIndex
+import kotlinx.coroutines.delay
+
+@Preview
+@OptIn(ExperimentalComposeUiApi::class)
+@Composable
+fun LookaheadWithAnimatedContentSize() {
+ val expanded by produceState(initialValue = true) {
+ while (true) {
+ delay(3000)
+ value = !value
+ }
+ }
+ LookaheadScope {
+ Column {
+ Column(
+ Modifier
+ .then(
+ if (expanded) Modifier.fillMaxWidth() else Modifier
+ )
+ .animateContentSize()
+ .zIndex(2f)
+ ) {
+ Box(
+ Modifier
+ .fillMaxWidth()
+ .height(100.dp)
+ .background(pastelColors[0])
+ )
+ if (expanded) {
+ Box(
+ Modifier
+ .fillMaxWidth()
+ .height(200.dp)
+ .background(Color.White)
+ )
+ }
+ }
+ Box(
+ Modifier
+ .animateBounds()
+ .fillMaxWidth()
+ .height(100.dp)
+ .background(pastelColors[1])
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithDisappearingMoveableContentDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithDisappearingMoveableContentDemo.kt
index 7efce9a..9704813 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithDisappearingMoveableContentDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithDisappearingMoveableContentDemo.kt
@@ -20,18 +20,20 @@
import android.annotation.SuppressLint
import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.animateContentSize
+import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.spring
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
+import androidx.compose.animation.slideOutHorizontally
+import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@@ -47,54 +49,62 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.LookaheadScope
import androidx.compose.ui.layout.intermediateLayout
+import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.round
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.delay
+@Preview
@Composable
fun LookaheadWithDisappearingMovableContentDemo() {
- Box(
- Modifier
- .fillMaxSize()
- .padding(start = 50.dp, top = 200.dp)
- ) {
- LookaheadScope {
- val icon = remember {
- movableContentOf<Boolean> {
- MyIcon(it, Modifier.animatePosition())
- }
+ LookaheadScope {
+ val isCompact by produceState(initialValue = false) {
+ while (true) {
+ delay(3000)
+ value = !value
}
- val title = remember {
- movableContentOf<Boolean> {
- Title(visible = it, Modifier.animatePosition())
- }
- }
- val details = remember {
- movableContentOf<Boolean> {
- Details(visible = it, Modifier.animatePosition())
- }
- }
+ }
+ Column {
- val isCompact by produceState(initialValue = false) {
- while (true) {
- delay(2000)
- value = !value
- }
- }
- Row(Modifier.background(Color.Yellow), verticalAlignment = Alignment.CenterVertically) {
- if (isCompact) {
- icon(true)
- Column {
- title(true)
- details(true)
+ Box(
+ Modifier
+ .padding(start = 50.dp, top = 200.dp, bottom = 100.dp)
+ ) {
+ val icon = remember {
+ movableContentOf<Boolean> {
+ MyIcon(it)
}
- } else {
- icon(false)
- Column {
- title(true)
- details(false)
+ }
+ val title = remember {
+ movableContentOf<Boolean> {
+ Title(visible = it, Modifier.animatePosition())
+ }
+ }
+ val details = remember {
+ movableContentOf<Boolean> {
+ Details(visible = it)
+ }
+ }
+
+ Row(
+ Modifier
+ .background(Color.Yellow)
+ .animateContentSize(), verticalAlignment = Alignment.CenterVertically
+ ) {
+ if (isCompact) {
+ icon(true)
+ Column {
+ title(true)
+ details(true)
+ }
+ } else {
+ icon(false)
+ Column {
+ title(true)
+ details(false)
+ }
}
}
}
@@ -104,7 +114,12 @@
@Composable
fun MyIcon(visible: Boolean, modifier: Modifier = Modifier) {
- AV2(visible, modifier) {
+ AnimatedVisibility(
+ visible,
+ enter = fadeIn(),
+ exit = fadeOut() + slideOutHorizontally { -it },
+ modifier = modifier
+ ) {
Box(
modifier
.size(40.dp)
@@ -115,33 +130,24 @@
@Composable
fun Title(visible: Boolean, modifier: Modifier = Modifier) {
- AV2(visible, modifier) {
+ AnimatedVisibility(visible, enter = fadeIn(), exit = fadeOut(), modifier = modifier) {
Text("Text", modifier, fontSize = 30.sp)
}
}
@Composable
fun Details(visible: Boolean, modifier: Modifier = Modifier) {
- AV2(visible, modifier) {
+ AnimatedVisibility(
+ visible, enter = fadeIn(),
+ exit = fadeOut() + slideOutVertically { it },
+ modifier = modifier
+ ) {
Text("Detailed Text", fontSize = 18.sp)
}
}
-@Composable
-fun AV2(visible: Boolean, modifier: Modifier = Modifier, content: @Composable () -> Unit) {
- AnimatedVisibility(
- visible, enter = fadeIn(), exit = fadeOut(), modifier = modifier.then(
- if (!visible) Modifier
- .size(0.dp)
- .wrapContentSize() else Modifier
- )
- ) {
- content()
- }
-}
-
context(LookaheadScope)
- @SuppressLint("UnnecessaryComposedModifier")
+@SuppressLint("UnnecessaryComposedModifier")
fun Modifier.animatePosition(): Modifier = composed {
val offsetAnimation = remember {
DeferredAnimation(IntOffset.VectorConverter)
@@ -151,15 +157,16 @@
layout(width, height) {
val (x, y) =
coordinates?.let { coordinates ->
+ val origin = this.lookaheadScopeCoordinates
offsetAnimation.updateTarget(
- lookaheadScopeCoordinates.localLookaheadPositionOf(
+ origin.localLookaheadPositionOf(
coordinates
)
.round(),
- spring(),
+ spring(stiffness = Spring.StiffnessMediumLow),
)
val currentOffset =
- lookaheadScopeCoordinates.localPositionOf(
+ origin.localPositionOf(
coordinates,
Offset.Zero
)
diff --git a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
index dab4a12..e0edcbe 100644
--- a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
+++ b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
@@ -39,9 +39,12 @@
import androidx.compose.runtime.setValue
import androidx.compose.runtime.withFrameNanos
import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.LookaheadScope
+import androidx.compose.ui.layout.layout
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
@@ -495,7 +498,6 @@
}
}
- @OptIn(ExperimentalAnimationApi::class)
@Test
fun testEnterTransitionNoneAndExitTransitionNone() {
val testModifier by mutableStateOf(TestModifier())
@@ -679,4 +681,46 @@
playTimeMs += 20
}
}
+
+ @OptIn(ExperimentalComposeUiApi::class)
+ @Test
+ fun testAnimatedVisibilityInLookaheadScope() {
+ val lookaheadSizes = mutableListOf<IntSize>()
+ var visible by mutableStateOf(true)
+ rule.setContent {
+ CompositionLocalProvider(LocalDensity provides Density(1f)) {
+ LookaheadScope {
+ Box(Modifier.layout { measurable, constraints ->
+ measurable.measure(constraints).run {
+ if (isLookingAhead) {
+ lookaheadSizes.add(IntSize(width, height))
+ }
+ layout(width, height) { place(0, 0) }
+ }
+ }) {
+ AnimatedVisibility(visible = visible) {
+ Box(Modifier.size(200.dp, 100.dp))
+ }
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertTrue(visible)
+ assertTrue(lookaheadSizes.isNotEmpty())
+ lookaheadSizes.forEach {
+ assertEquals(IntSize(200, 100), it)
+ }
+ lookaheadSizes.clear()
+ visible = !visible
+ }
+ rule.runOnIdle {
+ assertFalse(visible)
+ assertTrue(lookaheadSizes.isNotEmpty())
+ lookaheadSizes.forEach {
+ assertEquals(IntSize.Zero, it)
+ }
+ lookaheadSizes.clear()
+ }
+ }
}
diff --git a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt
index ae167df..df4be48 100644
--- a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt
+++ b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt
@@ -20,20 +20,26 @@
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.LayoutModifier
+import androidx.compose.ui.layout.LookaheadScope
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.InspectableValue
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -41,6 +47,8 @@
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertNotNull
import junit.framework.TestCase.assertNull
+import junit.framework.TestCase.assertTrue
+import kotlin.random.Random
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.CoreMatchers.nullValue
import org.hamcrest.MatcherAssert.assertThat
@@ -142,16 +150,64 @@
}
}
+ @OptIn(ExperimentalComposeUiApi::class)
+ @Test
+ fun testAnimatedContentSizeInLookahead() {
+ val lookaheadSizes = mutableListOf<IntSize>()
+ var size by mutableStateOf(IntSize(400, 600))
+ rule.setContent {
+ CompositionLocalProvider(LocalDensity provides Density(1f)) {
+ LookaheadScope {
+ Box(Modifier
+ .layout { measurable, constraints ->
+ measurable
+ .measure(constraints)
+ .run {
+ if (isLookingAhead) {
+ lookaheadSizes.add(IntSize(width, height))
+ }
+ layout(width, height) { place(0, 0) }
+ }
+ }
+ .animateContentSize()
+ .size(size.width.dp, size.height.dp)) {
+ Box(Modifier.size(20.dp))
+ }
+ }
+ }
+ }
+
+ repeat(8) {
+ size = IntSize(
+ Random.nextInt(200, 600),
+ Random.nextInt(100, 800)
+ )
+ lookaheadSizes.clear()
+ rule.runOnIdle {
+ assertTrue(lookaheadSizes.isNotEmpty())
+ lookaheadSizes.forEach {
+ assertEquals(size, it)
+ }
+ }
+ }
+ }
+
@Test
fun testInspectorValue() {
rule.setContent {
- val modifier = Modifier.animateContentSize() as InspectableValue
- assertThat(modifier.nameFallback, `is`("animateContentSize"))
- assertThat(modifier.valueOverride, nullValue())
- assertThat(
- modifier.inspectableElements.map { it.name }.toList(),
- `is`(listOf("animationSpec", "finishedListener"))
- )
+ Modifier.animateContentSize().any {
+ it as InspectableValue
+ if (it.nameFallback == "animateContentSize") {
+ assertThat(it.valueOverride, nullValue())
+ assertThat(
+ it.inspectableElements.map { it.name }.toList(),
+ `is`(listOf("animationSpec", "finishedListener"))
+ )
+ true
+ } else {
+ false
+ }
+ }.also { assertTrue(it) }
}
}
}
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
index 4d49ae5..d15138e 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
@@ -21,15 +21,13 @@
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.AnimationVector2D
import androidx.compose.animation.core.FiniteAnimationSpec
+import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.spring
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.Modifier
-import androidx.compose.ui.composed
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.layout.IntrinsicMeasurable
import androidx.compose.ui.layout.IntrinsicMeasureScope
@@ -37,10 +35,12 @@
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
-import androidx.compose.ui.platform.debugInspectorInfo
+import androidx.compose.ui.node.LayoutModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntSize
-import kotlinx.coroutines.CoroutineScope
+import androidx.compose.ui.unit.constrain
import kotlinx.coroutines.launch
/**
@@ -66,33 +66,58 @@
* completed.
*/
fun Modifier.animateContentSize(
- animationSpec: FiniteAnimationSpec<IntSize> = spring(),
+ animationSpec: FiniteAnimationSpec<IntSize> = spring(
+ stiffness = Spring.StiffnessMediumLow
+ ),
finishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)? = null
-): Modifier = composed(
- inspectorInfo = debugInspectorInfo {
+): Modifier =
+ this.clipToBounds() then SizeAnimationModifierElement(animationSpec, finishedListener)
+
+private data class SizeAnimationModifierElement(
+ val animationSpec: FiniteAnimationSpec<IntSize>,
+ val finishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)?
+) : ModifierNodeElement<SizeAnimationModifierNode>() {
+ override fun create(): SizeAnimationModifierNode =
+ SizeAnimationModifierNode(animationSpec, finishedListener)
+
+ override fun update(node: SizeAnimationModifierNode) {
+ node.animationSpec = animationSpec
+ node.listener = finishedListener
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
name = "animateContentSize"
properties["animationSpec"] = animationSpec
properties["finishedListener"] = finishedListener
}
-) {
- // TODO: Listener could be a fun interface after 1.4
- val scope = rememberCoroutineScope()
- val animModifier = remember(scope) {
- SizeAnimationModifier(animationSpec, scope)
- }
- animModifier.listener = finishedListener
- this.clipToBounds().then(animModifier)
}
+internal val InvalidSize = IntSize(Int.MIN_VALUE, Int.MIN_VALUE)
+internal val IntSize.isValid: Boolean
+ get() = this != InvalidSize
+
/**
* This class creates a [LayoutModifier] that measures children, and responds to children's size
* change by animating to that size. The size reported to parents will be the animated size.
*/
-private class SizeAnimationModifier(
- val animSpec: AnimationSpec<IntSize>,
- val scope: CoroutineScope,
-) : LayoutModifierWithPassThroughIntrinsics() {
+private class SizeAnimationModifierNode(
+ var animationSpec: AnimationSpec<IntSize>,
var listener: ((startSize: IntSize, endSize: IntSize) -> Unit)? = null
+) : LayoutModifierNodeWithPassThroughIntrinsics() {
+ private var lookaheadSize: IntSize = InvalidSize
+ private var lookaheadConstraints: Constraints = Constraints()
+ set(value) {
+ field = value
+ lookaheadConstraintsAvailable = true
+ }
+ private var lookaheadConstraintsAvailable: Boolean = false
+
+ private fun targetConstraints(default: Constraints) =
+ if (lookaheadConstraintsAvailable) {
+ lookaheadConstraints
+ } else {
+ default
+ }
data class AnimData(
val anim: Animatable<IntSize, AnimationVector2D>,
@@ -101,16 +126,36 @@
var animData: AnimData? by mutableStateOf(null)
+ override fun onAttach() {
+ super.onAttach()
+ // When re-attached, we may be attached to a tree without lookahead scope.
+ lookaheadSize = InvalidSize
+ lookaheadConstraintsAvailable = false
+ }
+
override fun MeasureScope.measure(
measurable: Measurable,
constraints: Constraints
): MeasureResult {
-
- val placeable = measurable.measure(constraints)
-
+ val placeable = if (isLookingAhead) {
+ lookaheadConstraints = constraints
+ measurable.measure(constraints)
+ } else {
+ // Measure with lookahead constraints when available, to avoid unnecessary relayout
+ // in child during the lookahead animation.
+ measurable.measure(targetConstraints(constraints))
+ }
val measuredSize = IntSize(placeable.width, placeable.height)
-
- val (width, height) = animateTo(measuredSize)
+ val (width, height) = if (isLookingAhead) {
+ lookaheadSize = measuredSize
+ measuredSize
+ } else {
+ animateTo(if (lookaheadSize.isValid) lookaheadSize else measuredSize).let {
+ // Constrain the measure result to incoming constraints, so that parent doesn't
+ // force center this layout.
+ constraints.constrain(it)
+ }
+ }
return layout(width, height) {
placeable.placeRelative(0, 0)
}
@@ -120,8 +165,8 @@
val data = animData?.apply {
if (targetSize != anim.targetValue) {
startSize = anim.value
- scope.launch {
- val result = anim.animateTo(targetSize, animSpec)
+ coroutineScope.launch {
+ val result = anim.animateTo(targetSize, animationSpec)
if (result.endReason == AnimationEndReason.Finished) {
listener?.invoke(startSize, result.endState.value)
}
@@ -139,6 +184,29 @@
}
}
+internal abstract class LayoutModifierNodeWithPassThroughIntrinsics :
+ LayoutModifierNode, Modifier.Node() {
+ override fun IntrinsicMeasureScope.minIntrinsicWidth(
+ measurable: IntrinsicMeasurable,
+ height: Int
+ ) = measurable.minIntrinsicWidth(height)
+
+ override fun IntrinsicMeasureScope.minIntrinsicHeight(
+ measurable: IntrinsicMeasurable,
+ width: Int
+ ) = measurable.minIntrinsicHeight(width)
+
+ override fun IntrinsicMeasureScope.maxIntrinsicWidth(
+ measurable: IntrinsicMeasurable,
+ height: Int
+ ) = measurable.maxIntrinsicWidth(height)
+
+ override fun IntrinsicMeasureScope.maxIntrinsicHeight(
+ measurable: IntrinsicMeasurable,
+ width: Int
+ ) = measurable.maxIntrinsicHeight(width)
+}
+
internal abstract class LayoutModifierWithPassThroughIntrinsics : LayoutModifier {
final override fun IntrinsicMeasureScope.minIntrinsicWidth(
measurable: IntrinsicMeasurable,
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 6c7d2fa..46189d4 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
@@ -33,27 +33,26 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
-import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.key
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.composed
import androidx.compose.ui.draw.clipToBounds
+import androidx.compose.ui.graphics.GraphicsLayerScope
import androidx.compose.ui.graphics.TransformOrigin
-import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.constrain
@RequiresOptIn(message = "This is an experimental animation API.")
@Target(
@@ -815,6 +814,7 @@
val scale: Scale? = null
)
+@OptIn(ExperimentalAnimationApi::class, InternalAnimationApi::class)
@Suppress("ModifierFactoryExtensionFunction", "ComposableModifierFactory")
@Composable
internal fun Transition<EnterExitState>.createModifier(
@@ -823,47 +823,77 @@
label: String
): Modifier {
- // Generates up to 3 modifiers, one for each type of enter/exit transition in the order:
- // slide then shrink/expand then alpha.
- var modifier: Modifier = Modifier
+ var shouldAnimateSlide by remember(this) { mutableStateOf(false) }
+ var shouldAnimateSizeChange by remember(this) { mutableStateOf(false) }
+ // Animate if the enter or exit transition for the type is defined. Once the shouldAnimateFoo
+ // is set, it'll stay true until the transition is complete. This would ensure the removal of
+ // any of type animation in the enter/exit amid a transition doesn't result in a
+ // jump. Reset shouldAnimateFoo to false when the transition is finished.
+ val isTransitioning = currentState != targetState || isSeeking
+ shouldAnimateSlide = isTransitioning &&
+ (shouldAnimateSlide || enter.data.slide != null || exit.data.slide != null)
+ shouldAnimateSizeChange = isTransitioning &&
+ (shouldAnimateSizeChange || enter.data.changeSize != null || exit.data.changeSize != null)
- modifier = modifier.slideInOut(
- this,
- rememberUpdatedState(enter.data.slide),
- rememberUpdatedState(exit.data.slide),
- label
- ).shrinkExpand(
- this,
- rememberUpdatedState(enter.data.changeSize),
- rememberUpdatedState(exit.data.changeSize),
- label
- )
+ val slideAnimation = if (shouldAnimateSlide) {
+ createDeferredAnimation(IntOffset.VectorConverter, remember { "$label slide" })
+ } else {
+ null
+ }
+ val sizeAnimation = if (shouldAnimateSizeChange) {
+ createDeferredAnimation(IntSize.VectorConverter, remember { "$label shrink/expand" })
+ } else null
+
+ val offsetAnimation = if (shouldAnimateSizeChange) {
+ createDeferredAnimation(
+ IntOffset.VectorConverter,
+ remember { "$label InterruptionHandlingOffset" }
+ )
+ } else null
+
+ val disableClip = (enter.data.changeSize?.clip == false ||
+ exit.data.changeSize?.clip == false) || !shouldAnimateSizeChange
+
+ val graphicsLayerBlock = createGraphicsLayerBlock(enter, exit, label)
+
+ return (if (disableClip) Modifier else Modifier.clipToBounds())
+ .then(
+ EnterExitTransitionElement(
+ this, sizeAnimation, offsetAnimation, slideAnimation,
+ enter, exit, graphicsLayerBlock
+ )
+ )
+}
+
+@Composable
+private fun Transition<EnterExitState>.createGraphicsLayerBlock(
+ enter: EnterTransition,
+ exit: ExitTransition,
+ label: String
+): GraphicsLayerScope.() -> Unit {
+
+ var shouldAnimateAlpha by remember(this) { mutableStateOf(false) }
+ var shouldAnimateScale by remember(this) { mutableStateOf(false) }
+
+ val isTransitioning = currentState != targetState || isSeeking
+ shouldAnimateAlpha = isTransitioning &&
+ (shouldAnimateAlpha || enter.data.fade != null || exit.data.fade != null)
+ shouldAnimateScale = isTransitioning &&
+ (shouldAnimateScale || enter.data.scale != null || exit.data.scale != null)
// Fade - it's important to put fade in the end. Otherwise fade will clip slide.
// We'll animate if at any point during the transition fadeIn/fadeOut becomes non-null. This
// would ensure the removal of fadeIn/Out amid a fade animation doesn't result in a jump.
- var shouldAnimateAlpha by remember(this) { mutableStateOf(false) }
- var shouldAnimateScale by remember(this) { mutableStateOf(false) }
- if (currentState == targetState && !isSeeking) {
- shouldAnimateAlpha = false
- shouldAnimateScale = false
- } else {
- if (enter.data.fade != null || exit.data.fade != null) {
- shouldAnimateAlpha = true
- }
- if (enter.data.scale != null || exit.data.scale != null) {
- shouldAnimateScale = true
- }
- }
-
val alpha by if (shouldAnimateAlpha) {
animateFloat(
transitionSpec = {
when {
EnterExitState.PreEnter isTransitioningTo EnterExitState.Visible ->
enter.data.fade?.animationSpec ?: DefaultAlphaAndScaleSpring
+
EnterExitState.Visible isTransitioningTo EnterExitState.PostExit ->
exit.data.fade?.animationSpec ?: DefaultAlphaAndScaleSpring
+
else -> DefaultAlphaAndScaleSpring
}
},
@@ -879,14 +909,16 @@
DefaultAlpha
}
- if (shouldAnimateScale) {
+ return if (shouldAnimateScale) {
val scale by animateFloat(
transitionSpec = {
when {
EnterExitState.PreEnter isTransitioningTo EnterExitState.Visible ->
enter.data.scale?.animationSpec ?: DefaultAlphaAndScaleSpring
+
EnterExitState.Visible isTransitioningTo EnterExitState.PostExit ->
exit.data.scale?.animationSpec ?: DefaultAlphaAndScaleSpring
+
else -> DefaultAlphaAndScaleSpring
}
},
@@ -914,23 +946,24 @@
EnterExitState.Visible -> transformOriginWhenVisible
EnterExitState.PreEnter ->
enter.data.scale?.transformOrigin ?: exit.data.scale?.transformOrigin
+
EnterExitState.PostExit ->
exit.data.scale?.transformOrigin ?: enter.data.scale?.transformOrigin
} ?: TransformOrigin.Center
}
- modifier = modifier.graphicsLayer {
+ val block: GraphicsLayerScope.() -> Unit = {
this.alpha = alpha
this.scaleX = scale
this.scaleY = scale
this.transformOrigin = transformOrigin
}
+ block
} else if (shouldAnimateAlpha) {
- modifier = modifier.graphicsLayer {
- this.alpha = alpha
- }
+ { this.alpha = alpha }
+ } else {
+ {}
}
- return modifier
}
private val TransformOriginVectorConverter =
@@ -942,184 +975,64 @@
private val DefaultAlpha = mutableFloatStateOf(1f)
private val DefaultAlphaAndScaleSpring = spring<Float>(stiffness = Spring.StiffnessMediumLow)
-private fun Modifier.slideInOut(
- transition: Transition<EnterExitState>,
- slideIn: State<Slide?>,
- slideOut: State<Slide?>,
- labelPrefix: String
-): Modifier = composed {
- // We'll animate if at any point during the transition slideIn/slideOut becomes non-null. This
- // would ensure the removal of slideIn/Out amid a slide animation doesn't result in a jump.
- var shouldAnimate by remember(transition) { mutableStateOf(false) }
- if (transition.currentState == transition.targetState && !transition.isSeeking) {
- shouldAnimate = false
- } else {
- if (slideIn.value != null || slideOut.value != null) {
- shouldAnimate = true
- }
- }
-
- if (shouldAnimate) {
- val animation = transition.createDeferredAnimation(
- IntOffset.VectorConverter,
- remember { "$labelPrefix slide" }
- )
- val modifier = remember(transition) {
- SlideModifier(animation, slideIn, slideOut)
- }
- this.then(modifier)
- } else {
- this
- }
-}
-
private val DefaultOffsetAnimationSpec = spring(
stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntOffset.VisibilityThreshold
)
-private class SlideModifier(
- val lazyAnimation: Transition<EnterExitState>.DeferredAnimation<IntOffset, AnimationVector2D>,
- val slideIn: State<Slide?>,
- val slideOut: State<Slide?>
-) : LayoutModifierWithPassThroughIntrinsics() {
- val transitionSpec: Transition.Segment<EnterExitState>.() -> FiniteAnimationSpec<IntOffset> =
- {
- when {
- EnterExitState.PreEnter isTransitioningTo EnterExitState.Visible -> {
- slideIn.value?.animationSpec ?: DefaultOffsetAnimationSpec
- }
- EnterExitState.Visible isTransitioningTo EnterExitState.PostExit -> {
- slideOut.value?.animationSpec ?: DefaultOffsetAnimationSpec
- }
- else -> DefaultOffsetAnimationSpec
- }
+private class EnterExitTransitionModifierNode(
+ var transition: Transition<EnterExitState>,
+ var sizeAnimation: Transition<EnterExitState>.DeferredAnimation<IntSize, AnimationVector2D>?,
+ var offsetAnimation:
+ Transition<EnterExitState>.DeferredAnimation<IntOffset, AnimationVector2D>?,
+ var slideAnimation: Transition<EnterExitState>.DeferredAnimation<IntOffset, AnimationVector2D>?,
+ var enter: EnterTransition,
+ var exit: ExitTransition,
+ var graphicsLayerBlock: GraphicsLayerScope.() -> Unit
+) : LayoutModifierNodeWithPassThroughIntrinsics() {
+
+ private var lookaheadConstraintsAvailable = false
+ private var lookaheadSize: IntSize = InvalidSize
+ private var lookaheadConstraints: Constraints = Constraints()
+ set(value) {
+ lookaheadConstraintsAvailable = true
+ field = value
}
-
- fun targetValueByState(targetState: EnterExitState, fullSize: IntSize): IntOffset {
- val preEnter = slideIn.value?.slideOffset?.invoke(fullSize) ?: IntOffset.Zero
- val postExit = slideOut.value?.slideOffset?.invoke(fullSize) ?: IntOffset.Zero
- return when (targetState) {
- EnterExitState.Visible -> IntOffset.Zero
- EnterExitState.PreEnter -> preEnter
- EnterExitState.PostExit -> postExit
- }
- }
-
- override fun MeasureScope.measure(
- measurable: Measurable,
- constraints: Constraints
- ): MeasureResult {
- val placeable = measurable.measure(constraints)
-
- val measuredSize = IntSize(placeable.width, placeable.height)
- return layout(placeable.width, placeable.height) {
- val slideOffset = lazyAnimation.animate(
- transitionSpec
- ) {
- targetValueByState(it, measuredSize)
- }
- placeable.placeWithLayer(slideOffset.value)
- }
- }
-}
-
-private fun Modifier.shrinkExpand(
- transition: Transition<EnterExitState>,
- expand: State<ChangeSize?>,
- shrink: State<ChangeSize?>,
- labelPrefix: String
-): Modifier = composed {
- // We'll animate if at any point during the transition shrink/expand becomes non-null. This
- // would ensure the removal of shrink/expand amid a size change animation doesn't result in a
- // jump.
- var shouldAnimate by remember(transition) { mutableStateOf(false) }
- if (transition.currentState == transition.targetState && !transition.isSeeking) {
- shouldAnimate = false
- } else {
- if (expand.value != null || shrink.value != null) {
- shouldAnimate = true
- }
- }
-
- if (shouldAnimate) {
- val alignment: State<Alignment?> = rememberUpdatedState(
- with(transition.segment) {
- EnterExitState.PreEnter isTransitioningTo EnterExitState.Visible
- }.let {
- if (it) {
- expand.value?.alignment ?: shrink.value?.alignment
- } else {
- shrink.value?.alignment ?: expand.value?.alignment
- }
- }
- )
- val sizeAnimation = transition.createDeferredAnimation(
- IntSize.VectorConverter,
- remember { "$labelPrefix shrink/expand" }
- )
- val offsetAnimation = key(transition.currentState == transition.targetState) {
- transition.createDeferredAnimation(
- IntOffset.VectorConverter,
- remember { "$labelPrefix InterruptionHandlingOffset" }
- )
- }
-
- val expandShrinkModifier = remember(transition) {
- ExpandShrinkModifier(
- sizeAnimation,
- offsetAnimation,
- expand,
- shrink,
- alignment
- )
- }
-
- if (transition.currentState == transition.targetState) {
- expandShrinkModifier.currentAlignment = null
- } else if (expandShrinkModifier.currentAlignment == null) {
- expandShrinkModifier.currentAlignment = alignment.value ?: Alignment.TopStart
- }
- val disableClip = expand.value?.clip == false || shrink.value?.clip == false
- this.then(if (disableClip) Modifier else Modifier.clipToBounds())
- .then(expandShrinkModifier)
- } else {
- this
- }
-}
-
-private val DefaultSizeAnimationSpec = spring(
- stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold
-)
-
-private class ExpandShrinkModifier(
- val sizeAnimation: Transition<EnterExitState>.DeferredAnimation<IntSize, AnimationVector2D>,
- val offsetAnimation: Transition<EnterExitState>.DeferredAnimation<IntOffset,
- AnimationVector2D>,
- val expand: State<ChangeSize?>,
- val shrink: State<ChangeSize?>,
- val alignment: State<Alignment?>
-) : LayoutModifierWithPassThroughIntrinsics() {
var currentAlignment: Alignment? = null
+ val alignment: Alignment?
+ get() = with(transition.segment) {
+ if (EnterExitState.PreEnter isTransitioningTo EnterExitState.Visible) {
+ enter.data.changeSize?.alignment ?: exit.data.changeSize?.alignment
+ } else {
+ exit.data.changeSize?.alignment ?: enter.data.changeSize?.alignment
+ }
+ }
+
+ private fun targetConstraints(default: Constraints) =
+ if (lookaheadConstraintsAvailable) lookaheadConstraints else default
+
val sizeTransitionSpec: Transition.Segment<EnterExitState>.() -> FiniteAnimationSpec<IntSize> =
{
when {
EnterExitState.PreEnter isTransitioningTo EnterExitState.Visible ->
- expand.value?.animationSpec
+ enter.data.changeSize?.animationSpec
+
EnterExitState.Visible isTransitioningTo EnterExitState.PostExit ->
- shrink.value?.animationSpec
+ exit.data.changeSize?.animationSpec
+
else -> DefaultSizeAnimationSpec
} ?: DefaultSizeAnimationSpec
}
- fun sizeByState(targetState: EnterExitState, fullSize: IntSize): IntSize {
- val preEnterSize = expand.value?.let { it.size(fullSize) } ?: fullSize
- val postExitSize = shrink.value?.let { it.size(fullSize) } ?: fullSize
+ fun sizeByState(targetState: EnterExitState, fullSize: IntSize): IntSize = when (targetState) {
+ EnterExitState.Visible -> fullSize
+ EnterExitState.PreEnter -> enter.data.changeSize?.size?.invoke(fullSize) ?: fullSize
+ EnterExitState.PostExit -> exit.data.changeSize?.size?.invoke(fullSize) ?: fullSize
+ }
- return when (targetState) {
- EnterExitState.Visible -> fullSize
- EnterExitState.PreEnter -> preEnterSize
- EnterExitState.PostExit -> postExitSize
- }
+ override fun onAttach() {
+ super.onAttach()
+ lookaheadConstraintsAvailable = false
+ lookaheadSize = InvalidSize
}
// This offset is only needed when the alignment value changes during the shrink/expand
@@ -1129,14 +1042,14 @@
fun targetOffsetByState(targetState: EnterExitState, fullSize: IntSize): IntOffset =
when {
currentAlignment == null -> IntOffset.Zero
- alignment.value == null -> IntOffset.Zero
- currentAlignment == alignment.value -> IntOffset.Zero
+ alignment == null -> IntOffset.Zero
+ currentAlignment == alignment -> IntOffset.Zero
else -> when (targetState) {
EnterExitState.Visible -> IntOffset.Zero
EnterExitState.PreEnter -> IntOffset.Zero
- EnterExitState.PostExit -> shrink.value?.let {
+ EnterExitState.PostExit -> exit.data.changeSize?.let {
val endSize = it.size(fullSize)
- val targetOffset = alignment.value!!.align(
+ val targetOffset = alignment!!.align(
fullSize,
endSize,
LayoutDirection.Ltr
@@ -1155,22 +1068,111 @@
measurable: Measurable,
constraints: Constraints
): MeasureResult {
- val placeable = measurable.measure(constraints)
+ if (transition.currentState == transition.targetState) {
+ currentAlignment = null
+ } else if (currentAlignment == null) {
+ currentAlignment = alignment ?: Alignment.TopStart
+ }
+ if (isLookingAhead) {
+ val placeable = measurable.measure(constraints)
+ 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) {
+ placeable.place(0, 0)
+ }
+ } else {
+ val placeable = measurable.measure(targetConstraints(constraints))
+ val measuredSize = IntSize(placeable.width, placeable.height)
+ val target = if (lookaheadSize.isValid) lookaheadSize else measuredSize
+ val animSize = sizeAnimation?.animate(sizeTransitionSpec) { sizeByState(it, target) }
+ // Since we measure with lookahead constraints when available, the size needs to
+ // be constrained by incoming constraints so that we know how to position content
+ // in the constrained rect based on alignment.
+ val currentSize = constraints.constrain(animSize?.value ?: measuredSize)
+ val offsetDelta = offsetAnimation?.animate({ DefaultOffsetAnimationSpec }) {
+ targetOffsetByState(it, target)
+ }?.value ?: IntOffset.Zero
+ val slideOffset = slideAnimation?.animate(slideSpec) {
+ slideTargetValueByState(it, target)
+ }?.value ?: IntOffset.Zero
+ val offset = (currentAlignment?.align(target, currentSize, LayoutDirection.Ltr)
+ ?: IntOffset.Zero) + slideOffset
+ return layout(currentSize.width, currentSize.height) {
+ placeable.placeWithLayer(
+ offset.x + offsetDelta.x, offset.y + offsetDelta.y, 0f, graphicsLayerBlock
+ )
+ }
+ }
+ }
- val measuredSize = IntSize(placeable.width, placeable.height)
- val currentSize = sizeAnimation.animate(sizeTransitionSpec) {
- sizeByState(it, measuredSize)
- }.value
+ val slideSpec: Transition.Segment<EnterExitState>.() -> FiniteAnimationSpec<IntOffset> = {
+ when {
+ EnterExitState.PreEnter isTransitioningTo EnterExitState.Visible -> {
+ enter.data.slide?.animationSpec ?: DefaultOffsetAnimationSpec
+ }
- val offsetDelta = offsetAnimation.animate({ DefaultOffsetAnimationSpec }) {
- targetOffsetByState(it, measuredSize)
- }.value
+ EnterExitState.Visible isTransitioningTo EnterExitState.PostExit -> {
+ exit.data.slide?.animationSpec ?: DefaultOffsetAnimationSpec
+ }
- val offset =
- currentAlignment?.align(measuredSize, currentSize, LayoutDirection.Ltr)
- ?: IntOffset.Zero
- return layout(currentSize.width, currentSize.height) {
- placeable.place(offset.x + offsetDelta.x, offset.y + offsetDelta.y)
+ else -> DefaultOffsetAnimationSpec
+ }
+ }
+
+ fun slideTargetValueByState(targetState: EnterExitState, fullSize: IntSize): IntOffset {
+ val preEnter = enter.data.slide?.slideOffset?.invoke(fullSize) ?: IntOffset.Zero
+ val postExit = exit.data.slide?.slideOffset?.invoke(fullSize) ?: IntOffset.Zero
+ return when (targetState) {
+ EnterExitState.Visible -> IntOffset.Zero
+ EnterExitState.PreEnter -> preEnter
+ EnterExitState.PostExit -> postExit
}
}
}
+
+private val DefaultSizeAnimationSpec = spring(
+ stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold
+)
+
+private data class EnterExitTransitionElement(
+ val transition: Transition<EnterExitState>,
+ var sizeAnimation: Transition<EnterExitState>.DeferredAnimation<IntSize, AnimationVector2D>?,
+ var offsetAnimation:
+ Transition<EnterExitState>.DeferredAnimation<IntOffset, AnimationVector2D>?,
+ var slideAnimation: Transition<EnterExitState>.DeferredAnimation<IntOffset, AnimationVector2D>?,
+ var enter: EnterTransition,
+ var exit: ExitTransition,
+ var graphicsLayerBlock: GraphicsLayerScope.() -> Unit
+) : ModifierNodeElement<EnterExitTransitionModifierNode>() {
+ override fun create(): EnterExitTransitionModifierNode =
+ EnterExitTransitionModifierNode(
+ transition, sizeAnimation, offsetAnimation, slideAnimation, enter, exit,
+ graphicsLayerBlock
+ )
+
+ override fun update(node: EnterExitTransitionModifierNode) {
+ node.transition = transition
+ node.sizeAnimation = sizeAnimation
+ node.offsetAnimation = offsetAnimation
+ node.slideAnimation = slideAnimation
+ node.enter = enter
+ node.exit = exit
+ node.graphicsLayerBlock = graphicsLayerBlock
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
+ name = "enterExitTransition"
+ properties["transition"] = transition
+ properties["sizeAnimation"] = sizeAnimation
+ properties["offsetAnimation"] = offsetAnimation
+ properties["slideAnimation"] = slideAnimation
+ properties["enter"] = enter
+ properties["exit"] = exit
+ properties["graphicsLayerBlock"] = graphicsLayerBlock
+ }
+}
\ No newline at end of file
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
index 75258ec..dac5856 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
@@ -114,6 +114,7 @@
9901 to "1.5.0-alpha03",
10001 to "1.5.0-alpha04",
10101 to "1.5.0-alpha05",
+ 10200 to "1.6.0-alpha01",
)
/**
diff --git a/compose/foundation/CHANGELOG.md b/compose/foundation/CHANGELOG.md
new file mode 100644
index 0000000..870ea92
--- /dev/null
+++ b/compose/foundation/CHANGELOG.md
@@ -0,0 +1,21 @@
+# Log for changes in the Compose Foundation library
+#
+# `Added`: for new features
+# `Changed`: for changes in existing functionality
+# `Deprecated`: for soon to be removed functionality
+# `Removed`: for now removed feature
+# `Fixed`: for any bug fixes
+# `Security`: in case of vulnerabilities
+#
+# Possible headings:
+# API Changes
+# Bug Fixes
+# Dependency Updates
+# Behavior Change
+# External Contributions
+
+## Unreleased
+
+### New Features
+
+### Bug Fixes
diff --git a/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/WindowInsetsPaddingTest.kt b/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/WindowInsetsPaddingTest.kt
index ca4f233..3aba669 100644
--- a/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/WindowInsetsPaddingTest.kt
+++ b/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/WindowInsetsPaddingTest.kt
@@ -349,11 +349,19 @@
with(LocalDensity.current) {
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
Box(
- Modifier.fillMaxSize().padding(5.toDp(), 4.toDp(), 3.toDp(), 2.toDp())
+ Modifier
+ .fillMaxSize()
+ .padding(5.toDp(), 4.toDp(), 3.toDp(), 2.toDp())
.consumeWindowInsets(WindowInsets(5, 4, 3, 2))
) {
- Box(Modifier.fillMaxSize().systemBarsPadding()) {
- Box(Modifier.fillMaxSize().onGloballyPositioned { coordinates = it })
+ Box(
+ Modifier
+ .fillMaxSize()
+ .systemBarsPadding()) {
+ Box(
+ Modifier
+ .fillMaxSize()
+ .onGloballyPositioned { coordinates = it })
}
}
}
@@ -382,7 +390,10 @@
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
Box(Modifier.statusBarsPadding()) {
Box(Modifier.systemBarsPadding()) {
- Box(Modifier.fillMaxSize().onGloballyPositioned { coordinates = it })
+ Box(
+ Modifier
+ .fillMaxSize()
+ .onGloballyPositioned { coordinates = it })
}
}
}
@@ -415,9 +426,12 @@
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
Box(consumingModifier) {
val density = LocalDensity.current
- Box(Modifier.fillMaxSize().onConsumedWindowInsetsChanged {
- top = it.getTop(density)
- })
+ Box(
+ Modifier
+ .fillMaxSize()
+ .onConsumedWindowInsetsChanged {
+ top = it.getTop(density)
+ })
}
}
}
@@ -517,7 +531,10 @@
@Test
fun animateImeInsets() {
with(Api30Methods(rule)) {
- val coordinates = setInsetContent { Modifier.systemBarsPadding().imePadding() }
+ val coordinates = setInsetContent {
+ Modifier
+ .systemBarsPadding()
+ .imePadding() }
sendInsets(WindowInsetsCompat.Type.systemBars())
@@ -568,8 +585,14 @@
setContent {
val padding = WindowInsets.systemBars.asPaddingValues()
- Box(Modifier.fillMaxSize().padding(padding)) {
- Box(Modifier.fillMaxSize().onGloballyPositioned { coordinates = it })
+ Box(
+ Modifier
+ .fillMaxSize()
+ .padding(padding)) {
+ Box(
+ Modifier
+ .fillMaxSize()
+ .onGloballyPositioned { coordinates = it })
}
}
@@ -602,8 +625,15 @@
.statusBarsPadding()
.onGloballyPositioned { statusBar = it }
) {
- Box(Modifier.navigationBarsPadding().onGloballyPositioned { navigationBar = it }) {
- Box(Modifier.imePadding().fillMaxSize().onGloballyPositioned { ime = it })
+ Box(
+ Modifier
+ .navigationBarsPadding()
+ .onGloballyPositioned { navigationBar = it }) {
+ Box(
+ Modifier
+ .imePadding()
+ .fillMaxSize()
+ .onGloballyPositioned { ime = it })
}
}
}
@@ -692,10 +722,11 @@
.windowInsetsPadding(WindowInsets(top = 10))
.onGloballyPositioned { outer = it }
) {
- Box(Modifier
- .consumeWindowInsets(WindowInsets(top = 10))
- .windowInsetsPadding(WindowInsets(top = 20))
- .onGloballyPositioned { middle = it }
+ Box(
+ Modifier
+ .consumeWindowInsets(WindowInsets(top = 10))
+ .windowInsetsPadding(WindowInsets(top = 20))
+ .onGloballyPositioned { middle = it }
) {
Box(
Modifier
@@ -773,7 +804,10 @@
ComposeView(context).also {
it.consumeWindowInsets = false
it.setContent {
- Box(Modifier.fillMaxSize().statusBarsPadding())
+ Box(
+ Modifier
+ .fillMaxSize()
+ .statusBarsPadding())
}
}
})
@@ -812,6 +846,36 @@
assertThat(bottomInset).isEqualTo(0)
}
+ @OptIn(ExperimentalLayoutApi::class)
+ @Test
+ fun reuseModifier() {
+ var consumed1 = WindowInsets(0, 0, 0, 0)
+ var consumed2 = WindowInsets(0, 0, 0, 0)
+ setContent {
+ with(LocalDensity.current) {
+ val modifier = Modifier.consumeWindowInsets(PaddingValues(10.toDp()))
+ Box(
+ modifier
+ .fillMaxSize()
+ .onConsumedWindowInsetsChanged { consumed1 = it }
+ ) {
+ Box(
+ modifier
+ .fillMaxSize()
+ .onConsumedWindowInsetsChanged { consumed2 = it }
+ )
+ }
+ }
+ }
+
+ rule.waitForIdle()
+ sendInsets(WindowInsetsCompat.Type.statusBars(), AndroidXInsets.of(0, 30, 0, 0))
+ rule.runOnIdle {
+ assertThat(consumed1.getTop(rule.density)).isEqualTo(10)
+ assertThat(consumed2.getTop(rule.density)).isEqualTo(20)
+ }
+ }
+
private fun sendInsets(
type: Int,
sentInsets: AndroidXInsets = AndroidXInsets.of(10, 11, 12, 13)
@@ -838,10 +902,17 @@
lateinit var coordinates: LayoutCoordinates
setContent {
- Box(Modifier.fillMaxSize().background(Color.Blue).then(insetsModifier())) {
- Box(Modifier.fillMaxSize().onGloballyPositioned {
- coordinates = it
- })
+ Box(
+ Modifier
+ .fillMaxSize()
+ .background(Color.Blue)
+ .then(insetsModifier())) {
+ Box(
+ Modifier
+ .fillMaxSize()
+ .onGloballyPositioned {
+ coordinates = it
+ })
}
}
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Box.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Box.kt
index c70e44d..f22fdc4 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Box.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Box.kt
@@ -197,7 +197,7 @@
*/
@Composable
fun Box(modifier: Modifier) {
- Layout({}, measurePolicy = EmptyBoxMeasurePolicy, modifier = modifier)
+ Layout(measurePolicy = EmptyBoxMeasurePolicy, modifier = modifier)
}
internal val EmptyBoxMeasurePolicy = MeasurePolicy { _, constraints ->
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Spacer.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Spacer.kt
index 4ba62fe..0f9c428 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Spacer.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Spacer.kt
@@ -37,7 +37,7 @@
@Composable
@NonRestartableComposable
fun Spacer(modifier: Modifier) {
- Layout({}, measurePolicy = SpacerMeasurePolicy, modifier = modifier)
+ Layout(measurePolicy = SpacerMeasurePolicy, modifier = modifier)
}
private object SpacerMeasurePolicy : MeasurePolicy {
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt
index f8e7312..5f64e2d 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt
@@ -19,8 +19,10 @@
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.composed
import androidx.compose.ui.layout.LayoutModifier
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasureResult
@@ -30,8 +32,6 @@
import androidx.compose.ui.modifier.ModifierLocalReadScope
import androidx.compose.ui.modifier.ProvidableModifierLocal
import androidx.compose.ui.modifier.modifierLocalOf
-import androidx.compose.ui.platform.InspectorInfo
-import androidx.compose.ui.platform.InspectorValueInfo
import androidx.compose.ui.platform.debugInspectorInfo
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.constrainHeight
@@ -53,12 +53,14 @@
* @see WindowInsets
*/
@Stable
-fun Modifier.windowInsetsPadding(insets: WindowInsets): Modifier = this.then(
- InsetsPaddingModifier(insets, debugInspectorInfo {
+fun Modifier.windowInsetsPadding(insets: WindowInsets): Modifier = composed(
+ debugInspectorInfo {
name = "windowInsetsPadding"
properties["insets"] = insets
- })
-)
+ }
+) {
+ remember(insets) { InsetsPaddingModifier(insets) }
+}
/**
* Consume insets that haven't been consumed yet by other insets Modifiers similar to
@@ -71,12 +73,15 @@
* @sample androidx.compose.foundation.layout.samples.consumedInsetsSample
*/
@Stable
-fun Modifier.consumeWindowInsets(insets: WindowInsets): Modifier = this.then(
- UnionInsetsConsumingModifier(insets, debugInspectorInfo {
+fun Modifier.consumeWindowInsets(insets: WindowInsets): Modifier = composed(
+ debugInspectorInfo {
name = "consumeWindowInsets"
properties["insets"] = insets
- })
-)
+ }
+) {
+ remember(insets) { UnionInsetsConsumingModifier(insets) }
+}
+
@ExperimentalLayoutApi
@Deprecated("Use consumeWindowInsets", ReplaceWith("this.consumeWindowInsets(insets)"))
@Stable
@@ -98,12 +103,16 @@
*/
@ExperimentalLayoutApi
@Stable
-fun Modifier.consumeWindowInsets(paddingValues: PaddingValues): Modifier = this.then(
- PaddingValuesConsumingModifier(paddingValues, debugInspectorInfo {
+fun Modifier.consumeWindowInsets(paddingValues: PaddingValues): Modifier = composed(
+ debugInspectorInfo {
name = "consumeWindowInsets"
properties["paddingValues"] = paddingValues
- })
-)
+ }
+) {
+ remember(paddingValues) {
+ PaddingValuesConsumingModifier(paddingValues)
+ }
+}
@ExperimentalLayoutApi
@Deprecated("Use consumeWindowInsets", ReplaceWith("this.consumeWindowInsets(paddingValues)"))
@@ -120,15 +129,16 @@
@Stable
fun Modifier.onConsumedWindowInsetsChanged(
block: (consumedWindowInsets: WindowInsets) -> Unit
-) = this.then(
- ConsumedInsetsModifier(
- block,
- debugInspectorInfo {
- name = "onConsumedWindowInsetsChanged"
- properties["block"] = block
- }
- )
-)
+) = composed(
+ debugInspectorInfo {
+ name = "onConsumedWindowInsetsChanged"
+ properties["block"] = block
+ }
+) {
+ remember(block) {
+ ConsumedInsetsModifier(block)
+ }
+}
@ExperimentalLayoutApi
@Deprecated(
@@ -145,12 +155,8 @@
}
internal class InsetsPaddingModifier(
- private val insets: WindowInsets,
- inspectorInfo: InspectorInfo.() -> Unit = debugInspectorInfo {
- name = "InsetsPaddingModifier"
- properties["insets"] = insets
- }
-) : InspectorValueInfo(inspectorInfo), LayoutModifier,
+ private val insets: WindowInsets
+) : LayoutModifier,
ModifierLocalConsumer, ModifierLocalProvider<WindowInsets> {
private var unconsumedInsets: WindowInsets by mutableStateOf(insets)
private var consumedInsets: WindowInsets by mutableStateOf(insets)
@@ -209,9 +215,8 @@
* Base class for arbitrary insets consumption modifiers.
*/
@Stable
-private sealed class InsetsConsumingModifier(
- inspectorInfo: InspectorInfo.() -> Unit
-) : InspectorValueInfo(inspectorInfo), ModifierLocalConsumer, ModifierLocalProvider<WindowInsets> {
+private sealed class InsetsConsumingModifier : ModifierLocalConsumer,
+ ModifierLocalProvider<WindowInsets> {
private var consumedInsets: WindowInsets by mutableStateOf(WindowInsets(0, 0, 0, 0))
abstract fun calculateInsets(modifierLocalInsets: WindowInsets): WindowInsets
@@ -232,9 +237,8 @@
@Stable
private class PaddingValuesConsumingModifier(
- private val paddingValues: PaddingValues,
- inspectorInfo: InspectorInfo.() -> Unit
-) : InsetsConsumingModifier(inspectorInfo) {
+ private val paddingValues: PaddingValues
+) : InsetsConsumingModifier() {
override fun calculateInsets(modifierLocalInsets: WindowInsets): WindowInsets =
paddingValues.asInsets().add(modifierLocalInsets)
@@ -254,9 +258,8 @@
@Stable
private class ConsumedInsetsModifier(
- private val block: (WindowInsets) -> Unit,
- inspectorInfo: InspectorInfo.() -> Unit
-) : InspectorValueInfo(inspectorInfo), ModifierLocalConsumer {
+ private val block: (WindowInsets) -> Unit
+) : ModifierLocalConsumer {
private var oldWindowInsets: WindowInsets? = null
@@ -284,9 +287,8 @@
@Stable
private class UnionInsetsConsumingModifier(
- private val insets: WindowInsets,
- inspectorInfo: InspectorInfo.() -> Unit
-) : InsetsConsumingModifier(inspectorInfo) {
+ private val insets: WindowInsets
+) : InsetsConsumingModifier() {
override fun calculateInsets(modifierLocalInsets: WindowInsets): WindowInsets =
insets.union(modifierLocalInsets)
@@ -302,4 +304,4 @@
}
override fun hashCode(): Int = insets.hashCode()
-}
\ No newline at end of file
+}
diff --git a/compose/foundation/foundation/api/current.ignore b/compose/foundation/foundation/api/current.ignore
deleted file mode 100644
index 393276e..0000000
--- a/compose/foundation/foundation/api/current.ignore
+++ /dev/null
@@ -1,7 +0,0 @@
-// Baseline format: 1.0
-AddedAbstractMethod: androidx.compose.foundation.lazy.grid.LazyGridItemInfo#getContentType():
- Added method androidx.compose.foundation.lazy.grid.LazyGridItemInfo.getContentType()
-
-
-InvalidNullConversion: androidx.compose.foundation.MutatorMutex#mutateWith(T, androidx.compose.foundation.MutatePriority, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super R>,?>, kotlin.coroutines.Continuation<? super R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter receiver in androidx.compose.foundation.MutatorMutex.mutateWith(T receiver, androidx.compose.foundation.MutatePriority priority, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super R>,?> block, kotlin.coroutines.Continuation<? super R> arg4)
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index 15fd553..24143b5 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -48,6 +48,7 @@
}
public final class ClickableKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.CombinedClickableNode CombinedClickableNode(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, String? onLongClickLabel, kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, boolean enabled, String? onClickLabel, androidx.compose.ui.semantics.Role? role);
method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier combinedClickable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, optional String? onLongClickLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
@@ -58,6 +59,10 @@
method public static androidx.compose.ui.Modifier clipScrollableContainer(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.Orientation orientation);
}
+ @androidx.compose.foundation.ExperimentalFoundationApi public sealed interface CombinedClickableNode extends androidx.compose.ui.node.PointerInputModifierNode {
+ method public void update(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, String? onLongClickLabel, kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, boolean enabled, String? onClickLabel, androidx.compose.ui.semantics.Role? role);
+ }
+
public final class DarkThemeKt {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static boolean isSystemInDarkTheme();
}
@@ -229,6 +234,18 @@
package androidx.compose.foundation.gestures {
+ @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public interface BringIntoViewScroller {
+ method public float calculateScrollDistance(float offset, float size, float containerSize);
+ method public androidx.compose.animation.core.AnimationSpec<java.lang.Float> getScrollAnimationSpec();
+ property public abstract androidx.compose.animation.core.AnimationSpec<java.lang.Float> scrollAnimationSpec;
+ field public static final androidx.compose.foundation.gestures.BringIntoViewScroller.Companion Companion;
+ }
+
+ public static final class BringIntoViewScroller.Companion {
+ method public androidx.compose.animation.core.AnimationSpec<java.lang.Float> getDefaultScrollAnimationSpec();
+ property public final androidx.compose.animation.core.AnimationSpec<java.lang.Float> DefaultScrollAnimationSpec;
+ }
+
public final class DragGestureDetectorKt {
method public static suspend Object? awaitDragOrCancellation(androidx.compose.ui.input.pointer.AwaitPointerEventScope, long pointerId, kotlin.coroutines.Continuation<? super androidx.compose.ui.input.pointer.PointerInputChange>);
method public static suspend Object? awaitHorizontalDragOrCancellation(androidx.compose.ui.input.pointer.AwaitPointerEventScope, long pointerId, kotlin.coroutines.Continuation<? super androidx.compose.ui.input.pointer.PointerInputChange>);
@@ -297,6 +314,7 @@
}
public final class ScrollableDefaults {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public androidx.compose.foundation.gestures.BringIntoViewScroller bringIntoViewScroller();
method @androidx.compose.runtime.Composable public androidx.compose.foundation.gestures.FlingBehavior flingBehavior();
method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public androidx.compose.foundation.OverscrollEffect overscrollEffect();
method public boolean reverseDirection(androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.foundation.gestures.Orientation orientation, boolean reverseScrolling);
@@ -304,7 +322,7 @@
}
public final class ScrollableKt {
- method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, androidx.compose.foundation.OverscrollEffect? overscrollEffect, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, androidx.compose.foundation.OverscrollEffect? overscrollEffect, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.foundation.gestures.BringIntoViewScroller bringIntoViewScroller);
method public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
}
@@ -995,7 +1013,7 @@
@androidx.compose.foundation.ExperimentalFoundationApi public final class PagerDefaults {
method @androidx.compose.runtime.Composable public androidx.compose.foundation.gestures.snapping.SnapFlingBehavior flingBehavior(androidx.compose.foundation.pager.PagerState state, optional androidx.compose.foundation.pager.PagerSnapDistance pagerSnapDistance, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> lowVelocityAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float> highVelocityAnimationSpec, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> snapAnimationSpec, optional float snapVelocityThreshold, optional float snapPositionalThreshold);
- method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection pageNestedScrollConnection(androidx.compose.foundation.gestures.Orientation orientation);
+ method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection pageNestedScrollConnection(androidx.compose.foundation.pager.PagerState state, androidx.compose.foundation.gestures.Orientation orientation);
field public static final androidx.compose.foundation.pager.PagerDefaults INSTANCE;
}
@@ -1312,3 +1330,196 @@
}
+package androidx.compose.foundation.text2 {
+
+ public final class BasicSecureTextFieldKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void BasicSecureTextField(androidx.compose.foundation.text2.input.TextFieldState state, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,java.lang.Boolean>? onSubmit, optional int imeAction, optional int textObfuscationMode, optional int keyboardType, optional boolean enabled, optional androidx.compose.foundation.text2.input.TextEditFilter? filter, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional androidx.compose.foundation.ScrollState scrollState, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.unit.Density,? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+ }
+
+ public final class BasicTextField2Kt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void BasicTextField2(androidx.compose.foundation.text2.input.TextFieldState state, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.foundation.text2.input.TextEditFilter? filter, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional androidx.compose.foundation.text2.input.TextFieldLineLimits lineLimits, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.unit.Density,? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.foundation.text2.input.CodepointTransformation? codepointTransformation, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+ }
+
+}
+
+package androidx.compose.foundation.text2.input {
+
+ public final class AllCapsFilterKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter allCaps(androidx.compose.foundation.text2.input.TextEditFilter.Companion, androidx.compose.ui.text.intl.Locale locale);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public fun interface CodepointTransformation {
+ method public int transform(int codepointIndex, int codepoint);
+ field public static final androidx.compose.foundation.text2.input.CodepointTransformation.Companion Companion;
+ }
+
+ public static final class CodepointTransformation.Companion {
+ method public androidx.compose.foundation.text2.input.CodepointTransformation getNone();
+ property public final androidx.compose.foundation.text2.input.CodepointTransformation None;
+ }
+
+ public final class CodepointTransformationKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.CodepointTransformation mask(androidx.compose.foundation.text2.input.CodepointTransformation.Companion, char character);
+ }
+
+ public final class MaxLengthFilterKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter maxLengthInChars(androidx.compose.foundation.text2.input.TextEditFilter.Companion, int maxLength);
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter maxLengthInCodepoints(androidx.compose.foundation.text2.input.TextEditFilter.Companion, int maxLength);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public fun interface TextEditFilter {
+ method public void filter(androidx.compose.foundation.text2.input.TextFieldCharSequence originalValue, androidx.compose.foundation.text2.input.TextFieldBufferWithSelection valueWithChanges);
+ method public default androidx.compose.foundation.text.KeyboardOptions? getKeyboardOptions();
+ property public default androidx.compose.foundation.text.KeyboardOptions? keyboardOptions;
+ field public static final androidx.compose.foundation.text2.input.TextEditFilter.Companion Companion;
+ }
+
+ public static final class TextEditFilter.Companion {
+ }
+
+ public final class TextEditFilterKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter then(androidx.compose.foundation.text2.input.TextEditFilter, androidx.compose.foundation.text2.input.TextEditFilter next, optional androidx.compose.foundation.text.KeyboardOptions? keyboardOptions);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public abstract sealed class TextEditResult {
+ }
+
+ public final class TextEditResultKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAfterCharAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAfterCodepointAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAfterLastChange(androidx.compose.foundation.text2.input.TextFieldBuffer);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAtEnd(androidx.compose.foundation.text2.input.TextFieldBuffer);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorBeforeCharAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorBeforeCodepointAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorBeforeFirstChange(androidx.compose.foundation.text2.input.TextFieldBuffer);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectAll(androidx.compose.foundation.text2.input.TextFieldBuffer);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectAllChanges(androidx.compose.foundation.text2.input.TextFieldBuffer);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectCharsIn(androidx.compose.foundation.text2.input.TextFieldBuffer, long range);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectCodepointsIn(androidx.compose.foundation.text2.input.TextFieldBuffer, long range);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public class TextFieldBuffer implements java.lang.Appendable java.lang.CharSequence {
+ method public Appendable append(char char);
+ method public Appendable append(CharSequence? text);
+ method public Appendable append(CharSequence? text, int start, int end);
+ method public operator char get(int index);
+ method public final androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList getChanges();
+ method public final int getCodepointLength();
+ method public int getLength();
+ method @CallSuper protected void onTextWillChange(long rangeToBeReplaced, int newLength);
+ method public final void replace(int start, int end, String text);
+ method public CharSequence subSequence(int startIndex, int endIndex);
+ property public final androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList changes;
+ property public final int codepointLength;
+ property public int length;
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public static interface TextFieldBuffer.ChangeList {
+ method public int getChangeCount();
+ method public long getOriginalRange(int changeIndex);
+ method public long getRange(int changeIndex);
+ property public abstract int changeCount;
+ }
+
+ public final class TextFieldBufferKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static void delete(androidx.compose.foundation.text2.input.TextFieldBuffer, int start, int end);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static inline void forEachChange(androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.TextRange,? super androidx.compose.ui.text.TextRange,kotlin.Unit> block);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static inline void forEachChangeReversed(androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.TextRange,? super androidx.compose.ui.text.TextRange,kotlin.Unit> block);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static void insert(androidx.compose.foundation.text2.input.TextFieldBuffer, int index, String text);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public final class TextFieldBufferWithSelection extends androidx.compose.foundation.text2.input.TextFieldBuffer {
+ method public boolean getHasSelection();
+ method public long getSelectionInChars();
+ method public long getSelectionInCodepoints();
+ method public void placeCursorAfterCharAt(int index);
+ method public void placeCursorAfterCodepointAt(int index);
+ method public void placeCursorAfterLastChange();
+ method public void placeCursorAtEnd();
+ method public void placeCursorBeforeCharAt(int index);
+ method public void placeCursorBeforeCodepointAt(int index);
+ method public void placeCursorBeforeFirstChange();
+ method public void revertAllChanges();
+ method public void selectAll();
+ method public void selectAllChanges();
+ method public void selectCharsIn(long range);
+ method public void selectCodepointsIn(long range);
+ property public final boolean hasSelection;
+ property public final long selectionInChars;
+ property public final long selectionInCodepoints;
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public sealed interface TextFieldCharSequence extends java.lang.CharSequence {
+ method public boolean contentEquals(CharSequence other);
+ method public boolean equals(Object? other);
+ method public androidx.compose.ui.text.TextRange? getCompositionInChars();
+ method public long getSelectionInChars();
+ method public int hashCode();
+ property public abstract androidx.compose.ui.text.TextRange? compositionInChars;
+ property public abstract long selectionInChars;
+ }
+
+ public final class TextFieldCharSequenceKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldCharSequence TextFieldCharSequence(optional String text, optional long selection);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public sealed interface TextFieldLineLimits {
+ field public static final androidx.compose.foundation.text2.input.TextFieldLineLimits.Companion Companion;
+ }
+
+ public static final class TextFieldLineLimits.Companion {
+ method public androidx.compose.foundation.text2.input.TextFieldLineLimits getDefault();
+ property public final androidx.compose.foundation.text2.input.TextFieldLineLimits Default;
+ }
+
+ @androidx.compose.runtime.Immutable public static final class TextFieldLineLimits.MultiLine implements androidx.compose.foundation.text2.input.TextFieldLineLimits {
+ ctor public TextFieldLineLimits.MultiLine(optional int minHeightInLines, optional int maxHeightInLines);
+ method public int getMaxHeightInLines();
+ method public int getMinHeightInLines();
+ property public final int maxHeightInLines;
+ property public final int minHeightInLines;
+ }
+
+ public static final class TextFieldLineLimits.SingleLine implements androidx.compose.foundation.text2.input.TextFieldLineLimits {
+ field public static final androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine INSTANCE;
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public final class TextFieldState {
+ ctor public TextFieldState(optional String initialText, optional long initialSelectionInChars);
+ method public inline void edit(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.text2.input.TextFieldBuffer,? extends androidx.compose.foundation.text2.input.TextEditResult> block);
+ method public androidx.compose.foundation.text2.input.TextFieldCharSequence getText();
+ property public final androidx.compose.foundation.text2.input.TextFieldCharSequence text;
+ }
+
+ public static final class TextFieldState.Saver implements androidx.compose.runtime.saveable.Saver<androidx.compose.foundation.text2.input.TextFieldState,java.lang.Object> {
+ method public androidx.compose.foundation.text2.input.TextFieldState? restore(Object value);
+ method public Object? save(androidx.compose.runtime.saveable.SaverScope, androidx.compose.foundation.text2.input.TextFieldState value);
+ field public static final androidx.compose.foundation.text2.input.TextFieldState.Saver INSTANCE;
+ }
+
+ public final class TextFieldStateKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static void clearText(androidx.compose.foundation.text2.input.TextFieldState);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static suspend Object? forEachTextValue(androidx.compose.foundation.text2.input.TextFieldState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.text2.input.TextFieldCharSequence,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<?>);
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static androidx.compose.foundation.text2.input.TextFieldState rememberTextFieldState();
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static void setTextAndPlaceCursorAtEnd(androidx.compose.foundation.text2.input.TextFieldState, String text);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static void setTextAndSelectAll(androidx.compose.foundation.text2.input.TextFieldState, String text);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static kotlinx.coroutines.flow.Flow<androidx.compose.foundation.text2.input.TextFieldCharSequence> textAsFlow(androidx.compose.foundation.text2.input.TextFieldState);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi @kotlin.jvm.JvmInline public final value class TextObfuscationMode {
+ method public int getValue();
+ property public final int value;
+ field public static final androidx.compose.foundation.text2.input.TextObfuscationMode.Companion Companion;
+ }
+
+ public static final class TextObfuscationMode.Companion {
+ method public int getHidden();
+ method public int getRevealLastTyped();
+ method public int getVisible();
+ property public final int Hidden;
+ property public final int RevealLastTyped;
+ property public final int Visible;
+ }
+
+}
+
diff --git a/compose/foundation/foundation/api/restricted_current.ignore b/compose/foundation/foundation/api/restricted_current.ignore
deleted file mode 100644
index 393276e..0000000
--- a/compose/foundation/foundation/api/restricted_current.ignore
+++ /dev/null
@@ -1,7 +0,0 @@
-// Baseline format: 1.0
-AddedAbstractMethod: androidx.compose.foundation.lazy.grid.LazyGridItemInfo#getContentType():
- Added method androidx.compose.foundation.lazy.grid.LazyGridItemInfo.getContentType()
-
-
-InvalidNullConversion: androidx.compose.foundation.MutatorMutex#mutateWith(T, androidx.compose.foundation.MutatePriority, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super R>,?>, kotlin.coroutines.Continuation<? super R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter receiver in androidx.compose.foundation.MutatorMutex.mutateWith(T receiver, androidx.compose.foundation.MutatePriority priority, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super R>,?> block, kotlin.coroutines.Continuation<? super R> arg4)
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index 15fd553..2a07dc7 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -48,6 +48,7 @@
}
public final class ClickableKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.CombinedClickableNode CombinedClickableNode(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, String? onLongClickLabel, kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, boolean enabled, String? onClickLabel, androidx.compose.ui.semantics.Role? role);
method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier combinedClickable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, optional String? onLongClickLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
@@ -58,6 +59,10 @@
method public static androidx.compose.ui.Modifier clipScrollableContainer(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.Orientation orientation);
}
+ @androidx.compose.foundation.ExperimentalFoundationApi public sealed interface CombinedClickableNode extends androidx.compose.ui.node.PointerInputModifierNode {
+ method public void update(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, String? onLongClickLabel, kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, boolean enabled, String? onClickLabel, androidx.compose.ui.semantics.Role? role);
+ }
+
public final class DarkThemeKt {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static boolean isSystemInDarkTheme();
}
@@ -229,6 +234,18 @@
package androidx.compose.foundation.gestures {
+ @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public interface BringIntoViewScroller {
+ method public float calculateScrollDistance(float offset, float size, float containerSize);
+ method public androidx.compose.animation.core.AnimationSpec<java.lang.Float> getScrollAnimationSpec();
+ property public abstract androidx.compose.animation.core.AnimationSpec<java.lang.Float> scrollAnimationSpec;
+ field public static final androidx.compose.foundation.gestures.BringIntoViewScroller.Companion Companion;
+ }
+
+ public static final class BringIntoViewScroller.Companion {
+ method public androidx.compose.animation.core.AnimationSpec<java.lang.Float> getDefaultScrollAnimationSpec();
+ property public final androidx.compose.animation.core.AnimationSpec<java.lang.Float> DefaultScrollAnimationSpec;
+ }
+
public final class DragGestureDetectorKt {
method public static suspend Object? awaitDragOrCancellation(androidx.compose.ui.input.pointer.AwaitPointerEventScope, long pointerId, kotlin.coroutines.Continuation<? super androidx.compose.ui.input.pointer.PointerInputChange>);
method public static suspend Object? awaitHorizontalDragOrCancellation(androidx.compose.ui.input.pointer.AwaitPointerEventScope, long pointerId, kotlin.coroutines.Continuation<? super androidx.compose.ui.input.pointer.PointerInputChange>);
@@ -297,6 +314,7 @@
}
public final class ScrollableDefaults {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public androidx.compose.foundation.gestures.BringIntoViewScroller bringIntoViewScroller();
method @androidx.compose.runtime.Composable public androidx.compose.foundation.gestures.FlingBehavior flingBehavior();
method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public androidx.compose.foundation.OverscrollEffect overscrollEffect();
method public boolean reverseDirection(androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.foundation.gestures.Orientation orientation, boolean reverseScrolling);
@@ -304,7 +322,7 @@
}
public final class ScrollableKt {
- method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, androidx.compose.foundation.OverscrollEffect? overscrollEffect, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, androidx.compose.foundation.OverscrollEffect? overscrollEffect, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.foundation.gestures.BringIntoViewScroller bringIntoViewScroller);
method public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
}
@@ -995,7 +1013,7 @@
@androidx.compose.foundation.ExperimentalFoundationApi public final class PagerDefaults {
method @androidx.compose.runtime.Composable public androidx.compose.foundation.gestures.snapping.SnapFlingBehavior flingBehavior(androidx.compose.foundation.pager.PagerState state, optional androidx.compose.foundation.pager.PagerSnapDistance pagerSnapDistance, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> lowVelocityAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float> highVelocityAnimationSpec, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> snapAnimationSpec, optional float snapVelocityThreshold, optional float snapPositionalThreshold);
- method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection pageNestedScrollConnection(androidx.compose.foundation.gestures.Orientation orientation);
+ method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection pageNestedScrollConnection(androidx.compose.foundation.pager.PagerState state, androidx.compose.foundation.gestures.Orientation orientation);
field public static final androidx.compose.foundation.pager.PagerDefaults INSTANCE;
}
@@ -1312,3 +1330,198 @@
}
+package androidx.compose.foundation.text2 {
+
+ public final class BasicSecureTextFieldKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void BasicSecureTextField(androidx.compose.foundation.text2.input.TextFieldState state, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,java.lang.Boolean>? onSubmit, optional int imeAction, optional int textObfuscationMode, optional int keyboardType, optional boolean enabled, optional androidx.compose.foundation.text2.input.TextEditFilter? filter, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional androidx.compose.foundation.ScrollState scrollState, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.unit.Density,? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+ }
+
+ public final class BasicTextField2Kt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void BasicTextField2(androidx.compose.foundation.text2.input.TextFieldState state, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.foundation.text2.input.TextEditFilter? filter, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional androidx.compose.foundation.text2.input.TextFieldLineLimits lineLimits, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.unit.Density,? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.foundation.text2.input.CodepointTransformation? codepointTransformation, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+ }
+
+}
+
+package androidx.compose.foundation.text2.input {
+
+ public final class AllCapsFilterKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter allCaps(androidx.compose.foundation.text2.input.TextEditFilter.Companion, androidx.compose.ui.text.intl.Locale locale);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public fun interface CodepointTransformation {
+ method public int transform(int codepointIndex, int codepoint);
+ field public static final androidx.compose.foundation.text2.input.CodepointTransformation.Companion Companion;
+ }
+
+ public static final class CodepointTransformation.Companion {
+ method public androidx.compose.foundation.text2.input.CodepointTransformation getNone();
+ property public final androidx.compose.foundation.text2.input.CodepointTransformation None;
+ }
+
+ public final class CodepointTransformationKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.CodepointTransformation mask(androidx.compose.foundation.text2.input.CodepointTransformation.Companion, char character);
+ }
+
+ public final class MaxLengthFilterKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter maxLengthInChars(androidx.compose.foundation.text2.input.TextEditFilter.Companion, int maxLength);
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter maxLengthInCodepoints(androidx.compose.foundation.text2.input.TextEditFilter.Companion, int maxLength);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public fun interface TextEditFilter {
+ method public void filter(androidx.compose.foundation.text2.input.TextFieldCharSequence originalValue, androidx.compose.foundation.text2.input.TextFieldBufferWithSelection valueWithChanges);
+ method public default androidx.compose.foundation.text.KeyboardOptions? getKeyboardOptions();
+ property public default androidx.compose.foundation.text.KeyboardOptions? keyboardOptions;
+ field public static final androidx.compose.foundation.text2.input.TextEditFilter.Companion Companion;
+ }
+
+ public static final class TextEditFilter.Companion {
+ }
+
+ public final class TextEditFilterKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter then(androidx.compose.foundation.text2.input.TextEditFilter, androidx.compose.foundation.text2.input.TextEditFilter next, optional androidx.compose.foundation.text.KeyboardOptions? keyboardOptions);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public abstract sealed class TextEditResult {
+ }
+
+ public final class TextEditResultKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAfterCharAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAfterCodepointAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAfterLastChange(androidx.compose.foundation.text2.input.TextFieldBuffer);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAtEnd(androidx.compose.foundation.text2.input.TextFieldBuffer);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorBeforeCharAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorBeforeCodepointAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorBeforeFirstChange(androidx.compose.foundation.text2.input.TextFieldBuffer);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectAll(androidx.compose.foundation.text2.input.TextFieldBuffer);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectAllChanges(androidx.compose.foundation.text2.input.TextFieldBuffer);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectCharsIn(androidx.compose.foundation.text2.input.TextFieldBuffer, long range);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectCodepointsIn(androidx.compose.foundation.text2.input.TextFieldBuffer, long range);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public class TextFieldBuffer implements java.lang.Appendable java.lang.CharSequence {
+ method public Appendable append(char char);
+ method public Appendable append(CharSequence? text);
+ method public Appendable append(CharSequence? text, int start, int end);
+ method public operator char get(int index);
+ method public final androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList getChanges();
+ method public final int getCodepointLength();
+ method public int getLength();
+ method @CallSuper protected void onTextWillChange(long rangeToBeReplaced, int newLength);
+ method public final void replace(int start, int end, String text);
+ method public CharSequence subSequence(int startIndex, int endIndex);
+ property public final androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList changes;
+ property public final int codepointLength;
+ property public int length;
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public static interface TextFieldBuffer.ChangeList {
+ method public int getChangeCount();
+ method public long getOriginalRange(int changeIndex);
+ method public long getRange(int changeIndex);
+ property public abstract int changeCount;
+ }
+
+ public final class TextFieldBufferKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static void delete(androidx.compose.foundation.text2.input.TextFieldBuffer, int start, int end);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static inline void forEachChange(androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.TextRange,? super androidx.compose.ui.text.TextRange,kotlin.Unit> block);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static inline void forEachChangeReversed(androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.TextRange,? super androidx.compose.ui.text.TextRange,kotlin.Unit> block);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static void insert(androidx.compose.foundation.text2.input.TextFieldBuffer, int index, String text);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public final class TextFieldBufferWithSelection extends androidx.compose.foundation.text2.input.TextFieldBuffer {
+ method public boolean getHasSelection();
+ method public long getSelectionInChars();
+ method public long getSelectionInCodepoints();
+ method public void placeCursorAfterCharAt(int index);
+ method public void placeCursorAfterCodepointAt(int index);
+ method public void placeCursorAfterLastChange();
+ method public void placeCursorAtEnd();
+ method public void placeCursorBeforeCharAt(int index);
+ method public void placeCursorBeforeCodepointAt(int index);
+ method public void placeCursorBeforeFirstChange();
+ method public void revertAllChanges();
+ method public void selectAll();
+ method public void selectAllChanges();
+ method public void selectCharsIn(long range);
+ method public void selectCodepointsIn(long range);
+ property public final boolean hasSelection;
+ property public final long selectionInChars;
+ property public final long selectionInCodepoints;
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi public sealed interface TextFieldCharSequence extends java.lang.CharSequence {
+ method public boolean contentEquals(CharSequence other);
+ method public boolean equals(Object? other);
+ method public androidx.compose.ui.text.TextRange? getCompositionInChars();
+ method public long getSelectionInChars();
+ method public int hashCode();
+ property public abstract androidx.compose.ui.text.TextRange? compositionInChars;
+ property public abstract long selectionInChars;
+ }
+
+ public final class TextFieldCharSequenceKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldCharSequence TextFieldCharSequence(optional String text, optional long selection);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public sealed interface TextFieldLineLimits {
+ field public static final androidx.compose.foundation.text2.input.TextFieldLineLimits.Companion Companion;
+ }
+
+ public static final class TextFieldLineLimits.Companion {
+ method public androidx.compose.foundation.text2.input.TextFieldLineLimits getDefault();
+ property public final androidx.compose.foundation.text2.input.TextFieldLineLimits Default;
+ }
+
+ @androidx.compose.runtime.Immutable public static final class TextFieldLineLimits.MultiLine implements androidx.compose.foundation.text2.input.TextFieldLineLimits {
+ ctor public TextFieldLineLimits.MultiLine(optional int minHeightInLines, optional int maxHeightInLines);
+ method public int getMaxHeightInLines();
+ method public int getMinHeightInLines();
+ property public final int maxHeightInLines;
+ property public final int minHeightInLines;
+ }
+
+ public static final class TextFieldLineLimits.SingleLine implements androidx.compose.foundation.text2.input.TextFieldLineLimits {
+ field public static final androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine INSTANCE;
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public final class TextFieldState {
+ ctor public TextFieldState(optional String initialText, optional long initialSelectionInChars);
+ method @kotlin.PublishedApi internal void commitEdit(androidx.compose.foundation.text2.input.TextFieldBuffer newValue, androidx.compose.foundation.text2.input.TextEditResult result);
+ method public inline void edit(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.text2.input.TextFieldBuffer,? extends androidx.compose.foundation.text2.input.TextEditResult> block);
+ method public androidx.compose.foundation.text2.input.TextFieldCharSequence getText();
+ method @kotlin.PublishedApi internal androidx.compose.foundation.text2.input.TextFieldBuffer startEdit(androidx.compose.foundation.text2.input.TextFieldCharSequence value);
+ property public final androidx.compose.foundation.text2.input.TextFieldCharSequence text;
+ }
+
+ public static final class TextFieldState.Saver implements androidx.compose.runtime.saveable.Saver<androidx.compose.foundation.text2.input.TextFieldState,java.lang.Object> {
+ method public androidx.compose.foundation.text2.input.TextFieldState? restore(Object value);
+ method public Object? save(androidx.compose.runtime.saveable.SaverScope, androidx.compose.foundation.text2.input.TextFieldState value);
+ field public static final androidx.compose.foundation.text2.input.TextFieldState.Saver INSTANCE;
+ }
+
+ public final class TextFieldStateKt {
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static void clearText(androidx.compose.foundation.text2.input.TextFieldState);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static suspend Object? forEachTextValue(androidx.compose.foundation.text2.input.TextFieldState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.text2.input.TextFieldCharSequence,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<?>);
+ method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static androidx.compose.foundation.text2.input.TextFieldState rememberTextFieldState();
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static void setTextAndPlaceCursorAtEnd(androidx.compose.foundation.text2.input.TextFieldState, String text);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static void setTextAndSelectAll(androidx.compose.foundation.text2.input.TextFieldState, String text);
+ method @androidx.compose.foundation.ExperimentalFoundationApi public static kotlinx.coroutines.flow.Flow<androidx.compose.foundation.text2.input.TextFieldCharSequence> textAsFlow(androidx.compose.foundation.text2.input.TextFieldState);
+ }
+
+ @androidx.compose.foundation.ExperimentalFoundationApi @kotlin.jvm.JvmInline public final value class TextObfuscationMode {
+ method public int getValue();
+ property public final int value;
+ field public static final androidx.compose.foundation.text2.input.TextObfuscationMode.Companion Companion;
+ }
+
+ public static final class TextObfuscationMode.Companion {
+ method public int getHidden();
+ method public int getRevealLastTyped();
+ method public int getVisible();
+ property public final int Hidden;
+ property public final int RevealLastTyped;
+ property public final int Visible;
+ }
+
+}
+
diff --git a/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyListScrollingBenchmark.kt b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyListScrollingBenchmark.kt
index 329cccc..1f68d41 100644
--- a/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyListScrollingBenchmark.kt
+++ b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyListScrollingBenchmark.kt
@@ -82,6 +82,30 @@
}
@Test
+ fun scrollProgrammatically_noNewItems_withoutKeys() {
+ benchmarkRule.toggleStateBenchmark {
+ ListRemeasureTestCase(
+ addNewItemOnToggle = false,
+ content = testCase.content,
+ isVertical = testCase.isVertical,
+ useKeys = false
+ )
+ }
+ }
+
+ @Test
+ fun scrollProgrammatically_newItemComposed_withoutKeys() {
+ benchmarkRule.toggleStateBenchmark {
+ ListRemeasureTestCase(
+ addNewItemOnToggle = true,
+ content = testCase.content,
+ isVertical = testCase.isVertical,
+ useKeys = false
+ )
+ }
+ }
+
+ @Test
fun scrollViaPointerInput_noNewItems() {
benchmarkRule.toggleStateBenchmark {
ListRemeasureTestCase(
@@ -152,7 +176,7 @@
class LazyListScrollingTestCase(
private val name: String,
val isVertical: Boolean,
- val content: @Composable ListRemeasureTestCase.(LazyListState) -> Unit
+ val content: @Composable ListRemeasureTestCase.(LazyListState, useKeys: Boolean) -> Unit
) {
override fun toString(): String {
return name
@@ -162,16 +186,23 @@
private val LazyColumn = LazyListScrollingTestCase(
"LazyColumn",
isVertical = true
-) { state ->
+) { state, useKeys ->
LazyColumn(
state = state,
- modifier = Modifier.requiredHeight(400.dp).fillMaxWidth(),
+ modifier = Modifier
+ .requiredHeight(400.dp)
+ .fillMaxWidth(),
flingBehavior = NoFlingBehavior
) {
- item {
+ item(key = if (useKeys) "header" else null) {
FirstLargeItem()
}
- items(items) {
+ items(
+ items, key = if (useKeys) {
+ { it.index }
+ } else {
+ null
+ }) {
RegularItem()
}
}
@@ -180,16 +211,22 @@
private val LazyRow = LazyListScrollingTestCase(
"LazyRow",
isVertical = false
-) { state ->
+) { state, useKeys ->
LazyRow(
state = state,
- modifier = Modifier.requiredWidth(400.dp).fillMaxHeight(),
+ modifier = Modifier
+ .requiredWidth(400.dp)
+ .fillMaxHeight(),
flingBehavior = NoFlingBehavior
) {
- item {
+ item(if (useKeys) "header" else null) {
FirstLargeItem()
}
- items(items) {
+ items(items, key = if (useKeys) {
+ { it.index }
+ } else {
+ null
+ }) {
RegularItem()
}
}
@@ -197,9 +234,10 @@
class ListRemeasureTestCase(
val addNewItemOnToggle: Boolean,
- val content: @Composable ListRemeasureTestCase.(LazyListState) -> Unit,
+ val content: @Composable ListRemeasureTestCase.(LazyListState, useKeys: Boolean) -> Unit,
val isVertical: Boolean,
- val usePointerInput: Boolean = false
+ val usePointerInput: Boolean = false,
+ val useKeys: Boolean = true
) : LazyBenchmarkTestCase {
val items = List(100) { LazyItem(it) }
@@ -226,12 +264,15 @@
if (!::motionEventHelper.isInitialized) motionEventHelper = MotionEventHelper(view)
touchSlop = LocalViewConfiguration.current.touchSlop
listState = rememberLazyListState()
- content(listState)
+ content(listState, useKeys)
}
@Composable
fun RegularItem() {
- Box(Modifier.requiredSize(20.dp).background(Color.Red, RoundedCornerShape(8.dp)))
+ Box(
+ Modifier
+ .requiredSize(20.dp)
+ .background(Color.Red, RoundedCornerShape(8.dp)))
}
override fun beforeToggle() {
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
index efb61005..0f8a1de 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
@@ -61,7 +61,8 @@
ComposableDemo("Simple InteractionSource") { SimpleInteractionSourceSample() },
ComposableDemo("Flow InteractionSource") { InteractionSourceFlowSample() },
DemoCategory("Suspending Gesture Detectors", CoroutineGestureDemos),
- ComposableDemo("NestedScroll") { NestedScrollDemo() },
+ ComposableDemo("Nested Scroll") { NestedScrollDemo() },
+ ComposableDemo("Nested Scroll Connection") { NestedScrollConnectionSample() },
DemoCategory("Relocation Demos", RelocationDemos),
DemoCategory("Focus Demos", FocusDemos),
DemoCategory("Magnifier Demos", MagnifierDemos),
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/MagnifierDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/MagnifierDemos.kt
index 05418d0..0121df1 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/MagnifierDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/MagnifierDemos.kt
@@ -107,14 +107,15 @@
drawRect(color)
// Draw something interesting to zoom in on.
+ @Suppress("SteppedForLoop")
for (diameter in 2 until size.maxDimension.toInt() step 10) {
- drawCircle(
- color = Color.Black,
- radius = diameter / 2f,
- style = Stroke()
- )
+ drawCircle(
+ color = Color.Black,
+ radius = diameter / 2f,
+ style = Stroke()
+ )
+ }
}
- }
.pointerInput(Unit) {
awaitPointerEventScope {
while (true) {
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/NestedScrollDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/NestedScrollDemos.kt
index bfe8004..fe39345 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/NestedScrollDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/NestedScrollDemos.kt
@@ -31,9 +31,17 @@
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
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.geometry.Offset
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -104,4 +112,42 @@
}
}
}
-}
\ No newline at end of file
+}
+
+@Composable
+fun NestedScrollConnectionSample() {
+ var availableOffset by remember { mutableStateOf(Offset.Zero) }
+
+ val nestedScrollConnection = remember {
+ object : NestedScrollConnection {
+ override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
+ availableOffset = available
+
+ // In this case we aren't consuming any of the offset, just showing what is
+ // available.
+ return Offset.Zero
+ }
+ }
+ }
+ Box(
+ Modifier
+ .fillMaxSize()
+ // attach as a parent to the nested scroll system
+ .nestedScroll(nestedScrollConnection)
+ ) {
+ Column {
+ Text(
+ modifier = Modifier.fillMaxWidth(),
+ text = "Scroll Connection PreScroll available: $availableOffset")
+
+ // our list with build in nested scroll support that will notify us about its scroll
+ LazyColumn {
+ items(100) { index ->
+ Text("I'm item $index", modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp))
+ }
+ }
+ }
+ }
+}
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/pager/PagerCarrouselDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/pager/PagerCarrouselDemos.kt
index 5b43150..326bac5 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/pager/PagerCarrouselDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/pager/PagerCarrouselDemos.kt
@@ -18,6 +18,7 @@
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
+import androidx.compose.foundation.focusable
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -129,6 +130,7 @@
@Composable
private fun CarrouselItem(index: Int, fillOrientation: Orientation) {
val fillAxisModifier = if (fillOrientation == Orientation.Vertical) Modifier
+ .focusable()
.fillMaxWidth()
.height(256.dp) else Modifier
.fillMaxHeight()
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/pager/PagerDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/pager/PagerDemos.kt
index 45a08b6..242498a 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/pager/PagerDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/pager/PagerDemos.kt
@@ -34,6 +34,7 @@
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
+import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
@@ -98,6 +99,7 @@
internal fun PagerItem(index: Int) {
Box(
modifier = Modifier
+ .focusable()
.padding(10.dp)
.background(Color.Blue)
.fillMaxWidth()
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/performance/DrawingDemo.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/performance/DrawingDemo.kt
new file mode 100644
index 0000000..e310b12
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/performance/DrawingDemo.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.demos.performance
+
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.background
+import androidx.compose.foundation.gestures.detectDragGestures
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.tooling.preview.Preview
+
+/**
+ * This demo draws a straight line from where the screen was first touched to where the
+ * pointer is now. It basically tracks drag operations, drawing a line between the start
+ * and end positions of that drag. The intention of this app is to allow easy testing of
+ * what Compose is doing during drag operations (allocations, etc).
+ */
+@Preview
+@Composable
+fun DrawingDemo() {
+ val start = remember { mutableStateOf(Offset(0f, 0f)) }
+ val end = remember { mutableStateOf(Offset(0f, 0f)) }
+ Canvas(modifier = Modifier
+ .fillMaxWidth()
+ .fillMaxHeight()
+ .background(Color.White)
+ .pointerInput(Unit) {
+ detectDragGestures(
+ onDragStart = {
+ start.value = it
+ end.value = it
+ }
+ ) { _, dragAmount ->
+ end.value += dragAmount
+ }
+ }
+ ) {
+ drawLine(Color.Blue, start = start.value, end = end.value)
+ }
+}
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/performance/PerformanceDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/performance/PerformanceDemos.kt
new file mode 100644
index 0000000..9da7417
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/performance/PerformanceDemos.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.demos.performance
+
+import androidx.compose.integration.demos.common.ComposableDemo
+import androidx.compose.integration.demos.common.DemoCategory
+
+/**
+ * These demos are for triggering specific elements of Compose, to enable testing the performance
+ * (runtime duration, allocations, etc) of those elements.
+ */
+val PerformanceDemos = DemoCategory(
+ "Performance",
+ listOf(
+ ComposableDemo("Recomposition") { RecompositionDemo() },
+ ComposableDemo("Drawing") { DrawingDemo() },
+ )
+)
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/performance/RecompositionDemo.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/performance/RecompositionDemo.kt
new file mode 100644
index 0000000..9edab5b
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/performance/RecompositionDemo.kt
@@ -0,0 +1,158 @@
+/*
+ * 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.demos.performance
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.Button
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+/**
+ * This demo enables easy, targeted testing of simple recomposition situations.
+ * Each composable element below tests a specific hierarchy of objects. Tapping on the element
+ * triggers a recomposition of that element, which can be tested to see what Compose is doing
+ * to make that happen (allocations, etc).
+ *
+ * All of the demos use the same mechanism of a coroutine with an initial and per-frame delay
+ * to force the recomposition to happen at times and frequencies that can be examined in tools.
+ * The reason for the initial delay is to move the recomposition pieces away from any tough/ripple
+ * behavior of a composable, to make the resulting results clearer.
+ */
+@Preview
+@Composable
+fun RecompositionDemo() {
+ Column() {
+ Row(Modifier.padding(8.dp)) {
+ Text("Empty Box")
+ BoxElement()
+ }
+ Row(Modifier.padding(8.dp)) {
+ Text("No-Ripple Box")
+ NoRippleBoxElement()
+ }
+ Row(Modifier.padding(8.dp)) {
+ Text("Button")
+ ButtonElement()
+ }
+ }
+}
+
+// How many times the test will run
+val Iterations = 10
+
+// How long to delay between each iteration
+val PerFrameDelay = 100L
+
+// How long to delay (after tap) before first recomposition
+val InitialDelay = 1000L
+
+/**
+ * This hierarchy consists of just a single, empty Box composable.
+ */
+@Composable
+fun BoxElement() {
+ var iteration by remember { mutableIntStateOf(0) }
+ val scope = rememberCoroutineScope()
+ Box(modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .background(Color.Blue)
+ .clickable {
+ scope.launch {
+ // Note the initial delay to delineate the recomposition from other UI behavior
+ // such as touch input and ripple
+ delay(InitialDelay)
+ while (iteration < Iterations) {
+ delay(PerFrameDelay)
+ iteration++
+ }
+ }
+ iteration = 0
+ })
+}
+
+/**
+ * This hierarchy consists of just a single, empty Box composable. The default click
+ * indication is disabled to ensure that there will be no ripple. This is useful for testing
+ * the result of touch input when the element is tapped (separate from the ripple animation
+ * behavior).
+ */
+@Composable
+fun NoRippleBoxElement() {
+ var iteration by remember { mutableIntStateOf(0) }
+ val scope = rememberCoroutineScope()
+ val interactionSource = remember { MutableInteractionSource() }
+ Box(modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .background(Color.Blue)
+ .clickable(interactionSource = interactionSource, indication = null) {
+ scope.launch {
+ delay(InitialDelay)
+ while (iteration < Iterations) {
+ delay(PerFrameDelay)
+ iteration++
+ }
+ }
+ iteration = 0
+ })
+}
+
+/**
+ * This hierarchy consists of just a single, empty Button composable, to see whether recomposition
+ * of a Button is significantly different from other composables.
+ */
+@Composable
+fun ButtonElement() {
+ var iteration by remember { mutableIntStateOf(0) }
+ val scope = rememberCoroutineScope()
+ Button(modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .background(Color.Blue),
+ onClick = {
+ scope.launch {
+ delay(InitialDelay)
+ while (iteration < Iterations) {
+ delay(PerFrameDelay)
+ iteration++
+ }
+ iteration = 0
+ }
+ }) {
+ Text(text = "Button")
+ }
+}
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
index d48487a..22447b4 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
@@ -16,6 +16,13 @@
package androidx.compose.foundation.demos.text
+import androidx.compose.foundation.demos.text2.BasicSecureTextFieldDemos
+import androidx.compose.foundation.demos.text2.BasicTextField2CustomPinFieldDemo
+import androidx.compose.foundation.demos.text2.BasicTextField2Demos
+import androidx.compose.foundation.demos.text2.BasicTextField2FilterDemos
+import androidx.compose.foundation.demos.text2.DecorationBoxDemos
+import androidx.compose.foundation.demos.text2.KeyboardOptionsDemos
+import androidx.compose.foundation.demos.text2.ScrollableDemos
import androidx.compose.integration.demos.common.ComposableDemo
import androidx.compose.integration.demos.common.DemoCategory
@@ -121,6 +128,18 @@
)
),
DemoCategory(
+ "BasicTextField2",
+ listOf(
+ ComposableDemo("Basic text input") { BasicTextField2Demos() },
+ ComposableDemo("Keyboard Options") { KeyboardOptionsDemos() },
+ ComposableDemo("Decoration Box") { DecorationBoxDemos() },
+ ComposableDemo("Scroll") { ScrollableDemos() },
+ ComposableDemo("Filters") { BasicTextField2FilterDemos() },
+ ComposableDemo("Secure Field") { BasicSecureTextFieldDemos() },
+ ComposableDemo("Custom PIN field") { BasicTextField2CustomPinFieldDemo() },
+ )
+ ),
+ DemoCategory(
"Selection",
listOf(
ComposableDemo("Text selection") { TextSelectionDemo() },
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicSecureTextFieldDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicSecureTextFieldDemos.kt
new file mode 100644
index 0000000..c4030ea
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicSecureTextFieldDemos.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.demos.text2
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.border
+import androidx.compose.foundation.demos.text.TagLine
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.imePadding
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text2.BasicSecureTextField
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.TextObfuscationMode
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.Icon
+import androidx.compose.material.IconToggleButton
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Info
+import androidx.compose.material.icons.filled.Warning
+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.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.unit.dp
+import androidx.core.text.isDigitsOnly
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun BasicSecureTextFieldDemos() {
+ Column(
+ Modifier
+ .imePadding()
+ .verticalScroll(rememberScrollState())
+ ) {
+ TagLine(tag = "Visible")
+ BasicSecureTextFieldDemo(TextObfuscationMode.Visible)
+
+ TagLine(tag = "RevealLastTyped")
+ BasicSecureTextFieldDemo(TextObfuscationMode.RevealLastTyped)
+
+ TagLine(tag = "Hidden")
+ BasicSecureTextFieldDemo(TextObfuscationMode.Hidden)
+
+ TagLine(tag = "Number Password")
+ NumberPasswordDemo()
+
+ TagLine(tag = "Password Toggle Visibility")
+ PasswordToggleVisibilityDemo()
+ }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun BasicSecureTextFieldDemo(textObfuscationMode: TextObfuscationMode) {
+ val state = remember { TextFieldState() }
+ BasicSecureTextField(
+ state = state,
+ textObfuscationMode = textObfuscationMode,
+ modifier = demoTextFieldModifiers
+ )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun NumberPasswordDemo() {
+ val state = remember { TextFieldState() }
+ BasicSecureTextField(
+ state = state,
+ filter = { _, new ->
+ if (!new.isDigitsOnly()) {
+ new.revertAllChanges()
+ }
+ },
+ keyboardType = KeyboardType.NumberPassword,
+ imeAction = ImeAction.Default,
+ modifier = demoTextFieldModifiers
+ )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun PasswordToggleVisibilityDemo() {
+ val state = remember { TextFieldState() }
+ var visible by remember { mutableStateOf(false) }
+ Row(Modifier.fillMaxWidth()) {
+ BasicSecureTextField(
+ state = state,
+ textObfuscationMode = if (visible) {
+ TextObfuscationMode.Visible
+ } else {
+ TextObfuscationMode.RevealLastTyped
+ },
+ modifier = Modifier
+ .weight(1f)
+ .padding(6.dp)
+ .border(1.dp, Color.LightGray, RoundedCornerShape(6.dp))
+ .padding(6.dp)
+ )
+ IconToggleButton(checked = visible, onCheckedChange = { visible = it }) {
+ if (visible) {
+ Icon(Icons.Default.Warning, "")
+ } else {
+ Icon(Icons.Default.Info, "")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2CustomPinFieldDemo.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2CustomPinFieldDemo.kt
new file mode 100644
index 0000000..2fca5e7
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2CustomPinFieldDemo.kt
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.demos.text2
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.foundation.text2.BasicTextField2
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldBufferWithSelection
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.clearText
+import androidx.compose.foundation.text2.input.maxLengthInChars
+import androidx.compose.foundation.text2.input.then
+import androidx.compose.material.CircularProgressIndicator
+import androidx.compose.material.LocalContentAlpha
+import androidx.compose.material.LocalContentColor
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.snapshotFlow
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.graphics.BlurEffect
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.TileMode
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.style.TextDecoration
+import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.unit.dp
+import androidx.core.text.isDigitsOnly
+import kotlin.random.Random
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.filter
+
+@Composable
+fun BasicTextField2CustomPinFieldDemo() {
+ val viewModel = remember { VerifyPinViewModel() }
+ VerifyPinScreen(viewModel)
+}
+
+@Suppress("AnimateAsStateLabel")
+@Composable
+private fun VerifyPinScreen(viewModel: VerifyPinViewModel) {
+ val focusRequester = remember { FocusRequester() }
+
+ LaunchedEffect(viewModel) {
+ viewModel.run()
+ }
+
+ if (!viewModel.isLoading) {
+ DisposableEffect(Unit) {
+ focusRequester.requestFocus()
+ onDispose {}
+ }
+ }
+ val blurRadius by animateDpAsState(if (viewModel.isLoading) 5.dp else 0.dp)
+ val scale by animateFloatAsState(if (viewModel.isLoading) 0.85f else 1f)
+
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier
+ .fillMaxSize()
+ .wrapContentHeight()
+ ) {
+ PinField(
+ viewModel.pinState,
+ enabled = !viewModel.isLoading,
+ modifier = Modifier
+ .focusRequester(focusRequester)
+ .graphicsLayer {
+ if (blurRadius != 0.dp) {
+ val blurRadiusPx = blurRadius.toPx()
+ renderEffect =
+ BlurEffect(blurRadiusPx, blurRadiusPx, edgeTreatment = TileMode.Decal)
+ }
+ scaleX = scale
+ scaleY = scale
+ }
+ )
+ AnimatedVisibility(visible = viewModel.isLoading) {
+ CircularProgressIndicator(Modifier.padding(top = 8.dp))
+ }
+ }
+}
+
+private class VerifyPinViewModel {
+ val pinState = PinState(maxDigits = 6)
+ val isLoading: Boolean by derivedStateOf { pinState.digits.length == 6 }
+
+ suspend fun run() {
+ snapshotFlow { pinState.digits }
+ .filter { it.length == 6 }
+ .collectLatest { digits ->
+ validatePin(digits)
+ }
+ }
+
+ private suspend fun validatePin(digits: String): Boolean {
+ val random = Random(digits.toInt())
+ val isValid = random.nextBoolean()
+
+ if (isValid) {
+ awaitCancellation()
+ } else {
+ val delay = random.nextInt(3, 8) * 250
+ delay(delay.toLong())
+ pinState.clear()
+ return false
+ }
+ }
+}
+
+@Stable
+private class PinState(val maxDigits: Int) {
+ val digits: String by derivedStateOf {
+ textState.text.toString()
+ }
+
+ /*internal*/ val textState = TextFieldState()
+ /*internal*/ val filter: TextEditFilter = OnlyDigitsFilter.then(
+ TextEditFilter.maxLengthInChars(maxDigits),
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword)
+ )
+
+ fun clear() {
+ textState.clearText()
+ }
+
+ private object OnlyDigitsFilter : TextEditFilter {
+ override fun filter(
+ originalValue: TextFieldCharSequence,
+ valueWithChanges: TextFieldBufferWithSelection
+ ) {
+ if (!valueWithChanges.isDigitsOnly()) {
+ valueWithChanges.revertAllChanges()
+ }
+ }
+ }
+}
+
+@Composable
+private fun PinField(
+ state: PinState,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true
+) {
+ val contentAlpha = if (enabled) 1f else 0.3f
+ val contentColor = LocalContentColor.current.copy(alpha = contentAlpha)
+
+ BasicTextField2(
+ state = state.textState,
+ filter = state.filter,
+ modifier = modifier
+ .border(1.dp, contentColor, RoundedCornerShape(8.dp))
+ .padding(8.dp),
+ enabled = enabled
+ ) {
+ CompositionLocalProvider(LocalContentAlpha provides contentAlpha) {
+ // Ignore inner field, we'll draw it ourselves.
+ PinContents(state)
+ }
+ }
+}
+
+@Composable
+private fun PinContents(state: PinState) {
+ val focusedColor = MaterialTheme.colors.secondary.copy(alpha = LocalContentAlpha.current)
+ val text = buildAnnotatedString {
+ val digits = state.digits
+ repeat(state.maxDigits) { i ->
+ withStyle(
+ SpanStyle(
+ textDecoration = TextDecoration.Underline,
+ background = if (digits.length == i) focusedColor else Color.Unspecified,
+ )
+ ) {
+ append(if (digits.length > i) digits[i].toString() else " ")
+ }
+ if (i < state.maxDigits - 1) {
+ append(" - ")
+ }
+ }
+ }
+ Text(text, fontFamily = FontFamily.Monospace)
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2Demos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2Demos.kt
new file mode 100644
index 0000000..22a6c91
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2Demos.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.compose.foundation.demos.text2
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.demos.text.TagLine
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.imePadding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.text2.BasicTextField2
+import androidx.compose.foundation.text2.input.TextFieldLineLimits
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.LocalTextStyle
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+
+@Composable
+fun BasicTextField2Demos() {
+ Column(
+ Modifier
+ .imePadding()
+ .verticalScroll(rememberScrollState())
+ ) {
+ TagLine(tag = "Plain BasicTextField2")
+ PlainBasicTextField2()
+
+ TagLine(tag = "Single Line BasicTextField2")
+ SingleLineBasicTextField2()
+
+ TagLine(tag = "State toggling BasicTextField2")
+ StateTogglingBasicTextField2()
+ }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun PlainBasicTextField2() {
+ val state = remember { TextFieldState() }
+ BasicTextField2(state, demoTextFieldModifiers, textStyle = LocalTextStyle.current)
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun SingleLineBasicTextField2() {
+ val state = remember { TextFieldState() }
+ BasicTextField2(
+ state = state,
+ modifier = demoTextFieldModifiers,
+ textStyle = LocalTextStyle.current,
+ lineLimits = TextFieldLineLimits.SingleLine
+ )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun StateTogglingBasicTextField2() {
+ var counter by remember { mutableIntStateOf(0) }
+ val states = remember { listOf(TextFieldState(), TextFieldState()) }
+ val state = states[counter]
+ Text("Click to toggle state: $counter", modifier = Modifier.clickable {
+ counter++
+ counter %= 2
+ })
+
+ BasicTextField2(state, demoTextFieldModifiers, textStyle = LocalTextStyle.current)
+}
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2FilterDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2FilterDemos.kt
new file mode 100644
index 0000000..b0e09b9
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2FilterDemos.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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.demos.text2
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.demos.text.TagLine
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.imePadding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.samples.BasicTextField2ChangeIterationSample
+import androidx.compose.foundation.samples.BasicTextField2ChangeReverseIterationSample
+import androidx.compose.foundation.samples.BasicTextField2CustomFilterSample
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.foundation.text2.BasicTextField2
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldBufferWithSelection
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.allCaps
+import androidx.compose.foundation.text2.input.maxLengthInChars
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.intl.Locale
+import androidx.core.text.isDigitsOnly
+
+@Composable
+fun BasicTextField2FilterDemos() {
+ Column(
+ Modifier
+ .imePadding()
+ .verticalScroll(rememberScrollState())
+ ) {
+ TagLine(tag = "allCaps")
+ FilterDemo(filter = TextEditFilter.allCaps(Locale.current))
+
+ TagLine(tag = "maxLength(5)")
+ FilterDemo(filter = TextEditFilter.maxLengthInChars(5))
+
+ TagLine(tag = "Digits Only BasicTextField2")
+ DigitsOnlyBasicTextField2()
+
+ TagLine(tag = "Custom (type backwards with prompt)")
+ Box(demoTextFieldModifiers, propagateMinConstraints = true) {
+ BasicTextField2CustomFilterSample()
+ }
+
+ TagLine(tag = "Change tracking (change logging sample)")
+ Box(demoTextFieldModifiers, propagateMinConstraints = true) {
+ BasicTextField2ChangeIterationSample()
+ }
+
+ TagLine(tag = "Change tracking (insert mode sample)")
+ Box(demoTextFieldModifiers, propagateMinConstraints = true) {
+ BasicTextField2ChangeReverseIterationSample()
+ }
+ }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun DigitsOnlyBasicTextField2() {
+ FilterDemo(filter = object : TextEditFilter {
+ override val keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Number
+ )
+
+ override fun filter(
+ originalValue: TextFieldCharSequence,
+ valueWithChanges: TextFieldBufferWithSelection
+ ) {
+ if (!valueWithChanges.isDigitsOnly()) {
+ valueWithChanges.revertAllChanges()
+ }
+ }
+ })
+}
+
+@Composable
+private fun FilterDemo(filter: TextEditFilter) {
+ val state = remember { TextFieldState() }
+ BasicTextField2(
+ state = state,
+ filter = filter,
+ modifier = demoTextFieldModifiers
+ )
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/DecorationBoxDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/DecorationBoxDemos.kt
new file mode 100644
index 0000000..6b7c425
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/DecorationBoxDemos.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
+
+package androidx.compose.foundation.demos.text2
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.demos.text.TagLine
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.text2.BasicTextField2
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.material.LocalTextStyle
+import androidx.compose.material.TextFieldDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.input.VisualTransformation
+
+@Composable
+fun DecorationBoxDemos() {
+ Column {
+ TagLine(tag = "OutlinedTextField")
+ OutlinedBasicTextField2()
+ }
+}
+
+@Composable
+fun OutlinedBasicTextField2() {
+ val state = remember { TextFieldState() }
+ BasicTextField2(
+ state = state,
+ modifier = Modifier,
+ textStyle = LocalTextStyle.current,
+ decorationBox = @Composable {
+ TextFieldDefaults.OutlinedTextFieldDecorationBox(
+ value = state.text.toString(),
+ visualTransformation = VisualTransformation.None,
+ innerTextField = it,
+ placeholder = null,
+ label = null,
+ leadingIcon = null,
+ trailingIcon = null,
+ singleLine = true,
+ enabled = true,
+ isError = false,
+ interactionSource = remember { MutableInteractionSource() },
+ colors = TextFieldDefaults.outlinedTextFieldColors()
+ )
+ }
+ )
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/KeyboardOptionsDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/KeyboardOptionsDemos.kt
new file mode 100644
index 0000000..3590e8e
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/KeyboardOptionsDemos.kt
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.demos.text2
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.border
+import androidx.compose.foundation.demos.text.TagLine
+import androidx.compose.foundation.demos.text.fontSize8
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.foundation.text2.BasicTextField2
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+
+@Preview
+@Composable
+fun KeyboardOptionsDemos() {
+ LazyColumn {
+ item { Item(KeyboardType.Text) }
+ item { Item(KeyboardType.Ascii) }
+ item { Item(KeyboardType.Number) }
+ item { Item(KeyboardType.Phone) }
+ item { Item(KeyboardType.Uri) }
+ item { Item(KeyboardType.Email) }
+ item { Item(KeyboardType.Password) }
+ item { Item(KeyboardType.NumberPassword) }
+ }
+}
+
+@Composable
+private fun Item(keyboardType: KeyboardType) {
+ TagLine(tag = "Keyboard Type: $keyboardType")
+ EditLine(keyboardType = keyboardType)
+}
+
+@Composable
+private fun EditLine(
+ keyboardType: KeyboardType = KeyboardType.Text,
+ imeAction: ImeAction = ImeAction.Default,
+ text: String = ""
+) {
+ val state = remember { TextFieldState(text) }
+ BasicTextField2(
+ modifier = demoTextFieldModifiers,
+ state = state,
+ keyboardOptions = KeyboardOptions(
+ keyboardType = keyboardType,
+ imeAction = imeAction
+ ),
+ textStyle = TextStyle(fontSize = fontSize8),
+ )
+}
+
+val demoTextFieldModifiers = Modifier
+ .fillMaxWidth()
+ .padding(6.dp)
+ .border(1.dp, Color.LightGray, RoundedCornerShape(6.dp))
+ .padding(6.dp)
\ No newline at end of file
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/ScrollDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/ScrollDemos.kt
new file mode 100644
index 0000000..edd9b9c
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/ScrollDemos.kt
@@ -0,0 +1,203 @@
+/*
+ * 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.demos.text2
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.demos.text.TagLine
+import androidx.compose.foundation.layout.Column
+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.lazy.LazyColumn
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.text2.BasicTextField2
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.material.Slider
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import kotlin.math.roundToInt
+import kotlinx.coroutines.launch
+
+@Composable
+fun ScrollableDemos() {
+ LazyColumn(Modifier.padding(16.dp)) {
+ item {
+ TagLine(tag = "SingleLine Horizontal Scroll")
+ SingleLineHorizontalScrollableTextField()
+ }
+
+ item {
+ TagLine(tag = "SingleLine Horizontal Scroll with newlines")
+ SingleLineHorizontalScrollableTextFieldWithNewlines()
+ }
+
+ item {
+ TagLine(tag = "SingleLine Vertical Scroll")
+ SingleLineVerticalScrollableTextField()
+ }
+
+ item {
+ TagLine(tag = "MultiLine Vertical Scroll")
+ MultiLineVerticalScrollableTextField()
+ }
+
+ item {
+ TagLine(tag = "Hoisted ScrollState")
+ HoistedHorizontalScroll()
+ }
+
+ item {
+ TagLine(tag = "Shared Hoisted ScrollState")
+ SharedHoistedScroll()
+ }
+ }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun SingleLineHorizontalScrollableTextField() {
+ val state = remember {
+ TextFieldState("When content gets long,this field should scroll horizontally")
+ }
+ BasicTextField2(
+ state = state,
+ lineLimits = SingleLine,
+ textStyle = TextStyle(fontSize = 24.sp)
+ )
+}
+
+// TODO this is not supported currently. Add tests for this when supported.
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun SingleLineHorizontalScrollableTextFieldWithNewlines() {
+ val state = remember {
+ TextFieldState("This \ntext \ncontains \nnewlines \nbut \nis \nsingle-line.")
+ }
+ BasicTextField2(
+ state = state,
+ lineLimits = SingleLine,
+ textStyle = TextStyle(fontSize = 24.sp)
+ )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun SingleLineVerticalScrollableTextField() {
+ val state = remember {
+ TextFieldState(
+ buildString {
+ repeat(10) {
+ appendLine("When content gets long, this field should scroll vertically")
+ }
+ })
+ }
+ BasicTextField2(
+ state = state,
+ textStyle = TextStyle(fontSize = 24.sp),
+ lineLimits = MultiLine(maxHeightInLines = 1)
+ )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun MultiLineVerticalScrollableTextField() {
+ val state = remember {
+ TextFieldState(
+ buildString {
+ repeat(10) {
+ appendLine("When content gets long, this field should scroll vertically")
+ }
+ }
+ )
+ }
+ BasicTextField2(
+ state = state,
+ textStyle = TextStyle(fontSize = 24.sp),
+ modifier = Modifier.heightIn(max = 200.dp),
+ lineLimits = MultiLine()
+ )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun HoistedHorizontalScroll() {
+ val state = remember {
+ TextFieldState("When content gets long, this field should scroll horizontally")
+ }
+ val scrollState = rememberScrollState()
+ val coroutineScope = rememberCoroutineScope()
+ Column {
+ Slider(
+ value = scrollState.value.toFloat(),
+ onValueChange = {
+ coroutineScope.launch { scrollState.scrollTo(it.roundToInt()) }
+ },
+ valueRange = 0f..scrollState.maxValue.toFloat()
+ )
+ BasicTextField2(
+ state = state,
+ scrollState = scrollState,
+ textStyle = TextStyle(fontSize = 24.sp),
+ modifier = Modifier.height(200.dp),
+ lineLimits = SingleLine
+ )
+ }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun SharedHoistedScroll() {
+ val state1 = remember {
+ TextFieldState("When content gets long, this field should scroll horizontally")
+ }
+ val state2 = remember {
+ TextFieldState("When content gets long, this field should scroll horizontally")
+ }
+ val scrollState = rememberScrollState()
+ val coroutineScope = rememberCoroutineScope()
+ Column {
+ Slider(
+ value = scrollState.value.toFloat(),
+ onValueChange = {
+ coroutineScope.launch { scrollState.scrollTo(it.roundToInt()) }
+ },
+ valueRange = 0f..scrollState.maxValue.toFloat()
+ )
+ BasicTextField2(
+ state = state1,
+ scrollState = scrollState,
+ textStyle = TextStyle(fontSize = 24.sp),
+ modifier = Modifier.fillMaxWidth(),
+ lineLimits = SingleLine
+ )
+ BasicTextField2(
+ state = state2,
+ scrollState = scrollState,
+ textStyle = TextStyle(fontSize = 24.sp),
+ modifier = Modifier.fillMaxWidth(),
+ lineLimits = SingleLine
+ )
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/BasicTextField2Samples.kt b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/BasicTextField2Samples.kt
new file mode 100644
index 0000000..507a250
--- /dev/null
+++ b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/BasicTextField2Samples.kt
@@ -0,0 +1,327 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class, ExperimentalFoundationApi::class)
+@file:Suppress("UNUSED_PARAMETER", "unused", "LocalVariableName", "RedundantSuspendModifier")
+
+package androidx.compose.foundation.samples
+
+import androidx.annotation.Sampled
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.text2.BasicTextField2
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.delete
+import androidx.compose.foundation.text2.input.forEachChange
+import androidx.compose.foundation.text2.input.forEachChangeReversed
+import androidx.compose.foundation.text2.input.forEachTextValue
+import androidx.compose.foundation.text2.input.insert
+import androidx.compose.foundation.text2.input.rememberTextFieldState
+import androidx.compose.foundation.text2.input.selectCharsIn
+import androidx.compose.foundation.text2.input.setTextAndPlaceCursorAtEnd
+import androidx.compose.foundation.text2.input.textAsFlow
+import androidx.compose.foundation.text2.input.then
+import androidx.compose.material.Icon
+import androidx.compose.material.IconButton
+import androidx.compose.material.Text
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Clear
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.substring
+import kotlinx.coroutines.FlowPreview
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.debounce
+
+@Sampled
+fun BasicTextField2StateCompleteSample() {
+ class SearchViewModel(
+ val searchFieldState: TextFieldState = TextFieldState()
+ ) {
+ private val queryValidationRegex = """\w+""".toRegex()
+
+ // Use derived state to avoid recomposing every time the text changes, and only recompose
+ // when the input becomes valid or invalid.
+ val isQueryValid by derivedStateOf {
+ // This lambda will be re-executed every time inputState.text changes.
+ searchFieldState.text.matches(queryValidationRegex)
+ }
+
+ var searchResults: List<String> by mutableStateOf(emptyList())
+ private set
+
+ /** Called while the view model is active, e.g. from a LaunchedEffect. */
+ suspend fun run() {
+ searchFieldState.forEachTextValue { queryText ->
+ // Start a new search every time the user types something valid. If the previous
+ // search is still being processed when the text is changed, it will be cancelled
+ // and this code will run again with the latest query text.
+ if (isQueryValid) {
+ searchResults = performSearch(query = queryText)
+ }
+ }
+ }
+
+ fun clearQuery() {
+ searchFieldState.setTextAndPlaceCursorAtEnd("")
+ }
+
+ private suspend fun performSearch(query: CharSequence): List<String> {
+ TODO()
+ }
+ }
+
+ @Composable
+ fun SearchScreen(viewModel: SearchViewModel) {
+ Column {
+ Row {
+ BasicTextField2(viewModel.searchFieldState)
+ IconButton(onClick = { viewModel.clearQuery() }) {
+ Icon(Icons.Default.Clear, contentDescription = "clear search query")
+ }
+ }
+ if (!viewModel.isQueryValid) {
+ Text("Invalid query", style = TextStyle(color = Color.Red))
+ }
+ LazyColumn {
+ items(viewModel.searchResults) {
+ TODO()
+ }
+ }
+ }
+ }
+}
+
+@Sampled
+fun BasicTextField2TextDerivedStateSample() {
+ class ViewModel {
+ private val inputValidationRegex = """\w+""".toRegex()
+
+ val inputState = TextFieldState()
+
+ // Use derived state to avoid recomposing every time the text changes, and only recompose
+ // when the input becomes valid or invalid.
+ val isInputValid by derivedStateOf {
+ // This lambda will be re-executed every time inputState.text changes.
+ inputState.text.matches(inputValidationRegex)
+ }
+ }
+
+ @Composable
+ fun Screen(viewModel: ViewModel) {
+ Column {
+ BasicTextField2(viewModel.inputState)
+ if (!viewModel.isInputValid) {
+ Text("Input is invalid.", style = TextStyle(color = Color.Red))
+ }
+ }
+ }
+}
+
+@Sampled
+fun BasicTextField2StateEditSample() {
+ val state = TextFieldState("hello world!")
+ state.edit {
+ // Insert a comma after "hello".
+ insert(5, ",") // = "hello, world!"
+
+ // Delete the exclamation mark.
+ delete(12, 13) // = "hello, world"
+
+ // Add a different name.
+ append("Compose") // = "hello, Compose"
+
+ // Say goodbye.
+ replace(0, 5, "goodbye") // "goodbye, Compose"
+
+ // Select the new name so the user can change it by just starting to type.
+ selectCharsIn(TextRange(9, 16)) // "goodbye, ̲C̲o̲m̲p̲o̲s̲e"
+ }
+}
+
+@Sampled
+@Composable
+fun BasicTextField2CustomFilterSample() {
+ val state = remember { TextFieldState() }
+ BasicTextField2(state, filter = { _, new ->
+ // A filter that always places newly-input text at the start of the string, after a
+ // prompt character, like a shell.
+ val promptChar = '>'
+
+ fun CharSequence.countPrefix(char: Char): Int {
+ var i = 0
+ while (i < length && get(i) == char) i++
+ return i
+ }
+
+ // Step one: Figure out the insertion point.
+ val newPromptChars = new.countPrefix(promptChar)
+ val insertionPoint = if (newPromptChars == 0) 0 else 1
+
+ // Step two: Ensure text is placed at the insertion point.
+ if (new.changes.changeCount == 1) {
+ val insertedRange = new.changes.getRange(0)
+ val replacedRange = new.changes.getOriginalRange(0)
+ if (!replacedRange.collapsed && insertedRange.collapsed) {
+ // Text was deleted, delete forwards from insertion point.
+ new.delete(insertionPoint, insertionPoint + replacedRange.length)
+ }
+ }
+ // Else text was replaced or there were multiple changes - don't handle.
+
+ // Step three: Ensure the prompt character is there.
+ if (newPromptChars == 0) {
+ new.insert(0, ">")
+ }
+
+ // Step four: Ensure the cursor is ready for the next input.
+ new.placeCursorAfterCharAt(0)
+ })
+}
+
+@Sampled
+fun BasicTextField2FilterChainingSample() {
+ val removeFirstEFilter = TextEditFilter { _, new ->
+ val index = new.indexOf('e')
+ if (index != -1) {
+ new.replace(index, index + 1, "")
+ }
+ }
+ val printECountFilter = TextEditFilter { _, new ->
+ println("found ${new.count { it == 'e' }} 'e's in the string")
+ }
+
+ // Returns a filter that always prints 0 e's.
+ removeFirstEFilter.then(printECountFilter)
+
+ // Returns a filter that prints the number of e's before the first one is removed.
+ printECountFilter.then(removeFirstEFilter)
+}
+
+@Sampled
+@Composable
+fun BasicTextField2ChangeIterationSample() {
+ // Print a log message every time the text is changed.
+ BasicTextField2(state = rememberTextFieldState(), filter = { _, new ->
+ new.changes.forEachChange { sourceRange, replacedLength ->
+ val newString = new.substring(sourceRange)
+ println("""$replacedLength characters were replaced with "$newString"""")
+ }
+ })
+}
+
+@Sampled
+@Composable
+fun BasicTextField2ChangeReverseIterationSample() {
+ // Make a text field behave in "insert mode" – inserted text overwrites the text ahead of it
+ // instead of being inserted.
+ BasicTextField2(state = rememberTextFieldState(), filter = { _, new ->
+ new.changes.forEachChangeReversed { range, originalRange ->
+ if (!range.collapsed && originalRange.collapsed) {
+ // New text was inserted, delete the text ahead of it.
+ new.delete(
+ range.end.coerceAtMost(new.length),
+ (range.end + range.length).coerceAtMost(new.length)
+ )
+ }
+ }
+ })
+}
+
+@Sampled
+fun BasicTextField2ForEachTextValueSample() {
+ class SearchViewModel {
+ val searchFieldState = TextFieldState()
+ var searchResults: List<String> by mutableStateOf(emptyList())
+ private set
+
+ /** Called while the view model is active, e.g. from a LaunchedEffect. */
+ suspend fun run() {
+ searchFieldState.forEachTextValue { queryText ->
+ // Start a new search every time the user types something. If the previous search
+ // is still being processed when the text is changed, it will be cancelled and this
+ // code will run again with the latest query text.
+ searchResults = performSearch(query = queryText)
+ }
+ }
+
+ private suspend fun performSearch(query: CharSequence): List<String> {
+ TODO()
+ }
+ }
+
+ @Composable
+ fun SearchScreen(viewModel: SearchViewModel) {
+ Column {
+ BasicTextField2(viewModel.searchFieldState)
+ LazyColumn {
+ items(viewModel.searchResults) {
+ TODO()
+ }
+ }
+ }
+ }
+}
+
+@OptIn(FlowPreview::class)
+@Suppress("RedundantSuspendModifier")
+@Sampled
+fun BasicTextField2TextValuesSample() {
+ class SearchViewModel {
+ val searchFieldState = TextFieldState()
+ var searchResults: List<String> by mutableStateOf(emptyList())
+ private set
+
+ /** Called while the view model is active, e.g. from a LaunchedEffect. */
+ suspend fun run() {
+ searchFieldState.textAsFlow()
+ // Let fast typers get multiple keystrokes in before kicking off a search.
+ .debounce(500)
+ // collectLatest cancels the previous search if it's still running when there's a
+ // new change.
+ .collectLatest { queryText ->
+ searchResults = performSearch(query = queryText)
+ }
+ }
+
+ private suspend fun performSearch(query: CharSequence): List<String> {
+ TODO()
+ }
+ }
+
+ @Composable
+ fun SearchScreen(viewModel: SearchViewModel) {
+ Column {
+ BasicTextField2(viewModel.searchFieldState)
+ LazyColumn {
+ items(viewModel.searchResults) {
+ TODO()
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/BasicMarqueeTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/BasicMarqueeTest.kt
index ff170d3..0bf0f46 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/BasicMarqueeTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/BasicMarqueeTest.kt
@@ -1049,7 +1049,7 @@
rule.runOnIdle {
assertThat(outerDraws).isEqualTo(1)
- assertThat(innerDraws).isEqualTo(iterations + 1)
+ assertThat(innerDraws).isEqualTo(iterations)
}
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ImageTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ImageTest.kt
index 364d71f..d0bd0e5 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ImageTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ImageTest.kt
@@ -16,6 +16,7 @@
package androidx.compose.foundation
+import android.graphics.drawable.BitmapDrawable
import android.os.Build
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.heightIn
@@ -40,12 +41,14 @@
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.asAndroidBitmap
+import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.drawscope.CanvasDrawScope
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.graphics.toPixelMap
import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
@@ -69,6 +72,8 @@
import androidx.test.filters.SdkSuppress
import org.junit.Assert
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.fail
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -654,4 +659,43 @@
}
}
}
+
+ @Test
+ fun testLoadWebpImage() {
+ val testTag = "imageTag"
+ var bitmapDrawable: BitmapDrawable? = null
+ rule.setContent {
+ bitmapDrawable = LocalContext.current.getDrawable(R.drawable.webp_test)
+ as BitmapDrawable
+ Image(
+ painter = painterResource(id = R.drawable.webp_test),
+ null,
+ contentScale = ContentScale.None,
+ modifier = Modifier
+ .wrapContentSize()
+ .testTag(testTag)
+ )
+ }
+
+ rule.onNodeWithTag(testTag).captureToImage().apply {
+ val expectedDrawable = bitmapDrawable
+ if (expectedDrawable != null) {
+ val expectedBitmap = expectedDrawable.bitmap
+
+ assertNotNull(expectedBitmap)
+ assertEquals(expectedBitmap.width, width)
+ assertEquals(expectedBitmap.height, height)
+
+ val expectedPixelMap = expectedBitmap.asImageBitmap().toPixelMap()
+ val actualPixelMap = toPixelMap()
+ for (i in 0 until width) {
+ for (j in 0 until height) {
+ assertEquals(expectedPixelMap[i, j], actualPixelMap[i, j])
+ }
+ }
+ } else {
+ fail("Unable to load expected webp asset")
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
index 3fe4f04..f0f7f96 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
@@ -24,6 +24,7 @@
import androidx.compose.foundation.gestures.ScrollableState
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
@@ -40,12 +41,16 @@
import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.platform.ViewConfiguration
import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.captureToImage
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performMouseInput
import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.swipeUp
import androidx.compose.ui.test.swipeWithVelocity
+import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -749,6 +754,76 @@
assertThat(controller.lastVelocity.y).isWithin(0.01f).of(0f)
}
}
+
+ @ExperimentalFoundationApi
+ @MediumTest
+ @Test
+ fun testOverscrollCallbacks_verticalSwipeUp_shouldTriggerCallbacks() {
+ val overscrollController = OffsetOverscrollEffectCounter()
+
+ rule.setContent {
+ val scrollableState = ScrollableState { delta -> delta }
+ Box(Modifier.nestedScroll(NoOpConnection)) {
+ Box(
+ Modifier
+ .testTag(boxTag)
+ .size(300.dp)
+ .overscroll(overscrollController)
+ .scrollable(
+ state = scrollableState,
+ orientation = Orientation.Vertical,
+ overscrollEffect = overscrollController,
+ flingBehavior = ScrollableDefaults.flingBehavior()
+ )
+ )
+ }
+ }
+ rule.onNodeWithTag(boxTag).performTouchInput { swipeUp(bottom, centerY) }
+
+ rule.runOnIdle {
+ assertThat(overscrollController.applyToFlingCount).isGreaterThan(0)
+ assertThat(overscrollController.applyToScrollCount).isGreaterThan(0)
+ }
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @ExperimentalFoundationApi
+ @MediumTest
+ @Test
+ fun testOverscrollCallbacks_verticalScrollMouse_shouldNotTriggerCallbacks() {
+ val overscrollController = OffsetOverscrollEffectCounter()
+
+ rule.setContent {
+ val scrollableState = ScrollableState { delta -> delta }
+ Box(Modifier.nestedScroll(NoOpConnection)) {
+ Box(
+ Modifier
+ .testTag(boxTag)
+ .size(300.dp)
+ .overscroll(overscrollController)
+ .scrollable(
+ state = scrollableState,
+ orientation = Orientation.Vertical,
+ overscrollEffect = overscrollController,
+ flingBehavior = ScrollableDefaults.flingBehavior()
+ )
+ )
+ }
+ }
+
+ // For the mouse scroll to work, you need to
+ // - 1. place the test tag directly on the LazyColumn
+ // - 2. Call moveTo() before scroll()
+ rule.onNodeWithTag(boxTag).performMouseInput {
+ moveTo(Offset.Zero)
+ scroll(100f)
+ }
+
+ rule.runOnIdle {
+ assertThat(overscrollController.applyToFlingCount).isEqualTo(0)
+ assertThat(overscrollController.applyToScrollCount).isEqualTo(0)
+ }
+ }
}
@OptIn(ExperimentalFoundationApi::class)
@@ -809,4 +884,36 @@
preScrollVelocity += available
return Velocity.Zero
}
-}
\ No newline at end of file
+}
+
+// Custom offset overscroll that only counts the number of times each callback is triggered.
+@OptIn(ExperimentalFoundationApi::class)
+private class OffsetOverscrollEffectCounter : OverscrollEffect {
+ var applyToScrollCount: Int = 0
+ private set
+
+ var applyToFlingCount: Int = 0
+ private set
+
+ @ExperimentalFoundationApi
+ override fun applyToScroll(
+ delta: Offset,
+ source: NestedScrollSource,
+ performScroll: (Offset) -> Offset
+ ): Offset {
+ applyToScrollCount++
+ return Offset.Zero
+ }
+
+ override suspend fun applyToFling(
+ velocity: Velocity,
+ performFling: suspend (Velocity) -> Velocity
+ ) {
+ applyToFlingCount++
+ }
+
+ override val isInProgress: Boolean = false
+ override val effectModifier: Modifier = Modifier.offset {
+ IntOffset(x = 0, y = 0)
+ }
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
index 4f41bb7..234a4c5 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
@@ -108,6 +108,7 @@
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import kotlin.math.abs
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
@@ -803,17 +804,19 @@
@OptIn(ExperimentalTestApi::class)
@Test
- fun scrollable_nestedScroll_disabledForMouseWheel() {
+ fun scrollable_nestedScroll_childPartialConsumptionForMouseWheel() {
var innerDrag = 0f
var outerDrag = 0f
val outerState = ScrollableState(
consumeScrollDelta = {
+ // Since the child has already consumed half, the parent will consume the rest.
outerDrag += it
it
}
)
val innerState = ScrollableState(
consumeScrollDelta = {
+ // Child consumes half, leaving the rest for the parent to consume.
innerDrag += it / 2
it / 2
}
@@ -847,7 +850,10 @@
}
rule.runOnIdle {
assertThat(innerDrag).isGreaterThan(0f)
- assertThat(outerDrag).isZero()
+ assertThat(outerDrag).isGreaterThan(0f)
+ // Since child (inner) consumes half of the scroll, the parent (outer) consumes the
+ // remainder (which is half as well), so they will be equal.
+ assertThat(innerDrag).isEqualTo(outerDrag)
innerDrag
}
}
@@ -1317,6 +1323,61 @@
}
@Test
+ fun scrollable_nestedFlingCancellation_shouldPreventDeltasFromPropagating() {
+ var childDeltas = 0f
+ var touchSlop = 0f
+ val childController = ScrollableState {
+ childDeltas += it
+ it
+ }
+ val flingCancellationParent = object : NestedScrollConnection {
+ override fun onPostScroll(
+ consumed: Offset,
+ available: Offset,
+ source: NestedScrollSource
+ ): Offset {
+ if (source == NestedScrollSource.Fling && available != Offset.Zero) {
+ throw CancellationException()
+ }
+ return Offset.Zero
+ }
+ }
+
+ rule.setContent {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ Box(modifier = Modifier.nestedScroll(flingCancellationParent)) {
+ Box(
+ modifier = Modifier
+ .size(600.dp)
+ .testTag("childScrollable")
+ .scrollable(childController, Orientation.Horizontal)
+ )
+ }
+ }
+
+ // First drag, this won't trigger the cancellation flow.
+ rule.onNodeWithTag("childScrollable").performTouchInput {
+ down(centerLeft)
+ moveBy(Offset(100f, 0f))
+ up()
+ }
+
+ rule.runOnIdle {
+ assertThat(childDeltas).isEqualTo(100f - touchSlop)
+ }
+
+ childDeltas = 0f
+ var dragged = 0f
+ rule.onNodeWithTag("childScrollable").performTouchInput {
+ swipeWithVelocity(centerLeft, centerRight, 2000f)
+ dragged = centerRight.x - centerLeft.x
+ }
+
+ // child didn't receive more deltas after drag, because fling was cancelled by the parent
+ assertThat(childDeltas).isEqualTo(dragged - touchSlop)
+ }
+
+ @Test
fun scrollable_bothOrientations_proxiesPostFling() {
val velocityFlung = 5000f
val outerState = ScrollableState(consumeScrollDelta = { 0f })
@@ -2176,6 +2237,7 @@
"reverseDirection",
"flingBehavior",
"interactionSource",
+ "scrollableBringIntoViewConfig",
)
}
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridBeyondBoundsTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridBeyondBoundsTest.kt
index f0315ad..107ee85 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridBeyondBoundsTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridBeyondBoundsTest.kt
@@ -18,6 +18,7 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.list.TrackPlacedElement
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -32,7 +33,6 @@
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Left
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Right
import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout
-import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.modifier.modifierLocalConsumer
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.test.junit4.ComposeContentTestRule
@@ -97,7 +97,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -117,7 +117,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -137,7 +137,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -191,13 +191,13 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(Modifier
.size(10.toDp())
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -207,11 +207,10 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
@@ -224,7 +223,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Just return true so that we stop as soon as we run this once.
// This should result in one extra item being added.
true
@@ -251,13 +249,13 @@
Box(
Modifier
.size(itemSizeDp)
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(Modifier
.size(itemSizeDp)
- .onPlaced { placedItems += 11 }
+ .trackPlaced(11)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -267,11 +265,10 @@
Box(
Modifier
.size(itemSizeDp)
- .onPlaced { placedItems += index + 12 }
+ .trackPlaced(index + 12)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
@@ -284,7 +281,6 @@
assertThat(placedItems).containsExactly(10, 11, 12, 13, 14, 15, 16)
assertThat(visibleItems).containsExactly(10, 11, 12, 13, 14, 15)
}
- placedItems.clear()
// Just return true so that we stop as soon as we run this once.
// This should result in one extra item being added.
true
@@ -307,14 +303,14 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -324,17 +320,15 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
if (--extraItemCount > 0) {
- placedItems.clear()
// Return null to continue the search.
null
} else {
@@ -346,7 +340,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8, 9)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Return true to stop the search.
true
}
@@ -368,7 +361,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
@@ -378,26 +371,22 @@
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
)
}
items(5) { index ->
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index + 6
- }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
if (hasMoreContent) {
- placedItems.clear()
// Just return null so that we keep adding more items till we reach the end.
null
} else {
@@ -409,7 +398,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8, 9, 10)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Return true to end the search.
true
}
@@ -431,14 +419,14 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -448,14 +436,13 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
rule.runOnIdle {
assertThat(placedItems).containsExactly(5, 6, 7)
assertThat(visibleItems).containsExactly(5, 6, 7)
- placedItems.clear()
}
// Act.
@@ -477,7 +464,6 @@
}
}
}
- placedItems.clear()
// Just return true so that we stop as soon as we run this once.
// This should result in one extra item being added.
true
@@ -509,9 +495,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index
- }
+ .trackPlaced(index)
)
}
item {
@@ -521,20 +505,17 @@
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
)
}
items(5) { index ->
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index + 6
- }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
var count = 0
@@ -542,7 +523,6 @@
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
// Assert that we don't keep iterating when there is no ending condition.
assertThat(count++).isLessThan(lazyGridState.layoutInfo.totalItemsCount)
- placedItems.clear()
// Always return null to continue the search.
null
}
@@ -636,4 +616,7 @@
private fun unsupportedDirection(): Nothing = error(
"Lazy list does not support beyond bounds layout for the specified direction"
)
+
+ private fun Modifier.trackPlaced(index: Int): Modifier =
+ this then TrackPlacedElement(placedItems, index)
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListBeyondBoundsAndExtraItemsTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListBeyondBoundsAndExtraItemsTest.kt
index 559f3bb..3be7e19 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListBeyondBoundsAndExtraItemsTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListBeyondBoundsAndExtraItemsTest.kt
@@ -31,7 +31,6 @@
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Left
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Right
import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout
-import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.modifier.modifierLocalConsumer
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.LayoutDirection
@@ -51,12 +50,12 @@
private val beyondBoundsLayoutDirection = config.beyondBoundsLayoutDirection
private val reverseLayout = config.reverseLayout
private val layoutDirection = config.layoutDirection
+ private val placedItems = mutableSetOf<Int>()
@OptIn(ExperimentalComposeUiApi::class)
@Test
fun verifyItemsArePlacedBeforeBeyondBoundsItems_oneBeyondBoundItem() {
// Arrange
- val placedItems = mutableSetOf<Int>()
var beyondBoundsLayout: BeyondBoundsLayout? = null
val lazyListState = LazyListState()
rule.setContent {
@@ -71,14 +70,14 @@
Box(
Modifier
.size(10.dp)
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(
Modifier
.size(10.dp)
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -88,14 +87,13 @@
Box(
Modifier
.size(10.dp)
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
}
}
rule.runOnIdle { runBlocking { lazyListState.scrollToItem(5) } }
- rule.runOnIdle { placedItems.clear() }
// Act
rule.runOnUiThread {
@@ -107,7 +105,6 @@
assertThat(placedItems).containsAtLeast(4, 5, 6, 7, 8, 9)
}
assertThat(lazyListState.visibleItems).containsAtLeast(5, 6, 7)
- placedItems.clear()
true
}
}
@@ -123,7 +120,6 @@
@Test
fun verifyItemsArePlacedBeforeBeyondBoundsItems_twoBeyondBoundItem() {
// Arrange
- val placedItems = mutableSetOf<Int>()
var beyondBoundsLayout: BeyondBoundsLayout? = null
val lazyListState = LazyListState()
var extraItemCount = 2
@@ -139,14 +135,14 @@
Box(
Modifier
.size(10.dp)
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(
Modifier
.size(10.dp)
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -156,20 +152,18 @@
Box(
Modifier
.size(10.dp)
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
}
}
rule.runOnIdle { runBlocking { lazyListState.scrollToItem(5) } }
- rule.runOnIdle { placedItems.clear() }
// Act
rule.runOnUiThread {
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
if (--extraItemCount > 0) {
- placedItems.clear()
// Return null to continue the search.
null
} else {
@@ -180,7 +174,6 @@
assertThat(placedItems).containsAtLeast(4, 5, 6, 7, 8, 9, 10)
}
assertThat(lazyListState.visibleItems).containsAtLeast(5, 6, 7)
- placedItems.clear()
true
}
}
@@ -249,4 +242,7 @@
Before -> true
else -> error("Unsupported BeyondBoundsDirection")
}
+
+ private fun Modifier.trackPlaced(index: Int): Modifier =
+ this then TrackPlacedElement(placedItems, index)
}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListBeyondBoundsTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListBeyondBoundsTest.kt
index d431ea4..4e0a1ed 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListBeyondBoundsTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListBeyondBoundsTest.kt
@@ -36,9 +36,12 @@
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Below
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Left
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Right
+import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout
-import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.modifier.modifierLocalConsumer
+import androidx.compose.ui.node.LayoutAwareModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
@@ -102,7 +105,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -122,7 +125,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -142,7 +145,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -196,13 +199,13 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(Modifier
.size(10.toDp())
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -212,11 +215,10 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
@@ -229,7 +231,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Just return true so that we stop as soon as we run this once.
// This should result in one extra item being added.
true
@@ -252,14 +253,14 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -269,17 +270,15 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
if (--extraItemCount > 0) {
- placedItems.clear()
// Return null to continue the search.
null
} else {
@@ -291,7 +290,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8, 9)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Return true to stop the search.
true
}
@@ -313,7 +311,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
@@ -323,26 +321,22 @@
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
)
}
items(5) { index ->
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index + 6
- }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
if (hasMoreContent) {
- placedItems.clear()
// Just return null so that we keep adding more items till we reach the end.
null
} else {
@@ -354,7 +348,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8, 9, 10)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Return true to end the search.
true
}
@@ -376,14 +369,14 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -393,14 +386,13 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
rule.runOnIdle {
assertThat(placedItems).containsExactly(5, 6, 7)
assertThat(visibleItems).containsExactly(5, 6, 7)
- placedItems.clear()
}
// Act.
@@ -422,7 +414,6 @@
}
}
}
- placedItems.clear()
// Just return true so that we stop as soon as we run this once.
// This should result in one extra item being added.
true
@@ -454,9 +445,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index
- }
+ .trackPlaced(index)
)
}
item {
@@ -466,20 +455,17 @@
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
)
}
items(5) { index ->
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index + 6
- }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
var count = 0
@@ -487,7 +473,6 @@
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
// Assert that we don't keep iterating when there is no ending condition.
assertThat(count++).isLessThan(lazyListState.layoutInfo.totalItemsCount)
- placedItems.clear()
// Always return null to continue the search.
null
}
@@ -576,4 +561,37 @@
private fun unsupportedDirection(): Nothing = error(
"Lazy list does not support beyond bounds layout for the specified direction"
)
+
+ private fun Modifier.trackPlaced(index: Int): Modifier =
+ this then TrackPlacedElement(placedItems, index)
+}
+
+internal data class TrackPlacedElement(
+ var placedItems: MutableSet<Int>,
+ var index: Int
+) : ModifierNodeElement<TrackPlacedNode>() {
+ override fun create() = TrackPlacedNode(placedItems, index)
+
+ override fun update(node: TrackPlacedNode) {
+ node.placedItems = placedItems
+ node.index = index
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
+ name = "trackPlaced"
+ properties["index"] = index
+ }
+}
+
+internal class TrackPlacedNode(
+ var placedItems: MutableSet<Int>,
+ var index: Int
+) : LayoutAwareModifierNode, Modifier.Node() {
+ override fun onPlaced(coordinates: LayoutCoordinates) {
+ placedItems += index
+ }
+
+ override fun onDetach() {
+ placedItems -= index
+ }
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridAnimateItemPlacementTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridAnimateItemPlacementTest.kt
index 41f1c73f..202b94e 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridAnimateItemPlacementTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridAnimateItemPlacementTest.kt
@@ -2060,6 +2060,35 @@
}
}
+ @Test
+ fun columnCountChange() {
+ var columnCount by mutableStateOf(2)
+ val containerCrossAxisSize = itemSizeDp * 2
+ rule.setContent {
+ LazyStaggeredGrid(
+ cells = columnCount,
+ maxSize = itemSizeDp,
+ crossAxisSize = containerCrossAxisSize
+ ) {
+ items(10, key = { it }) {
+ Item(it)
+ }
+ }
+ }
+
+ rule.runOnUiThread {
+ columnCount = 1
+ }
+
+ onAnimationFrame { _ ->
+ // todo: proper animations when removal is supported
+ assertPositions(
+ 0 to AxisOffset(0f, 0f),
+ 1 to AxisOffset(itemSize, 0f)
+ )
+ }
+ }
+
private fun AxisOffset(crossAxis: Float, mainAxis: Float) =
if (isVertical) Offset(crossAxis, mainAxis) else Offset(mainAxis, crossAxis)
@@ -2160,6 +2189,7 @@
startPadding: Dp = 0.dp,
endPadding: Dp = 0.dp,
spacing: Dp = 0.dp,
+ crossAxisSize: Dp? = null,
content: LazyStaggeredGridScope.() -> Unit
) {
state = rememberLazyStaggeredGridState(startIndex)
@@ -2168,7 +2198,7 @@
StaggeredGridCells.Fixed(cells),
Modifier
.requiredHeightIn(minSize, maxSize)
- .requiredWidth(itemSizeDp * cells)
+ .requiredWidth(crossAxisSize ?: (itemSizeDp * cells))
.testTag(ContainerTag),
state = state,
verticalItemSpacing = spacing,
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridBeyondBoundsTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridBeyondBoundsTest.kt
index 1b82ba8..116e9ae 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridBeyondBoundsTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridBeyondBoundsTest.kt
@@ -18,6 +18,7 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.list.TrackPlacedElement
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -32,7 +33,6 @@
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Left
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Right
import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout
-import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.modifier.modifierLocalConsumer
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.test.junit4.ComposeContentTestRule
@@ -97,7 +97,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -117,7 +117,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -137,7 +137,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -191,13 +191,13 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(Modifier
.size(10.toDp())
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -207,11 +207,10 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
@@ -224,7 +223,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Just return true so that we stop as soon as we run this once.
// This should result in one extra item being added.
true
@@ -251,13 +249,13 @@
Box(
Modifier
.size(itemSizeDp)
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(Modifier
.size(itemSizeDp)
- .onPlaced { placedItems += 11 }
+ .trackPlaced(11)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -267,11 +265,10 @@
Box(
Modifier
.size(itemSizeDp)
- .onPlaced { placedItems += index + 12 }
+ .trackPlaced(index + 12)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
@@ -284,7 +281,6 @@
assertThat(placedItems).containsExactly(10, 11, 12, 13, 14, 15, 16)
assertThat(visibleItems).containsExactly(10, 11, 12, 13, 14, 15)
}
- placedItems.clear()
// Just return true so that we stop as soon as we run this once.
// This should result in one extra item being added.
true
@@ -319,13 +315,13 @@
Box(
Modifier
.size(itemSizeDp * if (index % 2 == 0) 2f else 1f)
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item(span = StaggeredGridItemSpan.FullLine) {
Box(Modifier
.size(itemSizeDp)
- .onPlaced { placedItems += 4 }
+ .trackPlaced(4)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -335,11 +331,10 @@
Box(
Modifier
.size(itemSizeDp * if (index % 2 == 0) 2f else 1f)
- .onPlaced { placedItems += index + 5 }
+ .trackPlaced(index + 5)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
@@ -352,7 +347,6 @@
assertThat(placedItems).containsExactly(4, 5, 6, 7, 8)
assertThat(visibleItems).containsExactly(4, 5, 6, 7)
}
- placedItems.clear()
// Just return true so that we stop as soon as we run this once.
// This should result in one extra item being added.
true
@@ -375,14 +369,14 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -392,17 +386,15 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
if (--extraItemCount > 0) {
- placedItems.clear()
// Return null to continue the search.
null
} else {
@@ -414,7 +406,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8, 9)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Return true to stop the search.
true
}
@@ -436,7 +427,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
@@ -446,26 +437,22 @@
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
)
}
items(5) { index ->
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index + 6
- }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
if (hasMoreContent) {
- placedItems.clear()
// Just return null so that we keep adding more items till we reach the end.
null
} else {
@@ -477,7 +464,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8, 9, 10)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Return true to end the search.
true
}
@@ -499,14 +485,14 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -516,14 +502,13 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
rule.runOnIdle {
assertThat(placedItems).containsExactly(5, 6, 7)
assertThat(visibleItems).containsExactly(5, 6, 7)
- placedItems.clear()
}
// Act.
@@ -545,7 +530,6 @@
}
}
}
- placedItems.clear()
// Just return true so that we stop as soon as we run this once.
// This should result in one extra item being added.
true
@@ -577,9 +561,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index
- }
+ .trackPlaced(index)
)
}
item {
@@ -589,20 +571,17 @@
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
)
}
items(5) { index ->
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index + 6
- }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
var count = 0
@@ -610,7 +589,6 @@
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
// Assert that we don't keep iterating when there is no ending condition.
assertThat(count++).isLessThan(lazyStaggeredGridState.layoutInfo.totalItemsCount)
- placedItems.clear()
// Always return null to continue the search.
null
}
@@ -704,4 +682,7 @@
private fun unsupportedDirection(): Nothing = error(
"Lazy list does not support beyond bounds layout for the specified direction"
)
+
+ private fun Modifier.trackPlaced(index: Int): Modifier =
+ this then TrackPlacedElement(placedItems, index)
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/pager/PagerNestedScrollContentTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/pager/PagerNestedScrollContentTest.kt
index 78b2758..23b0547 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/pager/PagerNestedScrollContentTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/pager/PagerNestedScrollContentTest.kt
@@ -16,26 +16,44 @@
package androidx.compose.foundation.pager
+import androidx.compose.animation.splineBasedDecay
import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.gestures.DefaultFlingBehavior
+import androidx.compose.foundation.gestures.FlingBehavior
+import androidx.compose.foundation.gestures.ScrollScope
import androidx.compose.foundation.gestures.ScrollableDefaults
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyList
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.BasicText
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusDirection
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.focus.onFocusChanged
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
import androidx.test.filters.LargeTest
import com.google.common.truth.Truth.assertThat
+import kotlin.math.abs
import kotlin.math.absoluteValue
+import kotlin.test.assertTrue
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Test
@@ -89,6 +107,58 @@
@OptIn(ExperimentalFoundationApi::class)
@Test
+ fun nestedScrollContent_shouldCancelFlingIfOnEdge() {
+ // Arrange
+ rule.mainClock.autoAdvance = false
+ val defaultFlingBehavior = DefaultFlingBehavior(splineBasedDecay(rule.density))
+ var flingTriggered = false
+ val flingInspector = object : FlingBehavior {
+ override suspend fun ScrollScope.performFling(initialVelocity: Float): Float {
+ flingTriggered = true
+ return with(defaultFlingBehavior) {
+ performFling(initialVelocity)
+ }
+ }
+ }
+ createPager(pageCount = { DefaultPageCount }) {
+ LazyList(
+ modifier = Modifier.fillMaxSize(),
+ contentPadding = PaddingValues(0.dp),
+ isVertical = vertical, // scrollable content on the same direction as pager
+ reverseLayout = false,
+ flingBehavior = flingInspector,
+ state = rememberLazyListState(initialFirstVisibleItemIndex = 8),
+ userScrollEnabled = true,
+ verticalArrangement = Arrangement.Top,
+ horizontalArrangement = Arrangement.Start,
+ verticalAlignment = Alignment.Top,
+ horizontalAlignment = Alignment.Start
+ ) {
+ items(10) {
+ Box(modifier = Modifier.size(100.dp)) {
+ BasicText(text = it.toString())
+ }
+ }
+ }
+ }
+
+ // Act: High velocity swipe should fling inner list to edge
+ val forwardDelta = pagerSize * 0.5f * scrollForwardSign.toFloat()
+ rule.onNodeWithTag(TestTag).performTouchInput {
+ swipeWithVelocityAcrossMainAxis(10000f, forwardDelta)
+ }
+
+ rule.mainClock.advanceTimeUntil { flingTriggered } // wait for drag to finish
+
+ val previousOffset = pagerState.currentPageOffsetFraction
+ rule.mainClock.advanceTimeBy(1_000L) // advance time
+
+ // should've moved by then.
+ assertThat(pagerState.currentPageOffsetFraction).isNotEqualTo(previousOffset)
+ }
+
+ @OptIn(ExperimentalFoundationApi::class)
+ @Test
fun nestedScrollContent_shouldPropagateCrossAxisUnconsumedFlings() {
// Arrange
var postFlingVelocity = Velocity.Zero
@@ -194,6 +264,175 @@
assertThat(pagerState.currentPageOffsetFraction).isEqualTo(0f)
}
+ @OptIn(ExperimentalFoundationApi::class)
+ @Test
+ fun nestedScrollContent_shouldEnsurePagerIsSettled_WhenDirectionChanges() {
+ // Arrange
+ val lazyListState = LazyListState(9)
+ var touchSlop = 0f
+ createPager(pageCount = { DefaultPageCount }) {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ LazyList(
+ modifier = Modifier.fillMaxSize(),
+ contentPadding = PaddingValues(0.dp),
+ flingBehavior = ScrollableDefaults.flingBehavior(),
+ isVertical = vertical, // scrollable content on the same direction as pager
+ reverseLayout = false,
+ state = lazyListState,
+ userScrollEnabled = true,
+ verticalArrangement = Arrangement.Top,
+ horizontalArrangement = Arrangement.Start,
+ verticalAlignment = Alignment.Top,
+ horizontalAlignment = Alignment.Start
+ ) {
+ items(10) {
+ Box(modifier = Modifier.size(100.dp)) {
+ BasicText(text = it.toString())
+ }
+ }
+ }
+ }
+
+ val forwardDelta = pagerSize * 0.4f * scrollForwardSign.toFloat()
+ val firstLazyListItem = lazyListState.firstVisibleItemIndex
+ val firstLazyListItemOffset = lazyListState.firstVisibleItemScrollOffset
+ rule.onNodeWithTag(TestTag).performTouchInput {
+ down(center)
+ val toMove = forwardDelta + touchSlop * scrollForwardSign.toFloat()
+ moveBy(if (vertical) Offset(x = 0f, y = toMove) else Offset(x = toMove, y = 0f))
+ }
+
+ // Assert: Inner list won't consume scroll and pager moved
+ assertThat(abs(pagerState.currentPageOffsetFraction - 0.4f)).isLessThan(0.001f)
+ assertThat(lazyListState.firstVisibleItemScrollOffset).isEqualTo(firstLazyListItemOffset)
+ assertThat(lazyListState.firstVisibleItemIndex).isEqualTo(firstLazyListItem)
+
+ rule.onNodeWithTag(TestTag).performTouchInput {
+ moveBy(
+ if (vertical) Offset(x = 0f, y = -forwardDelta / 2)
+ else Offset(x = -forwardDelta / 2, y = 0f)
+ )
+ }
+
+ // assert: pager moved, but list is still at 0 after direction change
+ assertThat(abs(pagerState.currentPageOffsetFraction - 0.2f)).isLessThan(0.001f)
+ assertThat(lazyListState.firstVisibleItemScrollOffset).isEqualTo(firstLazyListItemOffset)
+ assertThat(lazyListState.firstVisibleItemIndex).isEqualTo(firstLazyListItem)
+
+ rule.onNodeWithTag(TestTag).performTouchInput {
+ up()
+ }
+ }
+
+ @Test
+ fun nestedScrollContent_focusShouldMoveAndSnapPages() {
+ // Arrange
+ lateinit var innerListFocusRequester: FocusRequester
+ lateinit var pagerFocusRequester: FocusRequester
+ val focusItems = mutableSetOf<String>()
+ val rowColumnContent: @Composable (Int) -> Unit = { page ->
+ repeat(DefaultPageCount) { item ->
+ val columnFocusRequester = FocusRequester().apply {
+ if (item == 3 && page == 5) innerListFocusRequester = this
+ }
+ Box(
+ modifier = Modifier
+ .focusRequester(columnFocusRequester)
+ .onFocusChanged {
+ if (it.isFocused) {
+ focusItems.add("page=$page-item=$item")
+ }
+ }
+ .size(150.dp)
+ .focusable(),
+ contentAlignment = Alignment.Center
+ ) {
+ BasicText(text = "page=$page-item=$item")
+ }
+ }
+ }
+ createPager(
+ modifier = Modifier.fillMaxSize(),
+ pageCount = { DefaultPageCount },
+ initialPage = 3,
+ pageSize = { PageSize.Fixed(100.dp) }) { page ->
+ val focusRequester = FocusRequester().apply {
+ if (page == 5) pagerFocusRequester = this
+ }
+ val rowColumnModifier =
+ Modifier
+ .focusRequester(focusRequester)
+ .verticalScroll(rememberScrollState())
+
+ if (vertical) {
+ Row(
+ modifier = rowColumnModifier
+ ) {
+ rowColumnContent(page)
+ }
+ } else {
+ Column(
+ modifier = rowColumnModifier
+ ) {
+ rowColumnContent(page)
+ }
+ }
+ }
+
+ // Act: Request first page to focus.
+ rule.runOnIdle { pagerFocusRequester.requestFocus() }
+
+ // Assert: Check we're settled.
+ rule.runOnIdle {
+ assertThat(pagerState.currentPage).isEqualTo(5)
+ assertThat(pagerState.currentPageOffsetFraction).isEqualTo(0.0f)
+ }
+
+ // Act: Focus scroll inner scrollable
+ rule.runOnIdle { innerListFocusRequester.requestFocus() }
+
+ // Assert: Check we actually scrolled.
+ rule.runOnIdle { assertThat(focusItems).contains("page=5-item=3") }
+
+ // Act: Move focus in inner scrollable
+ rule.runOnIdle {
+ assertTrue {
+ if (vertical) {
+ focusManager.moveFocus(FocusDirection.Next)
+ } else {
+ focusManager.moveFocus(FocusDirection.Down)
+ }
+ }
+ }
+
+ // Assert: Check we actually scrolled, but didn't move pages.
+ rule.runOnIdle {
+ assertThat(focusItems).contains("page=5-item=4")
+ assertThat(pagerState.currentPage).isEqualTo(5)
+ assertThat(pagerState.currentPageOffsetFraction).isEqualTo(0.0f)
+ }
+
+ // Act: Reset.
+ rule.runOnIdle { pagerFocusRequester.requestFocus() }
+
+ // Act: Move focus in pager.
+ rule.runOnIdle {
+ assertTrue {
+ if (vertical) {
+ focusManager.moveFocus(FocusDirection.Down)
+ } else {
+ focusManager.moveFocus(FocusDirection.Right)
+ }
+ }
+ }
+
+ // Assert: Check we moved pages.
+ rule.runOnIdle {
+ assertThat(pagerState.currentPage).isEqualTo(6)
+ assertThat(pagerState.currentPageOffsetFraction).isEqualTo(0.0f)
+ }
+ }
+
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{0}")
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewScrollableInteractionTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewScrollableInteractionTest.kt
index 3744d3a..e690ab0 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewScrollableInteractionTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewScrollableInteractionTest.kt
@@ -16,12 +16,17 @@
package androidx.compose.foundation.relocation
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.spring
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.ScrollState
+import androidx.compose.foundation.ScrollingLayoutElement
import androidx.compose.foundation.background
+import androidx.compose.foundation.gestures.BringIntoViewScroller
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.Orientation.Horizontal
import androidx.compose.foundation.gestures.Orientation.Vertical
+import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -33,6 +38,7 @@
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
@@ -47,6 +53,7 @@
import androidx.compose.ui.graphics.Color.Companion.Red
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.onPlaced
+import androidx.compose.ui.layout.positionInParent
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
@@ -56,6 +63,7 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpRect
import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toSize
import androidx.test.filters.LargeTest
import com.google.common.truth.Truth.assertThat
@@ -183,6 +191,7 @@
Modifier
.size(100.toDp(), 50.toDp())
.horizontalScroll(rememberScrollState())
+
Vertical ->
Modifier
.size(50.toDp(), 100.toDp())
@@ -224,6 +233,7 @@
Modifier
.size(100.toDp(), 50.toDp())
.horizontalScroll(rememberScrollState())
+
Vertical ->
Modifier
.size(50.toDp(), 100.toDp())
@@ -271,6 +281,7 @@
Modifier
.size(100.toDp(), 50.toDp())
.horizontalScroll(rememberScrollState())
+
Vertical ->
Modifier
.size(50.toDp(), 100.toDp())
@@ -482,6 +493,7 @@
Modifier
.size(100.toDp(), 50.toDp())
.horizontalScroll(scrollState)
+
Vertical ->
Modifier
.size(50.toDp(), 100.toDp())
@@ -538,6 +550,7 @@
Modifier
.size(100.toDp(), 50.toDp())
.horizontalScroll(scrollState)
+
Vertical ->
Modifier
.size(50.toDp(), 100.toDp())
@@ -597,6 +610,7 @@
Modifier
.size(100.toDp(), 50.toDp())
.horizontalScroll(scrollState)
+
Vertical ->
Modifier
.size(50.toDp(), 100.toDp())
@@ -648,6 +662,7 @@
Modifier
.size(100.toDp(), 50.toDp())
.horizontalScroll(scrollState)
+
Vertical ->
Modifier
.size(50.toDp(), 100.toDp())
@@ -709,6 +724,7 @@
Modifier
.size(100.toDp(), 50.toDp())
.horizontalScroll(grandParentScrollState)
+
Vertical ->
Modifier
.size(50.toDp(), 100.toDp())
@@ -725,6 +741,7 @@
Modifier
.size(200.toDp(), 50.toDp())
.horizontalScroll(parentScrollState)
+
Vertical ->
Modifier
.size(50.toDp(), 200.toDp())
@@ -785,6 +802,7 @@
Modifier
.size(100.toDp(), 50.toDp())
.verticalScroll(grandParentScrollState)
+
Vertical ->
Modifier
.size(50.toDp(), 100.toDp())
@@ -1075,6 +1093,216 @@
).inOrder()
}
+ @Test
+ fun bringIntoViewScroller_childIsAtTopOfParent_shouldReturnCorrectValues() {
+ val bringIntoViewRequester = BringIntoViewRequester()
+ val bringIntoViewItemCoordinates = mutableStateOf<LayoutCoordinates?>(null)
+
+ bringIntoViewScrollerTest_wrapper(
+ requester = bringIntoViewRequester,
+ childCoordinates = bringIntoViewItemCoordinates,
+ expectedChildSize = 10.dp // child is visible
+ ) {
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .onPlaced { bringIntoViewItemCoordinates.value = it }
+ .bringIntoViewRequester(bringIntoViewRequester)
+ )
+ Box(
+ modifier = Modifier
+ .size(100.dp)
+ )
+ }
+ }
+
+ @Test
+ fun bringIntoViewScroller_childIsInTheMiddleOfParent_shouldReturnCorrectValues() {
+ val bringIntoViewRequester = BringIntoViewRequester()
+ val bringIntoViewItemCoordinates = mutableStateOf<LayoutCoordinates?>(null)
+
+ bringIntoViewScrollerTest_wrapper(
+ requester = bringIntoViewRequester,
+ childCoordinates = bringIntoViewItemCoordinates,
+ expectedChildSize = 10.dp // child is visible
+ ) {
+ Box(
+ modifier = Modifier
+ .size(100.dp)
+ )
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .onPlaced { bringIntoViewItemCoordinates.value = it }
+ .bringIntoViewRequester(bringIntoViewRequester)
+ )
+ Box(
+ modifier = Modifier
+ .size(100.dp)
+ )
+ }
+ }
+
+ @Test
+ fun bringIntoViewScroller_childIsPartOutOfBoundsOfParent_shouldReturnCorrectValues() {
+ val bringIntoViewRequester = BringIntoViewRequester()
+ val bringIntoViewItemCoordinates = mutableStateOf<LayoutCoordinates?>(null)
+
+ bringIntoViewScrollerTest_wrapper(
+ requester = bringIntoViewRequester,
+ childCoordinates = bringIntoViewItemCoordinates,
+ expectedChildSize = 10.dp // child is part visible
+ ) {
+ Box(
+ modifier = Modifier
+ .size(195.dp)
+ )
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .onPlaced { bringIntoViewItemCoordinates.value = it }
+ .bringIntoViewRequester(bringIntoViewRequester)
+ )
+ }
+ }
+
+ @Test
+ fun bringIntoViewScroller_childIsOutOfBoundsOfParent_shouldReturnCorrectValues() {
+ val bringIntoViewRequester = BringIntoViewRequester()
+ val bringIntoViewItemCoordinates = mutableStateOf<LayoutCoordinates?>(null)
+
+ bringIntoViewScrollerTest_wrapper(
+ requester = bringIntoViewRequester,
+ childCoordinates = bringIntoViewItemCoordinates,
+ expectedChildSize = 10.dp // child is not visible
+ ) {
+ Box(
+ modifier = Modifier
+ .size(205.dp)
+ )
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .onPlaced { bringIntoViewItemCoordinates.value = it }
+ .bringIntoViewRequester(bringIntoViewRequester)
+ )
+ }
+ }
+
+ private fun bringIntoViewScrollerTest_wrapper(
+ requester: BringIntoViewRequester,
+ expectedChildSize: Dp,
+ childCoordinates: State<LayoutCoordinates?>,
+ content: @Composable () -> Unit
+ ) {
+
+ val containerSize = 200.dp
+
+ fun calculateExpectedChildOffset(): Int {
+ return if (orientation == Horizontal) {
+ childCoordinates.value?.positionInParent()?.x
+ } else {
+ childCoordinates.value?.positionInParent()?.y
+ }?.toInt() ?: 0
+ }
+
+ val expectedContainerSize = with(rule.density) { containerSize.roundToPx() }
+ val customBringIntoViewScroller = object : BringIntoViewScroller {
+ override val scrollAnimationSpec: AnimationSpec<Float> = spring()
+
+ override fun calculateScrollDistance(
+ offset: Float,
+ size: Float,
+ containerSize: Float
+ ): Float {
+ assertThat(containerSize).isEqualTo(expectedContainerSize)
+ assertThat(size).isEqualTo(with(rule.density) { expectedChildSize.roundToPx() })
+ assertThat(offset).isEqualTo(calculateExpectedChildOffset())
+ return 0f
+ }
+ }
+
+ rule.setContent {
+ testScope = rememberCoroutineScope()
+ val state = rememberScrollState()
+ RowOrColumn(
+ modifier = Modifier
+ .size(containerSize)
+ .scrollable(
+ state = state,
+ overscrollEffect = null,
+ orientation = orientation,
+ bringIntoViewScroller = customBringIntoViewScroller
+ )
+ .then(ScrollingLayoutElement(state, false, orientation == Vertical))
+ ) {
+ content()
+ }
+ }
+
+ testScope.launch {
+ requester.bringIntoView()
+ }
+
+ rule.waitForIdle()
+ }
+
+ @Test
+ fun bringIntoViewScroller_shouldStopScrollingWhenReceivingZero() {
+ val bringIntoViewRequests = listOf(300f, 150f, 0f)
+ val scrollState = ScrollState(0)
+ var requestsFulfilledScroll = 0
+ val customBringIntoViewScroller = object : BringIntoViewScroller {
+ var index = 0
+
+ override val scrollAnimationSpec: AnimationSpec<Float> = spring()
+
+ override fun calculateScrollDistance(
+ offset: Float,
+ size: Float,
+ containerSize: Float
+ ): Float {
+ return bringIntoViewRequests[index].also {
+ index = (index + 1)
+ if (index > 2) {
+ requestsFulfilledScroll = scrollState.value
+ index = 2
+ }
+ }
+ }
+ }
+
+ val requester = BringIntoViewRequester()
+
+ rule.setContent {
+ testScope = rememberCoroutineScope()
+ Box(
+ modifier = Modifier
+ .size(200.dp)
+ .scrollable(
+ state = scrollState,
+ overscrollEffect = null,
+ orientation = orientation,
+ bringIntoViewScroller = customBringIntoViewScroller
+ )
+ ) {
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .bringIntoViewRequester(requester)
+ )
+ }
+ }
+
+ testScope.launch {
+ requester.bringIntoView()
+ }
+
+ rule.waitForIdle()
+
+ assertThat(scrollState.value).isEqualTo(requestsFulfilledScroll)
+ }
+
// TODO(b/222093277) Once the test runtime supports layout calls between frames, write more
// tests for intermediate state changes, including request cancellation, non-overlapping
// request interruption, etc.
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/NodeInvalidationTestParent.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/NodeInvalidationTestParent.kt
index 8bfbd4d..9c8dd339 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/NodeInvalidationTestParent.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/NodeInvalidationTestParent.kt
@@ -142,8 +142,16 @@
assertThat(textChange).isFalse()
}
+ @Test
+ fun updateDoesntCrash_whenNotattached() {
+ createSubject(generateParams()).invalidateAll()
+ }
+
abstract fun Any.updateDrawArgs(drawParams: DrawParams): Boolean
abstract fun Any.updateAll(params: Params): Pair<Boolean, Boolean>
+
+ abstract fun Any.invalidateAll()
+
abstract fun createSubject(params: Params): Any
abstract fun createSubject(params: Params, drawParams: DrawParams): Any
private fun generateParams(): Params {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCacheTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCacheTest.kt
index 6c88691..70b96bd 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCacheTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCacheTest.kt
@@ -18,6 +18,7 @@
import androidx.compose.foundation.text.TEST_FONT_FAMILY
import androidx.compose.foundation.text.toIntPx
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.Paragraph
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.createFontFamilyResolver
@@ -25,6 +26,7 @@
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.sp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -50,7 +52,7 @@
val text = "Hello"
val textDelegate = ParagraphLayoutCache(
text = text,
- style = TextStyle(fontSize = fontSize, fontFamily = fontFamily),
+ style = createTextStyle(fontSize = fontSize),
fontFamilyResolver = fontFamilyResolver,
).also {
it.density = this
@@ -68,7 +70,7 @@
val text = "Hello"
val textDelegate = ParagraphLayoutCache(
text = text,
- style = TextStyle(fontSize = fontSize, fontFamily = fontFamily),
+ style = createTextStyle(fontSize = fontSize),
fontFamilyResolver = fontFamilyResolver,
).also {
it.density = this
@@ -79,11 +81,12 @@
}
}
+ @OptIn(ExperimentalTextApi::class)
@Test
fun TextLayoutInput_reLayout_withDifferentHeight() {
val textDelegate = ParagraphLayoutCache(
text = "Hello World",
- style = TextStyle.Default,
+ style = TextStyle.Default.copy(fontFamily = fontFamily),
fontFamilyResolver = fontFamilyResolver,
).also {
it.density = density
@@ -106,11 +109,12 @@
assertThat(resultFirstLayout.height).isLessThan(resultSecondLayout.height)
}
+ @OptIn(ExperimentalTextApi::class)
@Test
fun TextLayoutResult_reLayout_withDifferentHeight() {
val textDelegate = ParagraphLayoutCache(
text = "Hello World",
- style = TextStyle.Default,
+ style = TextStyle.Default.copy(fontFamily = fontFamily),
fontFamilyResolver = fontFamilyResolver,
).also {
it.density = density
@@ -138,7 +142,7 @@
val fontSize = 20f
val textDelegate = ParagraphLayoutCache(
text = "Hello World! Hello World! Hello World! Hello World!",
- style = TextStyle(fontSize = fontSize.sp),
+ style = createTextStyle(fontSize = fontSize.sp),
fontFamilyResolver = fontFamilyResolver,
softWrap = false,
overflow = TextOverflow.Ellipsis,
@@ -163,7 +167,7 @@
val textDelegate = ParagraphLayoutCache(
text = "Hello World! Hello World! Hello World! Hello World!",
- style = TextStyle(fontSize = fontSize.sp),
+ style = createTextStyle(fontSize = fontSize.sp),
fontFamilyResolver = fontFamilyResolver,
overflow = TextOverflow.Ellipsis,
).also {
@@ -187,7 +191,7 @@
val textDelegate = ParagraphLayoutCache(
text = "Hello World",
- style = TextStyle(fontSize = fontSize.sp, letterSpacing = 0.5.sp),
+ style = createTextStyle(fontSize = fontSize.sp, letterSpacing = 0.5.sp),
fontFamilyResolver = fontFamilyResolver,
overflow = TextOverflow.Ellipsis,
).also {
@@ -207,7 +211,7 @@
val text = "a\n".repeat(20)
val textDelegate = ParagraphLayoutCache(
text = text,
- style = TextStyle(fontSize = 1.sp),
+ style = createTextStyle(fontSize = 1.sp),
fontFamilyResolver = fontFamilyResolver,
overflow = TextOverflow.Ellipsis,
maxLines = 5
@@ -219,7 +223,7 @@
val expected = Paragraph(
text,
- TextStyle(fontSize = 1.sp),
+ createTextStyle(fontSize = 1.sp),
Constraints(),
density,
fontFamilyResolver,
@@ -233,44 +237,58 @@
@Test
fun slowCreate_null_beforeLayout() {
val text = "hello"
+ val style = createTextStyle(fontSize = 1.sp)
val subject = ParagraphLayoutCache(
text,
- TextStyle(fontSize = 1.sp),
+ style,
fontFamilyResolver
).also {
it.density = density
}
- assertThat(subject.slowCreateTextLayoutResultOrNull()).isNull()
+ assertThat(subject.slowCreateTextLayoutResultOrNull(style = style)).isNull()
}
@Test
fun slowCreate_not_null_afterLayout() {
val text = "hello"
+ val style = createTextStyle(fontSize = 1.sp)
val subject = ParagraphLayoutCache(
text,
- TextStyle(fontSize = 1.sp),
+ style,
fontFamilyResolver
).also {
it.density = density
}
subject.layoutWithConstraints(Constraints(), LayoutDirection.Ltr)
- assertThat(subject.slowCreateTextLayoutResultOrNull()).isNotNull()
+ assertThat(subject.slowCreateTextLayoutResultOrNull(style = style)).isNotNull()
}
@Test
fun slowCreate_not_null_afterLayout_minWidthMinHeight() {
val text = "hello"
+ val style = createTextStyle(fontSize = 1.sp)
val subject = ParagraphLayoutCache(
text,
- TextStyle(fontSize = 1.sp),
+ style,
fontFamilyResolver
).also {
it.density = density
}
subject.layoutWithConstraints(Constraints(minWidth = 5, minHeight = 5), LayoutDirection.Ltr)
- assertThat(subject.slowCreateTextLayoutResultOrNull()).isNotNull()
+ assertThat(subject.slowCreateTextLayoutResultOrNull(style = style)).isNotNull()
+ }
+
+ private fun createTextStyle(
+ fontSize: TextUnit,
+ letterSpacing: TextUnit = TextUnit.Unspecified
+ ): TextStyle {
+ return TextStyle(
+ fontSize = fontSize,
+ fontFamily = fontFamily,
+ letterSpacing = letterSpacing
+ )
}
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNodeInvalidationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNodeInvalidationTest.kt
index 401c40a..f006017c 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNodeInvalidationTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNodeInvalidationTest.kt
@@ -32,6 +32,16 @@
)
}
+ override fun Any.invalidateAll() {
+ this as TextAnnotatedStringNode
+ doInvalidations(
+ drawChanged = true,
+ textChanged = true,
+ layoutChanged = true,
+ callbacksChanged = true
+ )
+ }
+
override fun Any.updateDrawArgs(drawParams: DrawParams): Boolean {
this as TextAnnotatedStringNode
return updateDraw(drawParams.color, drawParams.style)
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNodeInvalidationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNodeInvalidationTest.kt
index a1adb5f..2ab25f2 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNodeInvalidationTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNodeInvalidationTest.kt
@@ -34,6 +34,11 @@
)
}
+ override fun Any.invalidateAll() {
+ this as TextStringSimpleNode
+ doInvalidations(drawChanged = true, textChanged = true, layoutChanged = true)
+ }
+
override fun createSubject(params: Params): Any {
return TextStringSimpleNode(
params.text,
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/AbstractSelectionMagnifierTests.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/AbstractSelectionMagnifierTests.kt
index 1c6dfb1..e97716b 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/AbstractSelectionMagnifierTests.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/AbstractSelectionMagnifierTests.kt
@@ -363,14 +363,16 @@
showHandle(handle)
- // Touch the handle to show the magnifier.
- rule.onNode(isSelectionHandle(handle))
- .performTouchInput { down(center) }
+ // Touch and move the handle to show the magnifier.
+ rule.onNode(isSelectionHandle(handle)).performTouchInput {
+ down(center)
+ movePastSlopBy(dragDistance)
+ }
val magnifierInitialPosition = getMagnifierCenterOffset()
// Drag the handle horizontally - the magnifier should follow.
rule.onNode(isSelectionHandle(handle))
- .performTouchInput { movePastSlopBy(dragDistance) }
+ .performTouchInput { moveBy(dragDistance) }
assertThat(getMagnifierCenterOffset())
.isEqualTo(magnifierInitialPosition + dragDistance)
@@ -383,6 +385,7 @@
) {
val dragDistance = Offset(1f, 0f)
val dragDirection = if (checkStart xor (layoutDirection == LayoutDirection.Rtl)) -1f else 1f
+ val moveOffset = dragDistance * dragDirection
val fillerWord = if (layoutDirection == LayoutDirection.Ltr) "aaaa" else "באמת"
// When testing the cursor, we use an empty line so it doesn't have room to move in either
// direction. For other handles, the line needs to have some text to select.
@@ -402,14 +405,27 @@
showHandle(handle)
- // Touch the handle to show the magnifier.
- rule.onNode(isSelectionHandle(handle))
- .performTouchInput { down(center) }
+ // Touch and move the handle to show the magnifier.
+ rule.onNode(isSelectionHandle(handle)).performTouchInput {
+ down(center)
+ // If cursor, we have to drag the cursor to show the magnifier,
+ // press alone will not suffice
+ if (handle == Handle.Cursor) {
+ movePastSlopBy(moveOffset)
+ }
+ }
val magnifierInitialPosition = getMagnifierCenterOffset()
// Drag just a little past the end of the line.
rule.onNode(isSelectionHandle(handle))
- .performTouchInput { movePastSlopBy(dragDistance * dragDirection) }
+ .performTouchInput {
+ if (handle == Handle.Cursor) {
+ // If cursor, we dragged past slop before, so just move the normal delta
+ moveBy(moveOffset)
+ } else {
+ movePastSlopBy(moveOffset)
+ }
+ }
// The magnifier shouldn't have moved.
assertThat(getMagnifierCenterOffset()).isEqualTo(magnifierInitialPosition)
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicSecureTextFieldTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicSecureTextFieldTest.kt
new file mode 100644
index 0000000..fe5e726
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicSecureTextFieldTest.kt
@@ -0,0 +1,273 @@
+/*
+ * 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
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.text.selection.fetchTextLayoutResult
+import androidx.compose.foundation.text2.input.TextObfuscationMode
+import androidx.compose.foundation.text2.input.rememberTextFieldState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performTextInput
+import androidx.compose.ui.test.performTextInputSelection
+import androidx.compose.ui.test.performTextReplacement
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class BasicSecureTextFieldTest {
+
+ @get:Rule
+ val rule = createComposeRule().apply {
+ mainClock.autoAdvance = false
+ }
+
+ private val Tag = "BasicSecureTextField"
+
+ @Test
+ fun passwordSemanticsAreSet() {
+ rule.setContent {
+ BasicSecureTextField(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.Password))
+ }
+
+ @Test
+ fun lastTypedCharacterIsRevealedTemporarily() {
+ rule.setContent {
+ BasicSecureTextField(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ performTextInput("a")
+ rule.mainClock.advanceTimeBy(200)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("a")
+ rule.mainClock.advanceTimeBy(1500)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("\u2022")
+ }
+ }
+
+ @Test
+ fun lastTypedCharacterIsRevealed_hidesAfterAnotherCharacterIsTyped() {
+ rule.setContent {
+ BasicSecureTextField(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ performTextInput("a")
+ rule.mainClock.advanceTimeBy(200)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("a")
+ performTextInput("b")
+ rule.mainClock.advanceTimeBy(50)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("\u2022b")
+ }
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @Test
+ fun lastTypedCharacterIsRevealed_whenInsertedInMiddle() {
+ rule.setContent {
+ BasicSecureTextField(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ performTextInput("abc")
+ rule.mainClock.advanceTimeBy(200)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("\u2022\u2022\u2022")
+ performTextInputSelection(TextRange(1))
+ performTextInput("d")
+ rule.mainClock.advanceTimeBy(50)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("\u2022d\u2022\u2022")
+ }
+ }
+
+ @Test
+ fun lastTypedCharacterIsRevealed_hidesAfterFocusIsLost() {
+ val focusRequester = FocusRequester()
+ rule.setContent {
+ Column {
+ BasicSecureTextField(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag)
+ )
+ Box(modifier = Modifier
+ .size(1.dp)
+ .focusRequester(focusRequester)
+ .focusable()
+ )
+ }
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ performTextInput("a")
+ rule.mainClock.advanceTimeBy(200)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("a")
+ focusRequester.requestFocus()
+ rule.mainClock.advanceTimeBy(50)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("\u2022")
+ }
+ }
+
+ @Test
+ fun lastTypedCharacterIsRevealed_hidesAfterAnotherCharacterRemoved() {
+ rule.setContent {
+ BasicSecureTextField(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ performTextInput("abc")
+ rule.mainClock.advanceTimeBy(200)
+ performTextInput("d")
+ rule.mainClock.advanceTimeBy(50)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("\u2022\u2022\u2022d")
+ performTextReplacement("bcd")
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("\u2022\u2022\u2022")
+ }
+ }
+
+ @Test
+ fun obfuscationMethodVisible_doesNotHideAnything() {
+ rule.setContent {
+ BasicSecureTextField(
+ state = rememberTextFieldState(),
+ textObfuscationMode = TextObfuscationMode.Visible,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ performTextInput("abc")
+ rule.mainClock.advanceTimeBy(200)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("abc")
+ rule.mainClock.advanceTimeBy(1500)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("abc")
+ }
+ }
+
+ @Test
+ fun obfuscationMethodVisible_revealsEverythingWhenSwitchedTo() {
+ var obfuscationMode by mutableStateOf(TextObfuscationMode.Hidden)
+ rule.setContent {
+ BasicSecureTextField(
+ state = rememberTextFieldState(),
+ textObfuscationMode = obfuscationMode,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ performTextInput("abc")
+ rule.mainClock.advanceTimeBy(200)
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("\u2022\u2022\u2022")
+ obfuscationMode = TextObfuscationMode.Visible
+ rule.mainClock.advanceTimeByFrame()
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("abc")
+ }
+ }
+
+ @Test
+ fun obfuscationMethodHidden_hidesEverything() {
+ rule.setContent {
+ BasicSecureTextField(
+ state = rememberTextFieldState(),
+ textObfuscationMode = TextObfuscationMode.Hidden,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ performTextInput("abc")
+ rule.mainClock.advanceTimeByFrame()
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("\u2022\u2022\u2022")
+ performTextInput("d")
+ rule.mainClock.advanceTimeByFrame()
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("\u2022\u2022\u2022\u2022")
+ }
+ }
+
+ @Test
+ fun obfuscationMethodHidden_hidesEverythingWhenSwitchedTo() {
+ var obfuscationMode by mutableStateOf(TextObfuscationMode.Visible)
+ rule.setContent {
+ BasicSecureTextField(
+ state = rememberTextFieldState(),
+ textObfuscationMode = obfuscationMode,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ performTextInput("abc")
+ rule.mainClock.advanceTimeByFrame()
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("abc")
+ obfuscationMode = TextObfuscationMode.Hidden
+ rule.mainClock.advanceTimeByFrame()
+ assertThat(fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("\u2022\u2022\u2022")
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2ImmIntegrationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2ImmIntegrationTest.kt
new file mode 100644
index 0000000..230447f
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2ImmIntegrationTest.kt
@@ -0,0 +1,354 @@
+/*
+ * 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
+
+import android.view.KeyEvent
+import android.view.inputmethod.ExtractedText
+import android.view.inputmethod.InputConnection
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.internal.AndroidTextInputAdapter
+import androidx.compose.foundation.text2.input.internal.ComposeInputMethodManager
+import androidx.compose.foundation.text2.input.placeCursorAtEnd
+import androidx.compose.foundation.text2.input.placeCursorBeforeCharAt
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusManager
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.text.TextRange
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class, ExperimentalTestApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+internal class BasicTextField2ImmIntegrationTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ @get:Rule
+ val immRule = ComposeInputMethodManagerTestRule()
+
+ private val Tag = "BasicTextField2"
+
+ private val imm = FakeInputMethodManager()
+ private val state = TextFieldState()
+
+ @Before
+ fun setUp() {
+ immRule.setFactory { imm }
+ }
+
+ @Test
+ fun keyboardVisibility_whenFocusGained() {
+ rule.setContent {
+ BasicTextField2(state, Modifier.testTag(Tag))
+ }
+
+ rule.runOnIdle {
+ imm.expectNoMoreCalls()
+ }
+
+ requestFocus(Tag)
+
+ rule.runOnIdle {
+ imm.expectCall("restartInput")
+ imm.expectCall("showSoftInput")
+ imm.expectNoMoreCalls()
+ }
+ }
+
+ @Test
+ fun keyboardVisibility_whenFocusLost() {
+ var focusManager: FocusManager? = null
+ rule.setContent {
+ focusManager = LocalFocusManager.current
+ BasicTextField2(state, Modifier.testTag(Tag))
+ }
+ requestFocus(Tag)
+ rule.runOnIdle {
+ imm.resetCalls()
+
+ focusManager!!.clearFocus()
+ }
+
+ rule.runOnIdle {
+ imm.expectNoMoreCalls()
+ }
+ }
+
+ @Test
+ fun keyboardVisibility_whenFocusTransferred() {
+ rule.setContent {
+ BasicTextField2(state, Modifier.testTag(Tag + 1))
+ BasicTextField2(state, Modifier.testTag(Tag + 2))
+ }
+ requestFocus(Tag + 1)
+ rule.runOnIdle { imm.resetCalls() }
+
+ requestFocus(Tag + 2)
+
+ rule.runOnIdle {
+ imm.expectCall("restartInput")
+ imm.expectCall("showSoftInput")
+ imm.expectNoMoreCalls()
+ }
+ }
+
+ @Test
+ fun keyboardVisibility_whenRemovedFromCompositionWhileFocused() {
+ var compose by mutableStateOf(true)
+ rule.setContent {
+ if (compose) {
+ BasicTextField2(state, Modifier.testTag(Tag))
+ }
+ }
+ requestFocus(Tag)
+ rule.runOnIdle {
+ imm.resetCalls()
+
+ compose = false
+ }
+
+ rule.runOnIdle {
+ imm.expectCall("hideSoftInput")
+ imm.expectCall("restartInput")
+ imm.expectNoMoreCalls()
+ }
+ }
+
+ @Test
+ fun inputRestarted_whenStateInstanceChanged() {
+ var state by mutableStateOf(state)
+ rule.setContent {
+ BasicTextField2(state, Modifier.testTag(Tag))
+ }
+ requestFocus(Tag)
+ rule.runOnIdle { imm.resetCalls() }
+
+ state = TextFieldState()
+
+ rule.runOnIdle {
+ imm.expectCall("restartInput")
+ imm.expectCall("showSoftInput")
+ imm.expectNoMoreCalls()
+ }
+ }
+
+ @Test
+ fun immUpdated_whenFilterChangesText_fromInputConnection() {
+ val state = TextFieldState()
+ var inputConnection: InputConnection? = null
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ filter = { _, new ->
+ // Force the selection not to change.
+ val initialSelection = new.selectionInChars
+ new.append("world")
+ new.selectCharsIn(initialSelection)
+ }
+ )
+ }
+ requestFocus(Tag)
+ rule.runOnIdle {
+ imm.resetCalls()
+ inputConnection!!.setComposingText("hello", 1)
+ imm.expectCall("updateSelection(5, 5, -1, -1)")
+ imm.expectCall("restartInput")
+ imm.expectNoMoreCalls()
+ }
+ }
+
+ @Test
+ fun immUpdated_whenFilterChangesText_fromKeyEvent() {
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ filter = { _, new ->
+ val initialSelection = new.selectionInChars
+ new.append("world")
+ new.selectCharsIn(initialSelection)
+ }
+ )
+ }
+ requestFocus(Tag)
+ rule.runOnIdle { imm.resetCalls() }
+
+ rule.onNodeWithTag(Tag).performKeyInput { pressKey(Key.A) }
+
+ rule.runOnIdle {
+ imm.expectCall("restartInput")
+ imm.expectNoMoreCalls()
+ }
+ }
+
+ @Test
+ fun immUpdated_whenFilterChangesSelection_fromInputConnection() {
+ val state = TextFieldState()
+ var inputConnection: InputConnection? = null
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ filter = { _, new -> new.selectAll() }
+ )
+ }
+ requestFocus(Tag)
+ rule.runOnIdle {
+ imm.resetCalls()
+ inputConnection!!.setComposingText("hello", 1)
+ imm.expectCall("updateSelection(0, 5, 0, 5)")
+ imm.expectNoMoreCalls()
+ }
+ }
+
+ @Test
+ fun immUpdated_whenEditChangesText() {
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(state, Modifier.testTag(Tag))
+ }
+ requestFocus(Tag)
+ rule.runOnIdle {
+ imm.resetCalls()
+
+ state.edit {
+ append("hello")
+ placeCursorBeforeCharAt(0)
+ }
+
+ imm.expectCall("restartInput")
+ imm.expectNoMoreCalls()
+ }
+ }
+
+ @Test
+ fun immUpdated_whenEditChangesSelection() {
+ val state = TextFieldState("hello", initialSelectionInChars = TextRange(0))
+ rule.setContent {
+ BasicTextField2(state, Modifier.testTag(Tag))
+ }
+ requestFocus(Tag)
+ rule.runOnIdle {
+ imm.resetCalls()
+
+ state.edit {
+ placeCursorAtEnd()
+ }
+
+ imm.expectCall("updateSelection(5, 5, -1, -1)")
+ imm.expectNoMoreCalls()
+ }
+ }
+
+ @Test
+ fun immUpdated_whenEditChangesTextAndSelection() {
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(state, Modifier.testTag(Tag))
+ }
+ requestFocus(Tag)
+ rule.runOnIdle {
+ imm.resetCalls()
+
+ state.edit {
+ append("hello")
+ placeCursorAtEnd()
+ }
+
+ imm.expectCall("updateSelection(5, 5, -1, -1)")
+ imm.expectCall("restartInput")
+ imm.expectNoMoreCalls()
+ }
+ }
+
+ private fun requestFocus(tag: String) =
+ rule.onNodeWithTag(tag).performSemanticsAction(SemanticsActions.RequestFocus)
+
+ private class FakeInputMethodManager : ComposeInputMethodManager {
+ private val calls = mutableListOf<String>()
+
+ fun expectCall(description: String) {
+ assertThat(calls.removeFirst()).isEqualTo(description)
+ }
+
+ fun expectNoMoreCalls() {
+ assertThat(calls).isEmpty()
+ }
+
+ fun resetCalls() {
+ calls.clear()
+ }
+
+ override fun restartInput() {
+ calls += "restartInput"
+ }
+
+ override fun showSoftInput() {
+ calls += "showSoftInput"
+ }
+
+ override fun hideSoftInput() {
+ calls += "hideSoftInput"
+ }
+
+ override fun updateExtractedText(token: Int, extractedText: ExtractedText) {
+ calls += "updateExtractedText"
+ }
+
+ override fun updateSelection(
+ selectionStart: Int,
+ selectionEnd: Int,
+ compositionStart: Int,
+ compositionEnd: Int
+ ) {
+ calls += "updateSelection($selectionStart, $selectionEnd, " +
+ "$compositionStart, $compositionEnd)"
+ }
+
+ override fun sendKeyEvent(event: KeyEvent) {
+ calls += "sendKeyEvent"
+ }
+ }
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2SemanticsTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2SemanticsTest.kt
new file mode 100644
index 0000000..2761b7e
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2SemanticsTest.kt
@@ -0,0 +1,307 @@
+package androidx.compose.foundation.text2
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.text.BasicText
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.foundation.text.selection.fetchTextLayoutResult
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldState
+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.platform.testTag
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.semantics.getOrNull
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.assertHasClickAction
+import androidx.compose.ui.test.assertTextEquals
+import androidx.compose.ui.test.hasImeAction
+import androidx.compose.ui.test.hasSetTextAction
+import androidx.compose.ui.test.isEnabled
+import androidx.compose.ui.test.isFocused
+import androidx.compose.ui.test.isNotEnabled
+import androidx.compose.ui.test.isNotFocused
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.performTextInput
+import androidx.compose.ui.test.performTextInputSelection
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.ImeAction
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class BasicTextField2SemanticsTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ private val Tag = "TextField"
+
+ @Test
+ fun defaultSemantics() {
+ rule.setContent {
+ BasicTextField2(
+ modifier = Modifier.testTag(Tag),
+ state = remember { TextFieldState() },
+ decorationBox = {
+ Column {
+ BasicText("label")
+ it()
+ }
+ }
+ )
+ }
+
+ rule.onNodeWithTag(Tag)
+ .assertEditableTextEquals("")
+ .assertTextEquals("label", includeEditableText = false)
+ .assertHasClickAction()
+ .assert(hasSetTextAction())
+ .assert(hasImeAction(ImeAction.Default))
+ .assert(isNotFocused())
+ .assert(
+ SemanticsMatcher.expectValue(
+ SemanticsProperties.TextSelectionRange,
+ TextRange.Zero
+ )
+ )
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.SetText))
+ .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Password))
+ // TODO(halilibo): enable after selection work is completed.
+ // .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.SetSelection))
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.GetTextLayoutResult))
+
+ val textLayoutResults = mutableListOf<TextLayoutResult>()
+ rule.onNodeWithTag(Tag)
+ .performSemanticsAction(SemanticsActions.GetTextLayoutResult) { it(textLayoutResults) }
+ assert(textLayoutResults.size == 1) { "TextLayoutResult is null" }
+ }
+
+ @Test
+ fun semantics_enabledStatus() {
+ var enabled by mutableStateOf(true)
+ rule.setContent {
+ val state = remember { TextFieldState() }
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ enabled = enabled
+ )
+ }
+
+ rule.onNodeWithTag(Tag)
+ .assert(isEnabled())
+
+ enabled = false
+ rule.waitForIdle()
+
+ rule.onNodeWithTag(Tag)
+ .assert(isNotEnabled())
+ }
+
+ @Test
+ fun semantics_clickAction() {
+ rule.setContent {
+ val state = remember { TextFieldState() }
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag)
+ .assert(isNotFocused())
+ .performSemanticsAction(SemanticsActions.OnClick)
+ rule.onNodeWithTag(Tag)
+ .assert(isFocused())
+ }
+
+ @Test
+ fun semantics_imeOption() {
+ rule.setContent {
+ val state = remember { TextFieldState() }
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).assert(hasImeAction(ImeAction.Search))
+ }
+
+ @Test
+ fun contentSemanticsAreSet_inTheFirstComposition() {
+ val state = TextFieldState("hello")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).assertTextEquals("hello")
+ }
+
+ @Test
+ fun contentSemanticsAreSet_afterRecomposition() {
+ val state = TextFieldState("hello")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).assertTextEquals("hello")
+
+ state.editProcessor.reset(TextFieldCharSequence("hello2"))
+
+ rule.onNodeWithTag(Tag).assertTextEquals("hello2")
+ }
+
+ @Test
+ fun selectionSemanticsAreSet_inTheFirstComposition() {
+ val state = TextFieldState("hello", initialSelectionInChars = TextRange(2))
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ assertTextEquals("hello")
+ assertSelection(TextRange(2))
+ }
+ }
+
+ @Test
+ fun selectionSemanticsAreSet_afterRecomposition() {
+ val state = TextFieldState("hello")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ assertTextEquals("hello")
+ assertSelection(TextRange.Zero)
+ }
+
+ state.editProcessor.reset(TextFieldCharSequence("hello", selection = TextRange(2)))
+
+ with(rule.onNodeWithTag(Tag)) {
+ assertTextEquals("hello")
+ assertSelection(TextRange(2))
+ }
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @Test
+ fun inputSelection_changesSelectionState() {
+ val state = TextFieldState("hello")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performTextInputSelection(TextRange(2))
+
+ rule.runOnIdle {
+ assertThat(state.text.selectionInChars).isEqualTo(TextRange(2))
+ }
+ }
+
+ @Test
+ fun textLayoutResultSemanticsAreSet_inTheFirstComposition() {
+ val state = TextFieldState("hello")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier
+ .testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).assertTextEquals("hello")
+ assertThat(rule.onNodeWithTag(Tag).fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("hello")
+ }
+
+ @Test
+ fun textLayoutResultSemanticsAreUpdated_afterRecomposition() {
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier
+ .testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).assertTextEquals("")
+ rule.onNodeWithTag(Tag).performTextInput("hello")
+ assertThat(rule.onNodeWithTag(Tag).fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo("hello")
+ }
+
+ @Test
+ fun semanticsAreSet_afterStateObjectChanges() {
+ val state1 = TextFieldState("hello")
+ val state2 = TextFieldState("world", TextRange(2))
+ var chosenState by mutableStateOf(true)
+ rule.setContent {
+ BasicTextField2(
+ state = if (chosenState) state1 else state2,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ assertTextEquals("hello")
+ assertSelection(TextRange.Zero)
+ }
+
+ chosenState = false
+
+ with(rule.onNodeWithTag(Tag)) {
+ assertTextEquals("world")
+ assertSelection(TextRange(2))
+ }
+ }
+
+ private fun SemanticsNodeInteraction.assertSelection(expected: TextRange) {
+ val selection = fetchSemanticsNode().config
+ .getOrNull(SemanticsProperties.TextSelectionRange)
+ assertThat(selection).isEqualTo(expected)
+ }
+
+ private fun SemanticsNodeInteraction.assertEditableTextEquals(
+ value: String
+ ): SemanticsNodeInteraction =
+ assert(
+ SemanticsMatcher("${SemanticsProperties.EditableText.name} = '$value'") {
+ it.config.getOrNull(SemanticsProperties.EditableText)?.text.equals(value)
+ }
+ )
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2Test.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2Test.kt
new file mode 100644
index 0000000..30f846c
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2Test.kt
@@ -0,0 +1,978 @@
+/*
+ * 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
+
+import android.text.InputType
+import android.view.inputmethod.EditorInfo
+import android.view.inputmethod.InputConnection
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.ScrollState
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.text.KeyboardHelper
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList
+import androidx.compose.foundation.text2.input.TextFieldBufferWithSelection
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.internal.AndroidTextInputAdapter
+import androidx.compose.foundation.text2.input.rememberTextFieldState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.runtime.derivedStateOf
+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.input.key.Key
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.semantics.SemanticsProperties.TextSelectionRange
+import androidx.compose.ui.semantics.getOrNull
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.assertIsFocused
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsNotFocused
+import androidx.compose.ui.test.assertTextEquals
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.performTextInput
+import androidx.compose.ui.test.performTextInputSelection
+import androidx.compose.ui.test.performTextReplacement
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.test.swipeRight
+import androidx.compose.ui.test.swipeUp
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardCapitalization
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class, ExperimentalTestApi::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+internal class BasicTextField2Test {
+ @get:Rule
+ val rule = createComposeRule()
+
+ private val Tag = "BasicTextField2"
+
+ @After
+ fun tearDown() {
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests(null)
+ }
+
+ @Test
+ fun textField_rendersEmptyContent() {
+ var textLayoutResult: TextLayoutResult? = null
+ rule.setContent {
+ val state = remember { TextFieldState() }
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.fillMaxSize(),
+ onTextLayout = { textLayoutResult = it }
+ )
+ }
+
+ rule.runOnIdle {
+ assertThat(textLayoutResult).isNotNull()
+ assertThat(textLayoutResult?.layoutInput?.text).isEqualTo(AnnotatedString(""))
+ }
+ }
+
+ @Test
+ fun textField_contentChange_updatesState() {
+ val state = TextFieldState("Hello ", TextRange(Int.MAX_VALUE))
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier
+ .fillMaxSize()
+ .testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performTextInput("World!")
+
+ rule.runOnIdle {
+ assertThat(state.text.toString()).isEqualTo("Hello World!")
+ }
+
+ rule.onNodeWithTag(Tag).assertTextEquals("Hello World!")
+ val selection = rule.onNodeWithTag(Tag).fetchSemanticsNode()
+ .config.getOrNull(TextSelectionRange)
+ assertThat(selection).isEqualTo(TextRange("Hello World!".length))
+ }
+
+ /**
+ * This is a goal that we set for ourselves. Only updating the editing buffer should not cause
+ * BasicTextField to recompose.
+ */
+ @Test
+ fun textField_imeUpdatesDontCauseRecomposition() {
+ val state = TextFieldState()
+ var compositionCount = 0
+ var textLayoutResultCount = 0
+ rule.setContent {
+ compositionCount++
+ BasicTextField2(
+ state = state,
+ modifier = Modifier
+ .fillMaxSize()
+ .testTag(Tag),
+ onTextLayout = { textLayoutResultCount++ }
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ performTextInput("hello")
+ }
+
+ rule.runOnIdle {
+ assertThat(compositionCount).isEqualTo(1)
+ assertThat(textLayoutResultCount).isEqualTo(2)
+ }
+ }
+
+ @Test
+ fun textField_textStyleFontSizeChange_relayouts() {
+ val state = TextFieldState("Hello ", TextRange(Int.MAX_VALUE))
+ var style by mutableStateOf(TextStyle(fontSize = 20.sp))
+ val textLayoutResults = mutableListOf<TextLayoutResult>()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier
+ .fillMaxSize()
+ .testTag(Tag),
+ textStyle = style,
+ onTextLayout = { textLayoutResults += it }
+ )
+ }
+
+ style = TextStyle(fontSize = 30.sp)
+
+ rule.runOnIdle {
+ assertThat(textLayoutResults.size).isEqualTo(2)
+ assertThat(textLayoutResults.map { it.layoutInput.style.fontSize })
+ .isEqualTo(listOf(20.sp, 30.sp))
+ }
+ }
+
+ @Test
+ fun textField_textStyleColorChange_doesNotRelayout() {
+ val state = TextFieldState("Hello")
+ var style by mutableStateOf(TextStyle(color = Color.Red))
+ val textLayoutResults = mutableListOf<TextLayoutResult>()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier
+ .fillMaxSize()
+ .testTag(Tag),
+ textStyle = style,
+ onTextLayout = { textLayoutResults += it }
+ )
+ }
+
+ style = TextStyle(color = Color.Blue)
+
+ rule.runOnIdle {
+ assertThat(textLayoutResults.size).isEqualTo(2)
+ assertThat(textLayoutResults[0].multiParagraph)
+ .isSameInstanceAs(textLayoutResults[1].multiParagraph)
+ }
+ }
+
+ @Test
+ fun textField_contentChange_relayouts() {
+ val state = TextFieldState("Hello ", TextRange(Int.MAX_VALUE))
+ val textLayoutResults = mutableListOf<TextLayoutResult>()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier
+ .fillMaxSize()
+ .testTag(Tag),
+ onTextLayout = { textLayoutResults += it }
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performTextInput("World!")
+
+ rule.runOnIdle {
+ assertThat(textLayoutResults.size).isEqualTo(2)
+ assertThat(textLayoutResults.map { it.layoutInput.text.text })
+ .isEqualTo(listOf("Hello ", "Hello World!"))
+ }
+ }
+
+ @Test
+ fun textField_focus_showsSoftwareKeyboard() {
+ val state = TextFieldState()
+ val keyboardHelper = KeyboardHelper(rule)
+ rule.setContent {
+ keyboardHelper.initialize()
+ BasicTextField2(
+ state = state,
+ modifier = Modifier
+ .fillMaxSize()
+ .testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performClick()
+ rule.onNodeWithTag(Tag).assertIsFocused()
+
+ keyboardHelper.waitForKeyboardVisibility(true)
+
+ rule.runOnIdle {
+ assertThat(keyboardHelper.isSoftwareKeyboardShown()).isTrue()
+ }
+ }
+
+ @Ignore // b/273412941
+ @Test
+ fun textField_focus_doesNotShowSoftwareKeyboard_ifDisabled() {
+ val state = TextFieldState()
+ val keyboardHelper = KeyboardHelper(rule)
+ rule.setContent {
+ keyboardHelper.initialize()
+ BasicTextField2(
+ state = state,
+ enabled = false,
+ modifier = Modifier
+ .fillMaxSize()
+ .testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).assertIsNotEnabled()
+ rule.onNodeWithTag(Tag).performClick()
+ rule.onNodeWithTag(Tag).assertIsNotFocused()
+
+ keyboardHelper.waitForKeyboardVisibility(false)
+
+ rule.runOnIdle {
+ assertThat(keyboardHelper.isSoftwareKeyboardShown()).isFalse()
+ }
+ }
+
+ @Test
+ fun textField_whenStateObjectChanges_newTextIsRendered() {
+ val state1 = TextFieldState("Hello")
+ val state2 = TextFieldState("World")
+ var toggleState by mutableStateOf(true)
+ val state by derivedStateOf { if (toggleState) state1 else state2 }
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ enabled = true,
+ modifier = Modifier
+ .fillMaxSize()
+ .testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).assertTextEquals("Hello")
+ toggleState = !toggleState
+ rule.onNodeWithTag(Tag).assertTextEquals("World")
+ }
+
+ @Test
+ fun textField_whenStateObjectChanges_restartsInput() {
+ val state1 = TextFieldState("Hello")
+ val state2 = TextFieldState("World")
+ var toggleState by mutableStateOf(true)
+ val state by derivedStateOf { if (toggleState) state1 else state2 }
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ enabled = true,
+ modifier = Modifier
+ .fillMaxSize()
+ .testTag(Tag)
+ )
+ }
+
+ with(rule.onNodeWithTag(Tag)) {
+ performTextReplacement("Compose")
+ assertTextEquals("Compose")
+ }
+ toggleState = !toggleState
+ with(rule.onNodeWithTag(Tag)) {
+ performTextReplacement("Compose2")
+ assertTextEquals("Compose2")
+ }
+ assertThat(state1.text.toString()).isEqualTo("Compose")
+ assertThat(state2.text.toString()).isEqualTo("Compose2")
+ }
+
+ @Test
+ fun textField_passesKeyboardOptionsThrough() {
+ var editorInfo: EditorInfo? = null
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { info, _ ->
+ editorInfo = info
+ }
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ // We don't need to test all combinations here, that is tested in EditorInfoTest.
+ keyboardOptions = KeyboardOptions(
+ capitalization = KeyboardCapitalization.Characters,
+ keyboardType = KeyboardType.Email,
+ imeAction = ImeAction.Previous
+ )
+ )
+ }
+ requestFocus(Tag)
+
+ rule.runOnIdle {
+ assertThat(editorInfo).isNotNull()
+ assertThat(editorInfo!!.imeOptions and EditorInfo.IME_ACTION_PREVIOUS).isNotEqualTo(0)
+ assertThat(editorInfo!!.inputType and EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS)
+ .isNotEqualTo(0)
+ assertThat(editorInfo!!.inputType and InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS)
+ .isNotEqualTo(0)
+ }
+ }
+
+ @Test
+ fun textField_appliesFilter_toInputConnection() {
+ var inputConnection: InputConnection? = null
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = RejectAllTextFilter,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+ requestFocus(Tag)
+
+ rule.runOnIdle { inputConnection!!.commitText("hello") }
+ rule.onNodeWithTag(Tag).assertTextEquals("")
+ }
+
+ @Test
+ fun textField_appliesFilter_toSetTextSemanticsAction() {
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = RejectAllTextFilter,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performTextReplacement("hello")
+ rule.onNodeWithTag(Tag).assertTextEquals("")
+ }
+
+ @Test
+ fun textField_appliesFilter_toInsertTextSemanticsAction() {
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = RejectAllTextFilter,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performTextInput("hello")
+ rule.onNodeWithTag(Tag).assertTextEquals("")
+ }
+
+ @Test
+ fun textField_appliesFilter_toKeyEvents() {
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = RejectAllTextFilter,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performKeyInput { pressKey(Key.A) }
+ rule.onNodeWithTag(Tag).assertTextEquals("")
+ }
+
+ @Ignore("b/276932521")
+ @Test
+ fun textField_appliesFilter_toInputConnection_afterChanging() {
+ var inputConnection: InputConnection? = null
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+
+ val state = TextFieldState()
+ var filter by mutableStateOf<TextEditFilter?>(null)
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = filter,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+ requestFocus(Tag)
+
+ rule.runOnIdle { inputConnection!!.commitText("hello") }
+ rule.onNodeWithTag(Tag).assertTextEquals("hello")
+
+ filter = RejectAllTextFilter
+
+ rule.runOnIdle { inputConnection!!.commitText("world") }
+ rule.onNodeWithTag(Tag).assertTextEquals("hello")
+
+ filter = null
+
+ rule.runOnIdle { inputConnection!!.commitText("world") }
+ rule.onNodeWithTag(Tag).assertTextEquals("helloworld")
+ }
+
+ @Test
+ fun textField_appliesFilter_toSetTextSemanticsAction_afterChanging() {
+ val state = TextFieldState()
+ var filter by mutableStateOf<TextEditFilter?>(null)
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = filter,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performTextInput("hello")
+ rule.onNodeWithTag(Tag).assertTextEquals("hello")
+
+ filter = RejectAllTextFilter
+
+ rule.onNodeWithTag(Tag).performTextReplacement("world")
+ rule.onNodeWithTag(Tag).assertTextEquals("hello")
+
+ filter = null
+
+ rule.onNodeWithTag(Tag).performTextReplacement("world")
+ rule.onNodeWithTag(Tag).assertTextEquals("world")
+ }
+
+ @Test
+ fun textField_appliesFilter_toInsertTextSemanticsAction_afterChanging() {
+ val state = TextFieldState()
+ var filter by mutableStateOf<TextEditFilter?>(null)
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = filter,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performTextInput("hello")
+ rule.onNodeWithTag(Tag).assertTextEquals("hello")
+
+ filter = RejectAllTextFilter
+
+ rule.onNodeWithTag(Tag).performTextInput("world")
+ rule.onNodeWithTag(Tag).assertTextEquals("hello")
+
+ filter = null
+
+ rule.onNodeWithTag(Tag).performTextInput("world")
+ rule.onNodeWithTag(Tag).assertTextEquals("helloworld")
+ }
+
+ @Test
+ fun textField_appliesFilter_toKeyEvents_afterChanging() {
+ val state = TextFieldState()
+ var filter by mutableStateOf<TextEditFilter?>(null)
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = filter,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performTextInput("hello")
+ rule.onNodeWithTag(Tag).assertTextEquals("hello")
+
+ filter = RejectAllTextFilter
+
+ rule.onNodeWithTag(Tag).performKeyInput { pressKey(Key.Spacebar) }
+ rule.onNodeWithTag(Tag).assertTextEquals("hello")
+
+ filter = null
+
+ rule.onNodeWithTag(Tag).performKeyInput { pressKey(Key.Spacebar) }
+ rule.onNodeWithTag(Tag).assertTextEquals("hello ")
+ }
+
+ @Test
+ fun textField_changesAreTracked_whenInputConnectionCommits() {
+ lateinit var inputConnection: InputConnection
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+ val state = TextFieldState()
+ lateinit var changes: ChangeList
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = { _, new ->
+ if (new.changes.changeCount > 0) {
+ changes = new.changes
+ }
+ },
+ modifier = Modifier.testTag(Tag),
+ )
+ }
+ requestFocus(Tag)
+
+ rule.runOnIdle { inputConnection.commitText("hello") }
+
+ rule.runOnIdle {
+ assertThat(changes.changeCount).isEqualTo(1)
+ assertThat(changes.getRange(0)).isEqualTo(TextRange(0, 5))
+ assertThat(changes.getOriginalRange(0)).isEqualTo(TextRange(0, 0))
+ }
+ }
+
+ @Ignore // b/278560997
+ @Test
+ fun textField_changesAreTracked_whenInputConnectionComposes() {
+ lateinit var inputConnection: InputConnection
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+ val state = TextFieldState()
+ lateinit var changes: ChangeList
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = { _, new ->
+ if (new.changes.changeCount > 0) {
+ changes = new.changes
+ }
+ },
+ modifier = Modifier.testTag(Tag),
+ )
+ }
+ requestFocus(Tag)
+
+ rule.runOnIdle { inputConnection.setComposingText("hello", 1) }
+
+ rule.runOnIdle {
+ assertThat(changes.changeCount).isEqualTo(1)
+ assertThat(changes.getRange(0)).isEqualTo(TextRange(0, 5))
+ assertThat(changes.getOriginalRange(0)).isEqualTo(TextRange(0))
+ }
+ }
+
+ @Ignore // b/278560997
+ @Test
+ fun textField_changesAreTracked_whenInputConnectionDeletes() {
+ lateinit var inputConnection: InputConnection
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+ val state = TextFieldState("hello")
+ lateinit var changes: ChangeList
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = { _, new ->
+ if (new.changes.changeCount > 0) {
+ changes = new.changes
+ }
+ },
+ modifier = Modifier.testTag(Tag),
+ )
+ }
+ requestFocus(Tag)
+
+ rule.runOnIdle {
+ inputConnection.beginBatchEdit()
+ inputConnection.finishComposingText()
+ inputConnection.setSelection(5, 5)
+ inputConnection.deleteSurroundingText(1, 0)
+ inputConnection.endBatchEdit()
+ }
+
+ rule.runOnIdle {
+ assertThat(changes.changeCount).isEqualTo(1)
+ assertThat(changes.getRange(0)).isEqualTo(TextRange(4, 4))
+ assertThat(changes.getOriginalRange(0)).isEqualTo(TextRange(4, 5))
+ }
+ }
+
+ @Ignore // b/278560997
+ @Test
+ fun textField_changesAreTracked_whenInputConnectionDeletesViaComposition() {
+ lateinit var inputConnection: InputConnection
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+ val state = TextFieldState("hello")
+ lateinit var changes: ChangeList
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = { _, new ->
+ if (new.changes.changeCount > 0) {
+ changes = new.changes
+ }
+ },
+ modifier = Modifier.testTag(Tag),
+ )
+ }
+ requestFocus(Tag)
+
+ rule.runOnIdle {
+ inputConnection.beginBatchEdit()
+ inputConnection.setComposingRegion(0, 5)
+ inputConnection.setComposingText("h", 1)
+ inputConnection.endBatchEdit()
+ }
+
+ rule.runOnIdle {
+ assertThat(changes.changeCount).isEqualTo(1)
+ assertThat(changes.getRange(0)).isEqualTo(TextRange(0, 1))
+ assertThat(changes.getOriginalRange(0)).isEqualTo(TextRange(0, 5))
+ }
+ }
+
+ @Test
+ fun textField_changesAreTracked_whenKeyEventInserts() {
+ val state = TextFieldState()
+ lateinit var changes: ChangeList
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = { _, new ->
+ if (new.changes.changeCount > 0) {
+ changes = new.changes
+ }
+ },
+ modifier = Modifier.testTag(Tag),
+ )
+ }
+ requestFocus(Tag)
+
+ rule.onNodeWithTag(Tag).performKeyInput { pressKey(Key.A) }
+
+ rule.runOnIdle {
+ assertThat(changes.changeCount).isEqualTo(1)
+ assertThat(changes.getRange(0)).isEqualTo(TextRange(0, 1))
+ assertThat(changes.getOriginalRange(0)).isEqualTo(TextRange(0))
+ }
+ }
+
+ @Ignore // b/278560997
+ @Test
+ fun textField_changesAreTracked_whenKeyEventDeletes() {
+ val state = TextFieldState("hello")
+ lateinit var changes: ChangeList
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = { _, new ->
+ if (new.changes.changeCount > 0) {
+ changes = new.changes
+ }
+ },
+ modifier = Modifier.testTag(Tag),
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performTextInputSelection(TextRange(5))
+ rule.onNodeWithTag(Tag).performKeyInput { pressKey(Key.Backspace) }
+
+ rule.runOnIdle {
+ assertThat(changes.changeCount).isEqualTo(1)
+ assertThat(changes.getRange(0)).isEqualTo(TextRange(4, 4))
+ assertThat(changes.getOriginalRange(0)).isEqualTo(TextRange(4, 5))
+ }
+ }
+
+ @Test
+ fun textField_changesAreTracked_whenSemanticsActionInserts() {
+ val state = TextFieldState()
+ lateinit var changes: ChangeList
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ filter = { _, new ->
+ if (new.changes.changeCount > 0) {
+ changes = new.changes
+ }
+ },
+ modifier = Modifier.testTag(Tag),
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performTextInput("hello")
+
+ rule.runOnIdle {
+ assertThat(changes.changeCount).isEqualTo(1)
+ assertThat(changes.getRange(0)).isEqualTo(TextRange(0, 5))
+ assertThat(changes.getOriginalRange(0)).isEqualTo(TextRange(0))
+ }
+ }
+
+ @Test
+ fun textField_filterKeyboardOptions_sentToIme() {
+ lateinit var editorInfo: EditorInfo
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { ei, _ ->
+ editorInfo = ei
+ }
+ val filter = KeyboardOptionsFilter(
+ KeyboardOptions(
+ keyboardType = KeyboardType.Email,
+ imeAction = ImeAction.Previous
+ )
+ )
+ rule.setContent {
+ BasicTextField2(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag),
+ filter = filter,
+ )
+ }
+ requestFocus(Tag)
+
+ rule.runOnIdle {
+ assertThat(editorInfo.imeOptions and EditorInfo.IME_ACTION_PREVIOUS).isNotEqualTo(0)
+ assertThat(editorInfo.inputType and InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS)
+ .isNotEqualTo(0)
+ }
+ }
+
+ @Test
+ fun textField_filterKeyboardOptions_mergedWithParams() {
+ lateinit var editorInfo: EditorInfo
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { ei, _ ->
+ editorInfo = ei
+ }
+ val filter = KeyboardOptionsFilter(KeyboardOptions(imeAction = ImeAction.Previous))
+ rule.setContent {
+ BasicTextField2(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag),
+ filter = filter,
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email),
+ )
+ }
+ requestFocus(Tag)
+
+ rule.runOnIdle {
+ assertThat(editorInfo.imeOptions and EditorInfo.IME_ACTION_PREVIOUS).isNotEqualTo(0)
+ assertThat(editorInfo.inputType and InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS)
+ .isNotEqualTo(0)
+ }
+ }
+
+ @Test
+ fun textField_filterKeyboardOptions_overriddenByParams() {
+ lateinit var editorInfo: EditorInfo
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { ei, _ ->
+ editorInfo = ei
+ }
+ val filter = KeyboardOptionsFilter(KeyboardOptions(imeAction = ImeAction.Previous))
+ rule.setContent {
+ BasicTextField2(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag),
+ filter = filter,
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
+ )
+ }
+ requestFocus(Tag)
+
+ rule.runOnIdle {
+ assertThat(editorInfo.imeOptions and EditorInfo.IME_ACTION_SEARCH).isNotEqualTo(0)
+ }
+ }
+
+ @Test
+ fun textField_filterKeyboardOptions_applyWhenFilterChanged() {
+ lateinit var editorInfo: EditorInfo
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { ei, _ ->
+ editorInfo = ei
+ }
+ var filter by mutableStateOf(
+ KeyboardOptionsFilter(
+ KeyboardOptions(
+ keyboardType = KeyboardType.Email,
+ imeAction = ImeAction.Previous
+ )
+ )
+ )
+ rule.setContent {
+ BasicTextField2(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag),
+ filter = filter,
+ )
+ }
+ requestFocus(Tag)
+
+ rule.runOnIdle {
+ assertThat(editorInfo.imeOptions and EditorInfo.IME_ACTION_PREVIOUS).isNotEqualTo(0)
+ assertThat(editorInfo.inputType and InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS)
+ .isNotEqualTo(0)
+ }
+
+ filter = KeyboardOptionsFilter(
+ KeyboardOptions(
+ keyboardType = KeyboardType.Decimal,
+ imeAction = ImeAction.Search
+ )
+ )
+
+ rule.runOnIdle {
+ assertThat(editorInfo.imeOptions and EditorInfo.IME_ACTION_SEARCH).isNotEqualTo(0)
+ assertThat(editorInfo.inputType and InputType.TYPE_NUMBER_FLAG_DECIMAL)
+ .isNotEqualTo(0)
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = 23)
+ @Test
+ fun textField_showsKeyboardAgainWhenTapped_ifFocused() {
+ val keyboardHelper = KeyboardHelper(rule)
+ rule.setContent {
+ keyboardHelper.initialize()
+ BasicTextField2(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ // make sure keyboard is hidden initially
+ keyboardHelper.hideKeyboardIfShown()
+
+ // click the first time to gain focus.
+ rule.onNodeWithTag(Tag).performClick()
+ keyboardHelper.waitForKeyboardVisibility(true)
+ assertThat(keyboardHelper.isSoftwareKeyboardShown()).isTrue()
+
+ // hide it again.
+ keyboardHelper.hideKeyboardIfShown()
+ rule.onNodeWithTag(Tag).assertIsFocused()
+ rule.onNodeWithTag(Tag).performClick()
+
+ // expect keyboard to show up again.
+ keyboardHelper.waitForKeyboardVisibility(true)
+ assertThat(keyboardHelper.isSoftwareKeyboardShown()).isTrue()
+ }
+
+ @Test
+ fun swipingThroughTextField_doesNotGainFocus() {
+ rule.setContent {
+ BasicTextField2(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ rule.onNodeWithTag(Tag).performTouchInput {
+ // swipe through
+ swipeRight(endX = right + 200, durationMillis = 1000)
+ }
+ rule.onNodeWithTag(Tag).assertIsNotFocused()
+ }
+
+ @Ignore // b/278560997
+ @Test
+ fun swipingTextFieldInScrollableContainer_doesNotGainFocus() {
+ val scrollState = ScrollState(0)
+ rule.setContent {
+ Column(Modifier.size(100.dp).verticalScroll(scrollState)) {
+ BasicTextField2(
+ state = rememberTextFieldState(),
+ modifier = Modifier.testTag(Tag)
+ )
+ Box(Modifier.size(200.dp))
+ }
+ }
+
+ rule.onNodeWithTag(Tag).performTouchInput {
+ // swipe through
+ swipeUp(durationMillis = 1000)
+ }
+ rule.onNodeWithTag(Tag).assertIsNotFocused()
+ assertThat(scrollState.value).isNotEqualTo(0)
+ }
+
+ private fun requestFocus(tag: String) =
+ rule.onNodeWithTag(tag).performSemanticsAction(SemanticsActions.RequestFocus)
+
+ private fun InputConnection.commitText(text: String) {
+ beginBatchEdit()
+ finishComposingText()
+ commitText(text, 1)
+ endBatchEdit()
+ }
+
+ private object RejectAllTextFilter : TextEditFilter {
+ override fun filter(
+ originalValue: TextFieldCharSequence,
+ valueWithChanges: TextFieldBufferWithSelection
+ ) {
+ valueWithChanges.revertAllChanges()
+ }
+ }
+
+ private class KeyboardOptionsFilter(override val keyboardOptions: KeyboardOptions) :
+ TextEditFilter {
+ override fun filter(
+ originalValue: TextFieldCharSequence,
+ valueWithChanges: TextFieldBufferWithSelection
+ ) {
+ // Noop
+ }
+ }
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/ComposeInputMethodManagerTestRule.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/ComposeInputMethodManagerTestRule.kt
new file mode 100644
index 0000000..537aabd
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/ComposeInputMethodManagerTestRule.kt
@@ -0,0 +1,52 @@
+/*
+ * 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
+
+import android.view.View
+import androidx.compose.foundation.text2.input.internal.ComposeInputMethodManager
+import androidx.compose.foundation.text2.input.internal.overrideComposeInputMethodManagerFactoryForTests
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Rule to help setting the factory used to create [ComposeInputMethodManager] instances for tests.
+ * Restores the previous factory after the test finishes.
+ */
+internal class ComposeInputMethodManagerTestRule : TestRule {
+ private var initialFactory: ((View) -> ComposeInputMethodManager)? = null
+
+ fun setFactory(factory: (View) -> ComposeInputMethodManager) {
+ val previousFactory = overrideComposeInputMethodManagerFactoryForTests(factory)
+ if (initialFactory == null) {
+ initialFactory = previousFactory
+ }
+ }
+
+ override fun apply(base: Statement, description: Description): Statement =
+ object : Statement() {
+ override fun evaluate() {
+ try {
+ base.evaluate()
+ } finally {
+ // Reset the factory if it was set during the test so the next test gets the
+ // default behavior.
+ initialFactory?.let(::overrideComposeInputMethodManagerFactoryForTests)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/DecorationBoxTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/DecorationBoxTest.kt
new file mode 100644
index 0000000..f66ec98
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/DecorationBoxTest.kt
@@ -0,0 +1,281 @@
+/*
+ * 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
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.assertIsFocused
+import androidx.compose.ui.test.click
+import androidx.compose.ui.test.hasParent
+import androidx.compose.ui.test.hasSetTextAction
+import androidx.compose.ui.test.hasText
+import androidx.compose.ui.test.isFocused
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.longClick
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.performTextInput
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class DecorationBoxTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ private val Tag = "BasicTextField2"
+ private val DecorationTag = "DecorationBox"
+
+ @Test
+ fun focusIsAppliedOnDecoratedComposable() {
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ decorationBox = { innerTextField ->
+ Box(
+ modifier = Modifier
+ .border(BorderStroke(2.dp, SolidColor(Color.Red)))
+ .padding(16.dp)
+ .testTag(DecorationTag)
+ ) {
+ innerTextField()
+ }
+ }
+ )
+ }
+
+ // requestFocus on node
+ rule.onNodeWithTag(Tag).performClick()
+
+ // assertThat decoration modifier has a focused parent.
+ rule.onNodeWithTag(DecorationTag, useUnmergedTree = true).assert(hasParent(isFocused()))
+ }
+
+ @Test
+ fun semanticsAreAppliedOnDecoratedComposable() {
+ val state = TextFieldState("hello")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ decorationBox = { innerTextField ->
+ Box(
+ modifier = Modifier
+ .border(BorderStroke(2.dp, SolidColor(Color.Red)))
+ .padding(16.dp)
+ .testTag(DecorationTag)
+ ) {
+ innerTextField()
+ }
+ }
+ )
+ }
+
+ // assertThat decoration modifier has a focused parent.
+ with(rule.onNodeWithTag(DecorationTag, useUnmergedTree = true)) {
+ assert(hasParent(hasText("hello")))
+ assert(hasParent(hasSetTextAction()))
+ }
+ }
+
+ @Test
+ fun clickGestureIsAppliedOnDecoratedComposable() {
+ val state = TextFieldState("hello")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ decorationBox = { innerTextField ->
+ Box(
+ modifier = Modifier
+ .border(BorderStroke(2.dp, SolidColor(Color.Red)))
+ .padding(16.dp)
+ .testTag(DecorationTag)
+ ) {
+ innerTextField()
+ }
+ }
+ )
+ }
+
+ // click on decoration box
+ rule.onNodeWithTag(DecorationTag, useUnmergedTree = true).performTouchInput {
+ // should be on the box not on inner text field since there is a padding
+ click(Offset(1f, 1f))
+ }
+
+ // assertThat textfield has focus
+ rule.onNodeWithTag(Tag).assertIsFocused()
+ }
+
+ @Test
+ fun nonPlacedInnerTextField_stillAcceptsTextInput() {
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ decorationBox = {
+ Box(
+ modifier = Modifier
+ .border(BorderStroke(2.dp, SolidColor(Color.Red)))
+ .padding(16.dp)
+ )
+ }
+ )
+ }
+
+ // requestFocus on node
+ with(rule.onNodeWithTag(Tag)) {
+ performClick()
+ performTextInput("hello")
+ }
+
+ rule.runOnIdle {
+ assertThat(state.text.toString()).isEqualTo("hello")
+ }
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @Test
+ fun nonPlacedInnerTextField_stillAcceptsKeyInput() {
+ val state = TextFieldState()
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ decorationBox = {
+ Box(
+ modifier = Modifier
+ .border(BorderStroke(2.dp, SolidColor(Color.Red)))
+ .padding(16.dp)
+ )
+ }
+ )
+ }
+
+ // requestFocus on node
+ with(rule.onNodeWithTag(Tag)) {
+ performClick()
+ performKeyInput {
+ pressKey(Key.H)
+ pressKey(Key.E)
+ pressKey(Key.L)
+ pressKey(Key.L)
+ pressKey(Key.O)
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(state.text.toString()).isEqualTo("hello")
+ }
+ }
+
+ @Test
+ fun minConstraintsArePropagated() {
+ val state = TextFieldState()
+ var decorationBoxConstraints: Constraints? = null
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.fillMaxSize().testTag(Tag),
+ decorationBox = {
+ Layout { _, constraints ->
+ decorationBoxConstraints = constraints
+ layout(0, 0) {}
+ }
+ }
+ )
+ }
+
+ rule.waitForIdle()
+
+ assertThat(decorationBoxConstraints?.minWidth)
+ .isNotEqualTo(0)
+ assertThat(decorationBoxConstraints?.minWidth)
+ .isEqualTo(decorationBoxConstraints?.maxWidth)
+
+ assertThat(decorationBoxConstraints?.minHeight)
+ .isNotEqualTo(0)
+ assertThat(decorationBoxConstraints?.minHeight)
+ .isEqualTo(decorationBoxConstraints?.maxHeight)
+ }
+
+ @Ignore // TODO(halilibo): enable when pointerInput gestures are enabled
+ @Test
+ fun longClickGestureIsAppliedOnDecoratedComposable() {
+ // create a decorated BasicTextField2
+ val state = TextFieldState("hello")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ modifier = Modifier.testTag(Tag),
+ decorationBox = { innerTextField ->
+ Box(
+ modifier = Modifier
+ .border(BorderStroke(2.dp, SolidColor(Color.Red)))
+ .padding(16.dp)
+ .testTag(DecorationTag)
+ ) {
+ innerTextField()
+ }
+ }
+ )
+ }
+
+ // click on decoration box
+ rule.onNodeWithTag(DecorationTag, useUnmergedTree = true).performTouchInput {
+ // should be on the box not on inner text field since there is a padding
+ longClick(Offset(1f, 1f))
+ }
+
+ // assertThat selection happened
+ rule.runOnIdle {
+ assertThat(state.text.selectionInChars).isEqualTo(TextRange(0, 5))
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/HeightInLinesModifierTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/HeightInLinesModifierTest.kt
new file mode 100644
index 0000000..4f255d7
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/HeightInLinesModifierTest.kt
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.text2
+
+import android.content.Context
+import android.graphics.Typeface
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.requiredWidth
+import androidx.compose.foundation.text.TEST_FONT
+import androidx.compose.foundation.text.heightInLines
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.platform.InspectableValue
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalFontFamilyResolver
+import androidx.compose.ui.platform.ValueElement
+import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.AndroidFont
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontLoadingStrategy
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.text.font.FontVariation
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.font.createFontFamilyResolver
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class HeightInLinesModifierTest {
+
+ private val longText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " +
+ "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam," +
+ " quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " +
+ "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu " +
+ "fugiat nulla pariatur."
+
+ private val context = InstrumentationRegistry.getInstrumentation().context
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun minLines_shortInputText() {
+ var subjectLayout: TextLayoutResult? = null
+ var subjectHeight: Int? = null
+ var twoLineHeight: Int? = null
+ val positionedLatch = CountDownLatch(1)
+ val twoLinePositionedLatch = CountDownLatch(1)
+
+ rule.setContent {
+ HeightObservingText(
+ onGlobalHeightPositioned = {
+ subjectHeight = it
+ positionedLatch.countDown()
+ },
+ onTextLayoutResult = {
+ subjectLayout = it
+ },
+ text = "abc",
+ lineLimits = MultiLine(minHeightInLines = 2)
+ )
+ HeightObservingText(
+ onGlobalHeightPositioned = {
+ twoLineHeight = it
+ twoLinePositionedLatch.countDown()
+ },
+ onTextLayoutResult = {},
+ text = "1\n2",
+ lineLimits = MultiLine(minHeightInLines = 2)
+ )
+ }
+ assertThat(positionedLatch.await(1, TimeUnit.SECONDS)).isTrue()
+ assertThat(twoLinePositionedLatch.await(1, TimeUnit.SECONDS)).isTrue()
+
+ rule.runOnIdle {
+ assertThat(subjectLayout).isNotNull()
+ assertThat(subjectLayout!!.lineCount).isEqualTo(1)
+ assertThat(subjectHeight!!).isEqualTo(twoLineHeight)
+ }
+ }
+
+ @Test
+ fun maxLines_shortInputText() {
+ val (textLayoutResult, height) = setTextFieldWithMaxLines(
+ text = "abc",
+ lines = MultiLine(maxHeightInLines = 5)
+ )
+
+ rule.runOnIdle {
+ assertThat(textLayoutResult).isNotNull()
+ assertThat(textLayoutResult!!.lineCount).isEqualTo(1)
+ assertThat(textLayoutResult.size.height).isEqualTo(height)
+ }
+ }
+
+ @Test
+ fun maxLines_notApplied_infiniteMaxLines() {
+ val (textLayoutResult, height) =
+ setTextFieldWithMaxLines(longText, MultiLine(minHeightInLines = Int.MAX_VALUE))
+
+ rule.runOnIdle {
+ assertThat(textLayoutResult).isNotNull()
+ assertThat(textLayoutResult!!.size.height).isEqualTo(height)
+ }
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun minLines_invalidValue() {
+ rule.setContent {
+ Box(
+ modifier = Modifier.heightInLines(textStyle = TextStyle.Default, minLines = 0)
+ )
+ }
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun maxLines_invalidValue() {
+ rule.setContent {
+ Box(
+ modifier = Modifier.heightInLines(textStyle = TextStyle.Default, maxLines = 0)
+ )
+ }
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun minLines_greaterThan_maxLines_invalidValue() {
+ rule.setContent {
+ Box(
+ modifier = Modifier.heightInLines(
+ textStyle = TextStyle.Default,
+ minLines = 2,
+ maxLines = 1
+ )
+ )
+ }
+ }
+
+ @Test
+ fun minLines_longInputText() {
+ val (textLayoutResult, height) = setTextFieldWithMaxLines(
+ text = longText,
+ MultiLine(minHeightInLines = 2)
+ )
+
+ rule.runOnIdle {
+ assertThat(textLayoutResult).isNotNull()
+ // should be in the 20s, but use this to create invariant for the next assertion
+ assertThat(textLayoutResult!!.lineCount).isGreaterThan(2)
+ assertThat(textLayoutResult.size.height).isEqualTo(height)
+ }
+ }
+
+ @Test
+ fun maxLines_longInputText() {
+ var subjectLayout: TextLayoutResult? = null
+ var subjectHeight: Int? = null
+ var twoLineHeight: Int? = null
+ val positionedLatch = CountDownLatch(1)
+ val twoLinePositionedLatch = CountDownLatch(1)
+
+ rule.setContent {
+ HeightObservingText(
+ onGlobalHeightPositioned = {
+ subjectHeight = it
+ positionedLatch.countDown()
+ },
+ onTextLayoutResult = {
+ subjectLayout = it
+ },
+ text = longText,
+ lineLimits = MultiLine(maxHeightInLines = 2)
+ )
+ HeightObservingText(
+ onGlobalHeightPositioned = {
+ twoLineHeight = it
+ twoLinePositionedLatch.countDown()
+ },
+ onTextLayoutResult = {},
+ text = "1\n2",
+ lineLimits = MultiLine(maxHeightInLines = 2)
+ )
+ }
+ assertThat(positionedLatch.await(1, TimeUnit.SECONDS)).isTrue()
+ assertThat(twoLinePositionedLatch.await(1, TimeUnit.SECONDS)).isTrue()
+
+ rule.runOnIdle {
+ assertThat(subjectLayout).isNotNull()
+ // should be in the 20s, but use this to create invariant for the next assertion
+ assertThat(subjectLayout!!.lineCount).isGreaterThan(2)
+ assertThat(subjectHeight!!).isEqualTo(twoLineHeight)
+ }
+ }
+
+ @OptIn(ExperimentalTextApi::class, ExperimentalCoroutinesApi::class)
+ @Test
+ fun asyncFontLoad_changesLineHeight() {
+ val testDispatcher = UnconfinedTestDispatcher()
+ val resolver = createFontFamilyResolver(context, testDispatcher)
+
+ val typefaceDeferred = CompletableDeferred<Typeface>()
+ val asyncLoader = object : AndroidFont.TypefaceLoader {
+ override fun loadBlocking(context: Context, font: AndroidFont): Typeface =
+ TODO("Not yet implemented")
+
+ override suspend fun awaitLoad(context: Context, font: AndroidFont): Typeface {
+ return typefaceDeferred.await()
+ }
+ }
+ val fontFamily = FontFamily(
+ object : AndroidFont(FontLoadingStrategy.Async, asyncLoader, FontVariation.Settings()) {
+ override val weight: FontWeight = FontWeight.Normal
+ override val style: FontStyle = FontStyle.Normal
+ },
+ TEST_FONT
+ )
+
+ val heights = mutableListOf<Int>()
+
+ rule.setContent {
+ CompositionLocalProvider(
+ LocalFontFamilyResolver provides resolver,
+ LocalDensity provides Density(1.0f, 1f)
+ ) {
+ HeightObservingText(
+ onGlobalHeightPositioned = {
+ heights.add(it)
+ },
+ onTextLayoutResult = {},
+ text = longText,
+ lineLimits = MultiLine(maxHeightInLines = 10),
+ textStyle = TextStyle.Default.copy(
+ fontFamily = fontFamily,
+ fontSize = 80.sp
+ )
+ )
+ }
+ }
+
+ val before = heights.toList()
+ typefaceDeferred.complete(Typeface.create("cursive", Typeface.BOLD_ITALIC))
+
+ rule.runOnIdle {
+ assertThat(heights.size).isGreaterThan(before.size)
+ assertThat(heights.distinct().size).isGreaterThan(before.distinct().size)
+ }
+ }
+
+ @Test
+ fun testInspectableValue() {
+ isDebugInspectorInfoEnabled = true
+
+ val modifier = Modifier.heightInLines(
+ textStyle = TextStyle.Default,
+ minLines = 5,
+ maxLines = 10
+ ) as InspectableValue
+ assertThat(modifier.nameFallback).isEqualTo("heightInLines")
+ assertThat(modifier.inspectableElements.asIterable()).containsExactly(
+ ValueElement("minLines", 5),
+ ValueElement("maxLines", 10),
+ ValueElement("textStyle", TextStyle.Default)
+ )
+
+ isDebugInspectorInfoEnabled = false
+ }
+
+ private fun setTextFieldWithMaxLines(
+ text: String,
+ lines: MultiLine
+ ): Pair<TextLayoutResult?, Int?> {
+ var textLayoutResult: TextLayoutResult? = null
+ var height: Int? = null
+ val positionedLatch = CountDownLatch(1)
+
+ rule.setContent {
+ HeightObservingText(
+ onGlobalHeightPositioned = {
+ height = it
+ positionedLatch.countDown()
+ },
+ onTextLayoutResult = {
+ textLayoutResult = it
+ },
+ text = text,
+ lineLimits = lines
+ )
+ }
+ assertThat(positionedLatch.await(1, TimeUnit.SECONDS)).isTrue()
+
+ return Pair(textLayoutResult, height)
+ }
+
+ @Composable
+ private fun HeightObservingText(
+ onGlobalHeightPositioned: (Int) -> Unit,
+ onTextLayoutResult: Density.(TextLayoutResult) -> Unit,
+ text: String,
+ lineLimits: MultiLine,
+ textStyle: TextStyle = TextStyle.Default
+ ) {
+ Box(
+ Modifier.onGloballyPositioned {
+ onGlobalHeightPositioned(it.size.height)
+ }
+ ) {
+ BasicTextField2(
+ state = remember { TextFieldState(text) },
+ textStyle = textStyle,
+ lineLimits = lineLimits,
+ modifier = Modifier.requiredWidth(100.dp),
+ onTextLayout = onTextLayoutResult
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCodepointTransformationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCodepointTransformationTest.kt
new file mode 100644
index 0000000..45f4155
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCodepointTransformationTest.kt
@@ -0,0 +1,218 @@
+/*
+ * 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
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.selection.fetchTextLayoutResult
+import androidx.compose.foundation.text2.input.CodepointTransformation
+import androidx.compose.foundation.text2.input.TextFieldLineLimits
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.mask
+import androidx.compose.foundation.text2.input.setTextAndPlaceCursorAtEnd
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performTextInput
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class TextFieldCodepointTransformationTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ private val Tag = "BasicTextField2"
+
+ @Test
+ fun textField_rendersTheResultOf_codepointTransformation() {
+ val state = TextFieldState()
+ state.setTextAndPlaceCursorAtEnd("Hello")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ codepointTransformation = { _, codepoint -> codepoint + 1 },
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ assertLayoutText("Ifmmp") // one character after in lexical order
+ }
+
+ @Test
+ fun textField_rendersTheResultOf_codepointTransformation_codepointIndex() {
+ val state = TextFieldState()
+ state.setTextAndPlaceCursorAtEnd("Hello")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ codepointTransformation = { index, codepoint ->
+ if (index % 2 == 0) codepoint + 1 else codepoint - 1
+ },
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ assertLayoutText("Idmkp") // one character after and before in lexical order
+ }
+
+ @Test
+ fun textField_toggleCodepointTransformation_affectsNextFrame() {
+ rule.mainClock.autoAdvance = false
+ val state = TextFieldState()
+ state.setTextAndPlaceCursorAtEnd("Hello")
+ var codepointTransformation by mutableStateOf(CodepointTransformation.None)
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ codepointTransformation = codepointTransformation,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ assertLayoutText("Hello") // no change
+ codepointTransformation = CodepointTransformation.mask('c')
+
+ rule.mainClock.advanceTimeByFrame()
+ assertLayoutText("ccccc") // all characters turn to c
+ }
+
+ @Test
+ fun textField_statefulCodepointTransformation_reactsToStateChange() {
+ val state = TextFieldState()
+ state.setTextAndPlaceCursorAtEnd("Hello")
+ var mask by mutableStateOf('-')
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ codepointTransformation = CodepointTransformation.mask(mask),
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ assertLayoutText("-----")
+ mask = '@'
+
+ rule.waitForIdle()
+ assertLayoutText("@@@@@")
+ }
+
+ @Test
+ fun textField_removingCodepointTransformation_rendersTextNormally() {
+ val state = TextFieldState()
+ state.setTextAndPlaceCursorAtEnd("Hello")
+ var codepointTransformation by mutableStateOf<CodepointTransformation?>(
+ CodepointTransformation.mask('*')
+ )
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ codepointTransformation = codepointTransformation,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ assertLayoutText("*****")
+ codepointTransformation = null
+
+ rule.waitForIdle()
+ assertLayoutText("Hello")
+ }
+
+ @Test
+ fun textField_codepointTransformation_continuesToRenderUpdatedText() {
+ val state = TextFieldState()
+ state.setTextAndPlaceCursorAtEnd("Hello")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ codepointTransformation = CodepointTransformation.mask('*'),
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ assertLayoutText("*****")
+ rule.waitForIdle()
+ rule.onNodeWithTag(Tag).performTextInput(", World!")
+ assertLayoutText("*".repeat("Hello, World!".length))
+ }
+
+ @Test
+ fun textField_singleLine_removesLineFeedViaCodepointTransformation() {
+ val state = TextFieldState()
+ state.setTextAndPlaceCursorAtEnd("Hello\nWorld")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ lineLimits = TextFieldLineLimits.SingleLine,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ assertLayoutText("Hello World")
+ rule.onNodeWithTag(Tag).performTextInput("\n")
+ assertLayoutText("Hello World ")
+ }
+
+ @Test
+ fun textField_singleLine_removesCarriageReturnViaCodepointTransformation() {
+ val state = TextFieldState()
+ state.setTextAndPlaceCursorAtEnd("Hello\rWorld")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ lineLimits = TextFieldLineLimits.SingleLine,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ assertLayoutText("Hello\uFEFFWorld")
+ }
+
+ @Test
+ fun textField_singleLine_doesNotOverrideGivenCodepointTransformation() {
+ val state = TextFieldState()
+ state.setTextAndPlaceCursorAtEnd("Hello\nWorld")
+ rule.setContent {
+ BasicTextField2(
+ state = state,
+ lineLimits = TextFieldLineLimits.SingleLine,
+ codepointTransformation = CodepointTransformation.None,
+ modifier = Modifier.testTag(Tag)
+ )
+ }
+
+ assertLayoutText("Hello\nWorld")
+ }
+
+ // TODO: add more tests when selection is added
+
+ private fun assertLayoutText(text: String) {
+ assertThat(rule.onNodeWithTag(Tag).fetchTextLayoutResult().layoutInput.text.text)
+ .isEqualTo(text)
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCursorTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCursorTest.kt
new file mode 100644
index 0000000..b615766
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCursorTest.kt
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2
+
+import android.os.Build
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.text.TEST_FONT_FAMILY
+import androidx.compose.foundation.text.selection.LocalTextSelectionColors
+import androidx.compose.foundation.text.selection.TextSelectionColors
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.testutils.assertDoesNotContainColor
+import androidx.compose.testutils.assertPixelColor
+import androidx.compose.testutils.assertPixels
+import androidx.compose.testutils.assertShape
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.MotionDurationScale
+import androidx.compose.ui.focus.onFocusChanged
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.toPixelMap
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.assertTextEquals
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.hasSetTextAction
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.performTextInput
+import androidx.compose.ui.test.performTextInputSelection
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.TextStyle
+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.sp
+import androidx.compose.ui.unit.toOffset
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import com.google.common.truth.Truth.assertThat
+import kotlin.math.ceil
+import kotlin.math.floor
+import org.junit.Rule
+import org.junit.Test
+
+@OptIn(ExperimentalFoundationApi::class, ExperimentalTestApi::class)
+@LargeTest
+class TextFieldCursorTest {
+
+ private val motionDurationScale = object : MotionDurationScale {
+ override var scaleFactor: Float by mutableStateOf(1f)
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @get:Rule
+ val rule = createComposeRule(effectContext = motionDurationScale).also {
+ it.mainClock.autoAdvance = false
+ }
+
+ private lateinit var state: TextFieldState
+
+ private val boxPadding = 8.dp
+ // Both TextField background and font color should be the same to make sure that only
+ // cursor is visible
+ private val contentColor = Color.White
+ private val cursorColor = Color.Red
+ private val textStyle = TextStyle(
+ color = contentColor,
+ background = contentColor,
+ fontSize = 10.sp,
+ fontFamily = TEST_FONT_FAMILY
+ )
+
+ private var isFocused = false
+ private var textLayoutResult: TextLayoutResult? = null
+ private val cursorRect: Rect
+ // assume selection is collapsed
+ get() = textLayoutResult?.getCursorRect(state.text.selectionInChars.start) ?: Rect.Zero
+
+ private val backgroundModifier = Modifier.background(contentColor)
+ private val focusModifier = Modifier.onFocusChanged { if (it.isFocused) isFocused = true }
+
+ // default TextFieldModifier
+ private val textFieldModifier = Modifier
+ .then(backgroundModifier)
+ .then(focusModifier)
+
+ // default onTextLayout to capture cursor boundaries.
+ private val onTextLayout: Density.(TextLayoutResult) -> Unit = { textLayoutResult = it }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun textFieldFocused_cursorRendered() {
+ state = TextFieldState()
+ rule.setContent {
+ Box(Modifier.padding(boxPadding)) {
+ BasicTextField2(
+ state = state,
+ textStyle = textStyle,
+ modifier = textFieldModifier,
+ cursorBrush = SolidColor(cursorColor),
+ onTextLayout = onTextLayout
+ )
+ }
+ }
+
+ focusAndWait()
+
+ rule.mainClock.advanceTimeBy(100)
+
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertCursor(2.dp, cursorRect)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun textFieldFocused_cursorWithBrush() {
+ state = TextFieldState()
+ rule.setContent {
+ Box(Modifier.padding(boxPadding)) {
+ BasicTextField2(
+ state = state,
+ textStyle = textStyle.copy(fontSize = textStyle.fontSize * 2),
+ modifier = Modifier
+ .then(backgroundModifier)
+ .then(focusModifier),
+ cursorBrush = Brush.verticalGradient(
+ // make a brush double/triple color at the beginning and end so we have
+ // stable colors at the ends.
+ // Without triple bottom, the bottom color never hits to the provided color.
+ listOf(
+ Color.Blue,
+ Color.Blue,
+ Color.Green,
+ Color.Green,
+ Color.Green
+ )
+ ),
+ onTextLayout = onTextLayout
+ )
+ }
+ }
+
+ focusAndWait()
+
+ rule.mainClock.advanceTimeBy(100)
+
+ val bitmap = rule.onNode(hasSetTextAction())
+ .captureToImage().toPixelMap()
+
+ val cursorLeft = ceil(cursorRect.left).toInt() + 1
+ val cursorTop = ceil(cursorRect.top).toInt() + 1
+ val cursorBottom = floor(cursorRect.bottom).toInt() - 1
+ bitmap.assertPixelColor(Color.Blue, x = cursorLeft, y = cursorTop)
+ bitmap.assertPixelColor(Color.Green, x = cursorLeft, y = cursorBottom)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun cursorBlinkingAnimation() {
+ state = TextFieldState()
+ rule.setContent {
+ // The padding helps if the test is run accidentally in landscape. Landscape makes
+ // the cursor to be next to the navigation bar which affects the red color to be a bit
+ // different - possibly anti-aliasing.
+ Box(Modifier.padding(boxPadding)) {
+ BasicTextField2(
+ state = state,
+ textStyle = textStyle,
+ modifier = textFieldModifier,
+ cursorBrush = SolidColor(cursorColor),
+ onTextLayout = onTextLayout
+ )
+ }
+ }
+
+ focusAndWait()
+
+ // cursor visible first 500 ms
+ rule.mainClock.advanceTimeBy(100)
+ with(rule.density) {
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertCursor(2.dp, cursorRect)
+ }
+
+ // cursor invisible during next 500 ms
+ rule.mainClock.advanceTimeBy(700)
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertShape(
+ density = rule.density,
+ shape = RectangleShape,
+ shapeColor = contentColor,
+ backgroundColor = contentColor,
+ shapeOverlapPixelCount = 0.0f
+ )
+ }
+
+ @Suppress("UnnecessaryOptInAnnotation")
+ @OptIn(ExperimentalTestApi::class)
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun cursorBlinkingAnimation_whenSystemDisablesAnimations() {
+ motionDurationScale.scaleFactor = 0f
+ state = TextFieldState()
+
+ rule.setContent {
+ // The padding helps if the test is run accidentally in landscape. Landscape makes
+ // the cursor to be next to the navigation bar which affects the red color to be a bit
+ // different - possibly anti-aliasing.
+ Box(Modifier.padding(boxPadding)) {
+ BasicTextField2(
+ state = state,
+ textStyle = textStyle,
+ modifier = textFieldModifier,
+ cursorBrush = SolidColor(cursorColor),
+ onTextLayout = onTextLayout
+ )
+ }
+ }
+
+ focusAndWait()
+
+ // cursor visible first 500 ms
+ rule.mainClock.advanceTimeBy(100)
+ with(rule.density) {
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertCursor(2.dp, cursorRect)
+ }
+
+ // cursor invisible during next 500 ms
+ rule.mainClock.advanceTimeBy(700)
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertShape(
+ density = rule.density,
+ shape = RectangleShape,
+ shapeColor = contentColor,
+ backgroundColor = contentColor,
+ shapeOverlapPixelCount = 0.0f
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun cursorUnsetColor_noCursor() {
+ state = TextFieldState("hello", initialSelectionInChars = TextRange(2))
+ rule.setContent {
+ // The padding helps if the test is run accidentally in landscape. Landscape makes
+ // the cursor to be next to the navigation bar which affects the red color to be a bit
+ // different - possibly anti-aliasing.
+ Box(Modifier.padding(boxPadding)) {
+ BasicTextField2(
+ state = state,
+ textStyle = textStyle,
+ modifier = textFieldModifier,
+ cursorBrush = SolidColor(Color.Unspecified)
+ )
+ }
+ }
+
+ focusAndWait()
+
+ // no cursor when usually shown
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertShape(
+ density = rule.density,
+ shape = RectangleShape,
+ shapeColor = contentColor,
+ backgroundColor = contentColor,
+ shapeOverlapPixelCount = 0.0f
+ )
+
+ // no cursor when should be no cursor
+ rule.mainClock.advanceTimeBy(700)
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertShape(
+ density = rule.density,
+ shape = RectangleShape,
+ shapeColor = contentColor,
+ backgroundColor = contentColor,
+ shapeOverlapPixelCount = 0.0f
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun cursorNotBlinking_whileTyping() {
+ state = TextFieldState("test", initialSelectionInChars = TextRange(4))
+ rule.setContent {
+ // The padding helps if the test is run accidentally in landscape. Landscape makes
+ // the cursor to be next to the navigation bar which affects the red color to be a bit
+ // different - possibly anti-aliasing.
+ Box(Modifier.padding(boxPadding)) {
+ BasicTextField2(
+ state = state,
+ textStyle = textStyle,
+ modifier = textFieldModifier,
+ cursorBrush = SolidColor(cursorColor),
+ onTextLayout = onTextLayout
+ )
+ }
+ }
+
+ focusAndWait()
+
+ // cursor visible first 500 ms
+ rule.mainClock.advanceTimeBy(500)
+ // TODO(b/170298051) check here that cursor is visible when we have a way to control
+ // cursor position when sending a text
+
+ // change text field value
+ rule.onNode(hasSetTextAction())
+ .performTextInput("s")
+
+ // cursor would have been invisible during next 500 ms if cursor blinks while typing.
+ // To prevent blinking while typing we restart animation when new symbol is typed.
+ rule.mainClock.advanceTimeBy(300)
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertCursor(2.dp, cursorRect)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun selectionChanges_cursorNotBlinking() {
+ state = TextFieldState("test", initialSelectionInChars = TextRange(2))
+ rule.setContent {
+ // The padding helps if the test is run accidentally in landscape. Landscape makes
+ // the cursor to be next to the navigation bar which affects the red color to be a bit
+ // different - possibly anti-aliasing.
+ Box(Modifier.padding(boxPadding)) {
+ BasicTextField2(
+ state = state,
+ textStyle = textStyle,
+ modifier = textFieldModifier,
+ cursorBrush = SolidColor(cursorColor),
+ onTextLayout = onTextLayout
+ )
+ }
+ }
+
+ focusAndWait()
+
+ // hide the cursor
+ rule.mainClock.advanceTimeBy(500)
+ rule.mainClock.advanceTimeByFrame()
+
+ // TODO(b/170298051) check here that cursor is visible when we have a way to control
+ // cursor position when sending a text
+
+ rule.onNode(hasSetTextAction())
+ .performTextInputSelection(TextRange(0))
+
+ // necessary for animation to start (shows cursor again)
+ rule.mainClock.advanceTimeByFrame()
+
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertCursor(2.dp, cursorRect)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun brushChanged_doesntResetTimer() {
+ var cursorBrush by mutableStateOf(SolidColor(cursorColor))
+ state = TextFieldState()
+ rule.setContent {
+ Box(Modifier.padding(boxPadding)) {
+ BasicTextField2(
+ state = state,
+ textStyle = textStyle,
+ modifier = textFieldModifier,
+ cursorBrush = cursorBrush,
+ onTextLayout = onTextLayout
+ )
+ }
+ }
+
+ focusAndWait()
+
+ rule.mainClock.advanceTimeBy(800)
+ cursorBrush = SolidColor(Color.Green)
+ rule.mainClock.advanceTimeByFrame()
+
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertShape(
+ density = rule.density,
+ shape = RectangleShape,
+ shapeColor = contentColor,
+ backgroundColor = contentColor,
+ shapeOverlapPixelCount = 0.0f
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun selectionNotCollapsed_cursorNotDrawn() {
+ state = TextFieldState("test", initialSelectionInChars = TextRange(2, 3))
+ rule.setContent {
+ // The padding helps if the test is run accidentally in landscape. Landscape makes
+ // the cursor to be next to the navigation bar which affects the red color to be a bit
+ // different - possibly anti-aliasing.
+ Box(Modifier.padding(boxPadding)) {
+ // set selection highlight to a known color
+ CompositionLocalProvider(
+ LocalTextSelectionColors provides TextSelectionColors(Color.Blue, Color.Blue)
+ ) {
+ BasicTextField2(
+ state = state,
+ // make sure that background is not obstructing selection
+ textStyle = textStyle.copy(
+ background = Color.Unspecified
+ ),
+ modifier = textFieldModifier,
+ cursorBrush = SolidColor(cursorColor),
+ onTextLayout = onTextLayout
+ )
+ }
+ }
+ }
+
+ focusAndWait()
+
+ // cursor should still be visible if there wasn't a selection
+ rule.mainClock.advanceTimeBy(300)
+ rule.mainClock.advanceTimeByFrame()
+
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertDoesNotContainColor(cursorColor)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun focusLost_cursorHidesImmediately() {
+ state = TextFieldState("test")
+ rule.setContent {
+ // The padding helps if the test is run accidentally in landscape. Landscape makes
+ // the cursor to be next to the navigation bar which affects the red color to be a bit
+ // different - possibly anti-aliasing.
+ Column(Modifier.padding(boxPadding)) {
+ BasicTextField2(
+ state = state,
+ // make sure that background is not obstructing selection
+ textStyle = textStyle,
+ modifier = textFieldModifier,
+ cursorBrush = SolidColor(cursorColor),
+ onTextLayout = onTextLayout
+ )
+ Box(modifier = Modifier
+ .focusable(true)
+ .testTag("box"))
+ }
+ }
+
+ focusAndWait()
+
+ rule.mainClock.advanceTimeBy(100)
+ rule.mainClock.advanceTimeByFrame()
+
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertCursor(2.dp, cursorRect)
+
+ rule.onNodeWithTag("box").performSemanticsAction(SemanticsActions.RequestFocus)
+ rule.mainClock.advanceTimeByFrame()
+
+ // cursor should hide immediately.
+ rule.onNode(hasSetTextAction())
+ .captureToImage()
+ .assertShape(
+ density = rule.density,
+ shape = RectangleShape,
+ shapeColor = contentColor,
+ backgroundColor = contentColor,
+ shapeOverlapPixelCount = 0.0f
+ )
+ }
+
+ private fun focusAndWait() {
+ rule.onNode(hasSetTextAction()).performClick()
+ rule.mainClock.advanceTimeUntil { isFocused }
+ }
+
+ private fun ImageBitmap.assertCursor(cursorWidth: Dp, cursorRect: Rect) {
+ assertThat(cursorRect.height).isNotEqualTo(0f)
+ assertThat(cursorRect).isNotEqualTo(Rect.Zero)
+ val cursorWidthPx = (with(rule.density) { cursorWidth.roundToPx() })
+
+ // assert cursor width is greater than 2 since we will shrink the check area by 1 on each
+ // side
+ assertThat(cursorWidthPx).isGreaterThan(2)
+
+ // shrink the check are by 1px for left, top, right, bottom
+ val checkRect = Rect(
+ ceil(cursorRect.left) + 1,
+ ceil(cursorRect.top) + 1,
+ floor(cursorRect.right) + cursorWidthPx - 1,
+ floor(cursorRect.bottom) - 1
+ )
+
+ // skip an expanded rectangle that is 1px larger than cursor rectangle due to antialiasing
+ val skipRect = Rect(
+ floor(cursorRect.left) - 1,
+ floor(cursorRect.top) - 1,
+ ceil(cursorRect.right) + cursorWidthPx + 1,
+ ceil(cursorRect.bottom) + 1
+ )
+
+ val width = width
+ val height = height
+ this.assertPixels(
+ IntSize(width, height)
+ ) { position ->
+ if (checkRect.contains(position.toOffset())) {
+ // cursor
+ cursorColor
+ } else if (skipRect.contains(position.toOffset())) {
+ // skip some pixels around cursor
+ null
+ } else {
+ // text field background
+ contentColor
+ }
+ }
+ }
+
+ @Test
+ fun textFieldCursor_alwaysReadLatestState_duringDraw() {
+ state = TextFieldState("hello world", TextRange(5))
+ rule.setContent {
+ Box(Modifier.padding(boxPadding)) {
+ BasicTextField2(
+ state = state,
+ textStyle = textStyle,
+ modifier = textFieldModifier.layout { measurable, constraints ->
+ // change the state during layout so draw can read the new state
+ val currValue = state.text
+ if (currValue.isNotEmpty()) {
+ val newText = currValue.dropLast(1)
+ val newValue =
+ TextFieldCharSequence(newText.toString(), TextRange(newText.length))
+ state.editProcessor.reset(newValue)
+ }
+
+ val p = measurable.measure(constraints)
+ layout(p.width, p.height) {
+ p.place(0, 0)
+ }
+ },
+ cursorBrush = SolidColor(cursorColor),
+ onTextLayout = onTextLayout
+ )
+ }
+ }
+
+ rule.waitForIdle()
+
+ rule.onNode(hasSetTextAction()).assertTextEquals("")
+ // this test just needs to finish without crashing. There is no other assertion
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldFocusTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldFocusTest.kt
new file mode 100644
index 0000000..d2186e6
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldFocusTest.kt
@@ -0,0 +1,493 @@
+package androidx.compose.foundation.text2
+
+import android.os.SystemClock
+import android.view.InputDevice
+import android.view.KeyEvent
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.border
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredWidth
+import androidx.compose.foundation.text.BasicText
+import androidx.compose.foundation.text.BasicTextField
+import androidx.compose.foundation.text.KeyboardHelper
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.LaunchedEffect
+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.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.focus.onFocusChanged
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.key.NativeKeyEvent
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.assertIsFocused
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performKeyPress
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class TextFieldFocusTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ private val keyboardHelper = KeyboardHelper(rule)
+
+ @Composable
+ private fun TextFieldApp(dataList: List<FocusTestData>) {
+ for (data in dataList) {
+ val state = remember { TextFieldState() }
+ BasicTextField2(
+ state = state,
+ modifier = Modifier
+ .focusRequester(data.focusRequester)
+ .onFocusChanged { data.focused = it.isFocused }
+ .requiredWidth(10.dp)
+ )
+ }
+ }
+
+ data class FocusTestData(val focusRequester: FocusRequester, var focused: Boolean = false)
+
+ @Test
+ fun requestFocus() {
+ lateinit var testDataList: List<FocusTestData>
+
+ rule.setContent {
+ testDataList = listOf(
+ FocusTestData(FocusRequester()),
+ FocusTestData(FocusRequester()),
+ FocusTestData(FocusRequester())
+ )
+
+ TextFieldApp(testDataList)
+ }
+
+ rule.runOnIdle { testDataList[0].focusRequester.requestFocus() }
+
+ rule.runOnIdle {
+ assertThat(testDataList[0].focused).isTrue()
+ assertThat(testDataList[1].focused).isFalse()
+ assertThat(testDataList[2].focused).isFalse()
+ }
+
+ rule.runOnIdle { testDataList[1].focusRequester.requestFocus() }
+ rule.runOnIdle {
+ assertThat(testDataList[0].focused).isFalse()
+ assertThat(testDataList[1].focused).isTrue()
+ assertThat(testDataList[2].focused).isFalse()
+ }
+
+ rule.runOnIdle { testDataList[2].focusRequester.requestFocus() }
+ rule.runOnIdle {
+ assertThat(testDataList[0].focused).isFalse()
+ assertThat(testDataList[1].focused).isFalse()
+ assertThat(testDataList[2].focused).isTrue()
+ }
+ }
+
+ @Test
+ fun noCrashWhenSwitchingBetweenEnabledFocusedAndDisabledTextField() {
+ val enabled = mutableStateOf(true)
+ var focused = false
+ val tag = "textField"
+ rule.setContent {
+ val state = remember { TextFieldState() }
+ BasicTextField2(
+ state = state,
+ enabled = enabled.value,
+ modifier = Modifier
+ .testTag(tag)
+ .onFocusChanged {
+ focused = it.isFocused
+ }
+ .requiredWidth(10.dp)
+ )
+ }
+ // bring enabled text field into focus
+ rule.onNodeWithTag(tag).performClick()
+ rule.runOnIdle {
+ assertThat(focused).isTrue()
+ }
+
+ // make text field disabled
+ enabled.value = false
+ rule.runOnIdle {
+ assertThat(focused).isFalse()
+ }
+
+ // make text field enabled again, it must not crash
+ enabled.value = true
+ rule.runOnIdle {
+ assertThat(focused).isFalse()
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = 22) // b/266742195
+ @Test
+ fun keyboardIsShown_forFieldInActivity_whenFocusRequestedImmediately_fromLaunchedEffect() {
+ keyboardIsShown_whenFocusRequestedImmediately_fromEffect(
+ runEffect = {
+ LaunchedEffect(Unit) {
+ it()
+ }
+ }
+ )
+ }
+
+ @SdkSuppress(minSdkVersion = 22) // b/266742195
+ @Test
+ fun keyboardIsShown_forFieldInActivity_whenFocusRequestedImmediately_fromDisposableEffect() {
+ keyboardIsShown_whenFocusRequestedImmediately_fromEffect(
+ runEffect = {
+ DisposableEffect(Unit) {
+ it()
+ onDispose {}
+ }
+ }
+ )
+ }
+
+ // TODO(b/229378542) We can't accurately detect IME visibility from dialogs before API 30 so
+ // this test can't assert.
+ @SdkSuppress(minSdkVersion = 30)
+ @Test
+ fun keyboardIsShown_forFieldInDialog_whenFocusRequestedImmediately_fromLaunchedEffect() {
+ keyboardIsShown_whenFocusRequestedImmediately_fromEffect(
+ runEffect = {
+ LaunchedEffect(Unit) {
+ it()
+ }
+ },
+ wrapContent = {
+ Dialog(onDismissRequest = {}, content = it)
+ }
+ )
+ }
+
+ // TODO(b/229378542) We can't accurately detect IME visibility from dialogs before API 30 so
+ // this test can't assert.
+ @SdkSuppress(minSdkVersion = 30)
+ @Test
+ fun keyboardIsShown_forFieldInDialog_whenFocusRequestedImmediately_fromDisposableEffect() {
+ keyboardIsShown_whenFocusRequestedImmediately_fromEffect(
+ runEffect = {
+ DisposableEffect(Unit) {
+ it()
+ onDispose {}
+ }
+ },
+ wrapContent = {
+ Dialog(onDismissRequest = {}, content = it)
+ }
+ )
+ }
+
+ private fun keyboardIsShown_whenFocusRequestedImmediately_fromEffect(
+ runEffect: @Composable (body: () -> Unit) -> Unit,
+ wrapContent: @Composable (@Composable () -> Unit) -> Unit = { it() }
+ ) {
+ val focusRequester = FocusRequester()
+ val keyboardHelper = KeyboardHelper(rule)
+
+ rule.setContent {
+ wrapContent {
+ keyboardHelper.initialize()
+
+ runEffect {
+ assertThat(keyboardHelper.isSoftwareKeyboardShown()).isFalse()
+ focusRequester.requestFocus()
+ }
+
+ BasicTextField(
+ value = "",
+ onValueChange = {},
+ modifier = Modifier.focusRequester(focusRequester)
+ )
+ }
+ }
+
+ keyboardHelper.waitForKeyboardVisibility(visible = true)
+
+ // Ensure the keyboard doesn't leak in to the next test. Can't do this at the start of the
+ // test since the KeyboardHelper won't be initialized until composition runs, and this test
+ // is checking behavior that all happens on the first frame.
+ keyboardHelper.hideKeyboard()
+ keyboardHelper.waitForKeyboardVisibility(visible = false)
+ }
+
+ @SdkSuppress(minSdkVersion = 22) // b/266742195
+ @Test
+ @Ignore // TODO(halilibo): reenable when dpad focus modifier does not use TextFieldState
+ fun basicTextField_checkFocusNavigation_onDPadLeft() {
+ setupAndEnableBasicTextField()
+ inputSingleLineTextInBasicTextField()
+
+ // Dismiss keyboard on back press
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_BACK)
+ rule.waitForIdle()
+
+ // Move focus to the focusable element on left
+ keyPressOnPhysicalKeyboard(rule, NativeKeyEvent.KEYCODE_DPAD_LEFT)
+
+ // Check if the element to the left of text field gains focus
+ rule.onNodeWithTag("test-button-left").assertIsFocused()
+ }
+
+ @SdkSuppress(minSdkVersion = 22) // b/266742195
+ @Test
+ @Ignore // TODO(halilibo): reenable when dpad focus modifier does not use TextFieldState
+ fun basicTextField_checkFocusNavigation_onDPadRight() {
+ setupAndEnableBasicTextField()
+ inputSingleLineTextInBasicTextField()
+
+ // Dismiss keyboard on back press
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_BACK)
+ rule.waitForIdle()
+
+ // Move focus to the focusable element on right
+ keyPressOnPhysicalKeyboard(rule, NativeKeyEvent.KEYCODE_DPAD_RIGHT)
+
+ // Check if the element to the right of text field gains focus
+ rule.onNodeWithTag("test-button-right").assertIsFocused()
+ }
+
+ @SdkSuppress(minSdkVersion = 22) // b/266742195
+ @Test
+ @Ignore // TODO(halilibo): reenable when dpad focus modifier does not use TextFieldState
+ fun basicTextField_checkFocusNavigation_onDPadUp() {
+ setupAndEnableBasicTextField()
+ inputMultilineTextInBasicTextField()
+
+ // Dismiss keyboard on back press
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_BACK)
+ rule.waitForIdle()
+
+ // Move focus to the focusable element on top
+ keyPressOnPhysicalKeyboard(rule, NativeKeyEvent.KEYCODE_DPAD_UP)
+
+ // Check if the element on the top of text field gains focus
+ rule.onNodeWithTag("test-button-top").assertIsFocused()
+ }
+
+ @SdkSuppress(minSdkVersion = 22) // b/266742195
+ @Test
+ @Ignore // TODO(halilibo): re-enable when dpad focus modifier does not use TextFieldState
+ fun basicTextField_checkFocusNavigation_onDPadDown() {
+ setupAndEnableBasicTextField()
+ inputMultilineTextInBasicTextField()
+
+ // Dismiss keyboard on back press
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_BACK)
+ rule.waitForIdle()
+
+ // Move focus to the focusable element on bottom
+ keyPressOnPhysicalKeyboard(rule, NativeKeyEvent.KEYCODE_DPAD_DOWN)
+
+ // Check if the element to the bottom of text field gains focus
+ rule.onNodeWithTag("test-button-bottom").assertIsFocused()
+ }
+
+ @Ignore // b/264919150
+ @Test
+ fun basicTextField_checkKeyboardShown_onDPadCenter() {
+ setupAndEnableBasicTextField()
+ inputSingleLineTextInBasicTextField()
+
+ // Dismiss keyboard on back press
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_BACK)
+ keyboardHelper.waitForKeyboardVisibility(false)
+ rule.runOnIdle {
+ assertThat(keyboardHelper.isSoftwareKeyboardShown()).isFalse()
+ }
+
+ // Check if keyboard is enabled on Dpad center key press
+ keyPressOnPhysicalKeyboard(rule, NativeKeyEvent.KEYCODE_DPAD_CENTER)
+ keyboardHelper.waitForKeyboardVisibility(true)
+ rule.runOnIdle {
+ assertThat(keyboardHelper.isSoftwareKeyboardShown()).isTrue()
+ }
+ }
+
+ @Test
+ fun basicTextField_handlesInvalidDevice() {
+ setupAndEnableBasicTextField()
+ inputSingleLineTextInBasicTextField()
+
+ // -2 shouldn't be a valid device – we verify this below by asserting the device in the
+ // event is actually null.
+ val invalidDeviceId = -2
+ val keyCode = NativeKeyEvent.KEYCODE_DPAD_CENTER
+ val keyEventDown = KeyEvent(
+ SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ KeyEvent.ACTION_DOWN, keyCode, 0, 0, invalidDeviceId, 0
+ )
+ assertThat(keyEventDown.device).isNull()
+ rule.onRoot().performKeyPress(androidx.compose.ui.input.key.KeyEvent(keyEventDown))
+ rule.waitForIdle()
+ val keyEventUp = KeyEvent(
+ SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ KeyEvent.ACTION_UP, keyCode, 0, 0, invalidDeviceId, 0
+ )
+ rule.onRoot().performKeyPress(androidx.compose.ui.input.key.KeyEvent(keyEventUp))
+ rule.waitForIdle()
+ }
+
+ private fun setupAndEnableBasicTextField() {
+ setupContent()
+
+ rule.onNodeWithTag("test-text-field-1").assertIsFocused()
+ }
+
+ private fun inputSingleLineTextInBasicTextField() {
+ // Input "abc"
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_A)
+ rule.waitForIdle()
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_B)
+ rule.waitForIdle()
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_C)
+ rule.waitForIdle()
+ }
+
+ private fun inputMultilineTextInBasicTextField() {
+ // Input "a\nb\nc"
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_A)
+ rule.waitForIdle()
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_ENTER)
+ rule.waitForIdle()
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_B)
+ rule.waitForIdle()
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_ENTER)
+ rule.waitForIdle()
+ keyPressOnVirtualKeyboard(NativeKeyEvent.KEYCODE_C)
+ rule.waitForIdle()
+ }
+
+ private fun setupContent() {
+ rule.setContent {
+ keyboardHelper.initialize()
+ Column() {
+ Row(horizontalArrangement = Arrangement.Center) {
+ TestFocusableElement(id = "top")
+ }
+ Row() {
+ TestFocusableElement(id = "left")
+ TestBasicTextField(id = "1", requestFocus = true)
+ TestFocusableElement(id = "right")
+ }
+ Row(horizontalArrangement = Arrangement.Center) {
+ TestFocusableElement(id = "bottom")
+ }
+ }
+ }
+ rule.waitForIdle()
+ }
+
+ @Composable
+ private fun TestFocusableElement(id: String) {
+ var isFocused by remember {
+ mutableStateOf(false)
+ }
+ BasicText(
+ text = "test-button-$id",
+ modifier = Modifier
+ .testTag("test-button-$id")
+ .padding(10.dp)
+ .onFocusChanged {
+ isFocused = it.hasFocus
+ }
+ .focusable()
+ .border(2.dp, if (isFocused) Color.Green else Color.Cyan)
+ )
+ }
+
+ @Composable
+ private fun TestBasicTextField(
+ id: String,
+ requestFocus: Boolean = false
+ ) {
+ var textInput by remember {
+ mutableStateOf("")
+ }
+ var isFocused by remember {
+ mutableStateOf(false)
+ }
+ val focusRequester = remember {
+ FocusRequester()
+ }
+ val modifier = if (requestFocus) Modifier.focusRequester(focusRequester) else Modifier
+
+ BasicTextField(
+ value = textInput,
+ onValueChange = {
+ textInput = it
+ },
+ modifier = modifier
+ .testTag("test-text-field-$id")
+ .padding(10.dp)
+ .onFocusChanged {
+ isFocused = it.isFocused || it.hasFocus
+ }
+ .border(2.dp, if (isFocused) Color.Red else Color.Transparent)
+ )
+
+ LaunchedEffect(requestFocus, focusRequester) {
+ if (requestFocus) focusRequester.requestFocus()
+ }
+ }
+
+ // Triggers a key press on the root node from a non-virtual device
+ private fun keyPressOnPhysicalKeyboard(
+ rule: ComposeContentTestRule,
+ keyCode: Int,
+ count: Int = 1
+ ) {
+ repeat(count) {
+ val deviceId = InputDevice.getDeviceIds().first { id ->
+ InputDevice.getDevice(id)?.isVirtual?.not() ?: false
+ }
+ val keyEventDown = KeyEvent(
+ SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ KeyEvent.ACTION_DOWN, keyCode, 0, 0, deviceId, 0
+ )
+ rule.onRoot().performKeyPress(androidx.compose.ui.input.key.KeyEvent(keyEventDown))
+ rule.waitForIdle()
+ val keyEventUp = KeyEvent(
+ SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ KeyEvent.ACTION_UP, keyCode, 0, 0, deviceId, 0
+ )
+ rule.onRoot().performKeyPress(androidx.compose.ui.input.key.KeyEvent(keyEventUp))
+ }
+ }
+
+ // Triggers a key press on the virtual keyboard
+ private fun keyPressOnVirtualKeyboard(keyCode: Int, count: Int = 1) {
+ repeat(count) {
+ InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode)
+ }
+ }
+}
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
new file mode 100644
index 0000000..d012665
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyEventTest.kt
@@ -0,0 +1,672 @@
+/*
+ * 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
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.text.TEST_FONT_FAMILY
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.platform.LocalClipboardManager
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.KeyInjectionScope
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.test.withKeyDown
+import androidx.compose.ui.test.withKeysDown
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(
+ ExperimentalFoundationApi::class,
+ ExperimentalTestApi::class
+)
+class TextFieldKeyEventTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ private val tag = "TextFieldTestTag"
+
+ private var defaultDensity = Density(1f)
+
+ @Test
+ fun textField_typedEvents() {
+ keysSequenceTest {
+ pressKey(Key.H)
+ press(Key.ShiftLeft + Key.I)
+ expectedText("hI")
+ }
+ }
+
+ @Ignore // re-enable after copy-cut-paste is supported
+ @Test
+ fun textField_copyPaste() {
+ keysSequenceTest("hello") {
+ withKeyDown(Key.CtrlLeft) {
+ pressKey(Key.A)
+ pressKey(Key.C)
+ }
+ pressKey(Key.DirectionRight)
+ pressKey(Key.Spacebar)
+ press(Key.CtrlLeft + Key.V)
+ expectedText("hello hello")
+ }
+ }
+
+ @Ignore // re-enable after copy-cut-paste is supported
+ @Test
+ fun textField_directCopyPaste() {
+ keysSequenceTest("hello") {
+ press(Key.CtrlLeft + Key.A)
+ pressKey(Key.Copy)
+ expectedText("hello")
+ pressKey(Key.DirectionRight)
+ pressKey(Key.Spacebar)
+ pressKey(Key.Paste)
+ expectedText("hello hello")
+ }
+ }
+
+ @Ignore // re-enable after copy-cut-paste is supported
+ @Test
+ fun textField_directCutPaste() {
+ keysSequenceTest("hello") {
+ press(Key.CtrlLeft + Key.A)
+ pressKey(Key.Cut)
+ expectedText("")
+ pressKey(Key.Paste)
+ expectedText("hello")
+ }
+ }
+
+ @Test
+ fun textField_linesNavigation() {
+ keysSequenceTest("hello\nworld") {
+ pressKey(Key.DirectionDown)
+ pressKey(Key.A)
+ pressKey(Key.DirectionUp)
+ pressKey(Key.A)
+ expectedText("haello\naworld")
+ pressKey(Key.DirectionUp)
+ pressKey(Key.A)
+ expectedText("ahaello\naworld")
+ }
+ }
+
+ @Test
+ fun textField_linesNavigation_cache() {
+ keysSequenceTest("hello\n\nworld") {
+ pressKey(Key.DirectionRight)
+ pressKey(Key.DirectionDown)
+ pressKey(Key.DirectionDown)
+ pressKey(Key.Zero)
+ expectedText("hello\n\nw0orld")
+ }
+ }
+
+ @Test
+ fun textField_newLine() {
+ keysSequenceTest("hello") {
+ pressKey(Key.Enter)
+ expectedText("\nhello")
+ }
+ }
+
+ @Test
+ fun textField_backspace() {
+ keysSequenceTest("hello") {
+ pressKey(Key.DirectionRight)
+ pressKey(Key.DirectionRight)
+ pressKey(Key.Backspace)
+ expectedText("hllo")
+ }
+ }
+
+ @Test
+ fun textField_delete() {
+ keysSequenceTest("hello") {
+ pressKey(Key.Delete)
+ expectedText("ello")
+ }
+ }
+
+ @Test
+ fun textField_delete_atEnd() {
+ keysSequenceTest("hello", TextRange(5)) {
+ pressKey(Key.Delete)
+ expectedText("hello")
+ }
+ }
+
+ @Test
+ fun textField_delete_whenEmpty() {
+ keysSequenceTest {
+ pressKey(Key.Delete)
+ expectedText("")
+ }
+ }
+
+ @Test
+ fun textField_nextWord() {
+ keysSequenceTest("hello world") {
+ press(Key.CtrlLeft + Key.DirectionRight)
+ pressKey(Key.Zero)
+ expectedText("hello0 world")
+ press(Key.CtrlLeft + Key.DirectionRight)
+ pressKey(Key.Zero)
+ expectedText("hello0 world0")
+ }
+ }
+
+ @Test
+ fun textField_nextWord_doubleSpace() {
+ keysSequenceTest("hello world") {
+ press(Key.CtrlLeft + Key.DirectionRight)
+ pressKey(Key.DirectionRight)
+ press(Key.CtrlLeft + Key.DirectionRight)
+ pressKey(Key.Zero)
+ expectedText("hello world0")
+ }
+ }
+
+ @Test
+ fun textField_prevWord() {
+ keysSequenceTest("hello world") {
+ withKeyDown(Key.CtrlLeft) {
+ pressKey(Key.DirectionRight)
+ pressKey(Key.DirectionRight)
+ pressKey(Key.DirectionLeft)
+ }
+ pressKey(Key.Zero)
+ expectedText("hello 0world")
+ }
+ }
+
+ @Test
+ fun textField_HomeAndEnd() {
+ keysSequenceTest("hello world") {
+ pressKey(Key.MoveEnd)
+ pressKey(Key.Zero)
+ pressKey(Key.MoveHome)
+ pressKey(Key.Zero)
+ expectedText("0hello world0")
+ }
+ }
+
+ @Test
+ fun textField_byWordSelection() {
+ keysSequenceTest("hello world\nhi") {
+ withKeysDown(listOf(Key.ShiftLeft, Key.CtrlLeft)) {
+ pressKey(Key.DirectionRight)
+ expectedSelection(TextRange(0, 5))
+ pressKey(Key.DirectionRight)
+ expectedSelection(TextRange(0, 12))
+ pressKey(Key.DirectionRight)
+ expectedSelection(TextRange(0, 15))
+ pressKey(Key.DirectionLeft)
+ expectedSelection(TextRange(0, 13))
+ }
+ }
+ }
+
+ @Ignore // TODO(halilibo): Remove ignore when backing buffer supports reversed selection
+ @Test
+ fun textField_lineEndStart() {
+ keysSequenceTest(initText = "hi\nhello world\nhi") {
+ pressKey(Key.MoveEnd)
+ pressKey(Key.DirectionRight)
+ pressKey(Key.Zero)
+ expectedText("hi\n0hello world\nhi")
+ pressKey(Key.MoveEnd)
+ pressKey(Key.Zero)
+ expectedText("hi\n0hello world0\nhi")
+ withKeyDown(Key.ShiftLeft) { pressKey(Key.MoveHome) }
+ expectedSelection(TextRange(16, 3))
+ pressKey(Key.MoveHome)
+ pressKey(Key.DirectionRight)
+ withKeyDown(Key.ShiftLeft) { pressKey(Key.MoveEnd) }
+ expectedSelection(TextRange(4, 16))
+ expectedText("hi\n0hello world0\nhi")
+ }
+ }
+
+ @Ignore // TODO(halilibo): Remove ignore when backing buffer supports reversed selection
+ @Test
+ fun textField_altLineLeftRight() {
+ keysSequenceTest(initText = "hi\nhello world\nhi") {
+ withKeyDown(Key.AltLeft) { pressKey(Key.DirectionRight) }
+ pressKey(Key.DirectionRight)
+ pressKey(Key.Zero)
+ expectedText("hi\n0hello world\nhi")
+ withKeyDown(Key.AltLeft) { pressKey(Key.DirectionRight) }
+ pressKey(Key.Zero)
+ expectedText("hi\n0hello world0\nhi")
+ withKeysDown(listOf(Key.ShiftLeft, Key.AltLeft)) { pressKey(Key.DirectionLeft) }
+ expectedSelection(TextRange(16, 3))
+ withKeyDown(Key.AltLeft) { pressKey(Key.DirectionLeft) }
+ pressKey(Key.DirectionRight)
+ withKeysDown(listOf(Key.ShiftLeft, Key.AltLeft)) { pressKey(Key.DirectionRight) }
+ expectedSelection(TextRange(4, 16))
+ expectedText("hi\n0hello world0\nhi")
+ }
+ }
+
+ @Ignore // TODO(halilibo): Remove ignore when backing buffer supports reversed selection
+ @Test
+ fun textField_altTop() {
+ keysSequenceTest(initText = "hi\nhello world\nhi") {
+ pressKey(Key.MoveEnd)
+ repeat(3) { pressKey(Key.DirectionRight) }
+ pressKey(Key.Zero)
+ expectedText("hi\nhe0llo world\nhi")
+ withKeyDown(Key.AltLeft) { pressKey(Key.DirectionUp) }
+ pressKey(Key.Zero)
+ expectedText("0hi\nhe0llo world\nhi")
+ pressKey(Key.MoveEnd)
+ repeat(3) { pressKey(Key.DirectionRight) }
+ withKeysDown(listOf(Key.ShiftLeft, Key.AltLeft)) { pressKey(Key.DirectionUp) }
+ expectedSelection(TextRange(6, 0))
+ expectedText("0hi\nhe0llo world\nhi")
+ }
+ }
+
+ @Test
+ fun textField_altBottom() {
+ keysSequenceTest(initText = "hi\nhello world\nhi") {
+ pressKey(Key.MoveEnd)
+ repeat(3) { pressKey(Key.DirectionRight) }
+ pressKey(Key.Zero)
+ expectedText("hi\nhe0llo world\nhi")
+ withKeysDown(listOf(Key.ShiftLeft, Key.AltLeft)) { pressKey(Key.DirectionDown) }
+ expectedSelection(TextRange(6, 18))
+ pressKey(Key.DirectionLeft)
+ pressKey(Key.Zero)
+ expectedText("hi\nhe00llo world\nhi")
+ withKeyDown(Key.AltLeft) { pressKey(Key.DirectionDown) }
+ pressKey(Key.Zero)
+ expectedText("hi\nhe00llo world\nhi0")
+ }
+ }
+
+ @Test
+ fun textField_deleteWords() {
+ keysSequenceTest("hello world\nhi world") {
+ pressKey(Key.MoveEnd)
+ withKeyDown(Key.CtrlLeft) {
+ pressKey(Key.Backspace)
+ expectedText("hello \nhi world")
+ pressKey(Key.Delete)
+ }
+ expectedText("hello world")
+ }
+ }
+
+ @Test
+ fun textField_deleteToBeginningOfLine() {
+ keysSequenceTest("hello world\nhi world") {
+ press(Key.CtrlLeft + Key.DirectionRight)
+
+ withKeyDown(Key.AltLeft) {
+ pressKey(Key.Backspace)
+ expectedText(" world\nhi world")
+ pressKey(Key.Backspace)
+ expectedText(" world\nhi world")
+ }
+
+ repeat(3) { pressKey(Key.DirectionRight) }
+
+ press(Key.AltLeft + Key.Backspace)
+ expectedText("rld\nhi world")
+ pressKey(Key.DirectionDown)
+ pressKey(Key.MoveEnd)
+
+ withKeyDown(Key.AltLeft) {
+ pressKey(Key.Backspace)
+ expectedText("rld\n")
+ pressKey(Key.Backspace)
+ expectedText("rld\n")
+ }
+ }
+ }
+
+ @Test
+ fun textField_deleteToEndOfLine() {
+ keysSequenceTest("hello world\nhi world") {
+ press(Key.CtrlLeft + Key.DirectionRight)
+ withKeyDown(Key.AltLeft) {
+ pressKey(Key.Delete)
+ expectedText("hello\nhi world")
+ pressKey(Key.Delete)
+ expectedText("hello\nhi world")
+ }
+
+ repeat(3) { pressKey(Key.DirectionRight) }
+
+ press(Key.AltLeft + Key.Delete)
+ expectedText("hello\nhi")
+
+ pressKey(Key.MoveHome)
+ withKeyDown(Key.AltLeft) {
+ pressKey(Key.Delete)
+ expectedText("hello\n")
+ pressKey(Key.Delete)
+ expectedText("hello\n")
+ }
+ }
+ }
+
+ @Test
+ fun textField_paragraphNavigation() {
+ keysSequenceTest("hello world\nhi") {
+ press(Key.CtrlLeft + Key.DirectionDown)
+ pressKey(Key.Zero)
+ expectedText("hello world0\nhi")
+ withKeyDown(Key.CtrlLeft) {
+ pressKey(Key.DirectionDown)
+ pressKey(Key.DirectionUp)
+ }
+ pressKey(Key.Zero)
+ expectedText("hello world0\n0hi")
+ }
+ }
+
+ @Ignore // TODO(halilibo): Remove ignore when backing buffer supports reversed selection
+ @Test
+ fun textField_selectionCaret() {
+ keysSequenceTest("hello world") {
+ press(Key.CtrlLeft + Key.ShiftLeft + Key.DirectionRight)
+ expectedSelection(TextRange(0, 5))
+ press(Key.ShiftLeft + Key.DirectionRight)
+ expectedSelection(TextRange(0, 6))
+ press(Key.CtrlLeft + Key.Backslash)
+ expectedSelection(TextRange(6, 6))
+ press(Key.CtrlLeft + Key.ShiftLeft + Key.DirectionLeft)
+ expectedSelection(TextRange(6, 0))
+ press(Key.ShiftLeft + Key.DirectionRight)
+ expectedSelection(TextRange(1, 6))
+ }
+ }
+
+ @Test
+ fun textField_pageNavigationDown() {
+ keysSequenceTest(
+ initText = "A\nB\nC\nD\nE",
+ modifier = Modifier.requiredSize(73.dp)
+ ) {
+ pressKey(Key.PageDown)
+ expectedSelection(TextRange(4))
+ }
+ }
+
+ @Test
+ fun textField_pageNavigationDown_exactFit() {
+ keysSequenceTest(
+ initText = "A\nB\nC\nD\nE",
+ modifier = Modifier.requiredSize(90.dp) // exactly 3 lines fit
+ ) {
+ pressKey(Key.PageDown)
+ expectedSelection(TextRange(6))
+ }
+ }
+
+ @Test
+ fun textField_pageNavigationUp() {
+ keysSequenceTest(
+ initText = "A\nB\nC\nD\nE",
+ initSelection = TextRange(8), // just before 5
+ modifier = Modifier.requiredSize(73.dp)
+ ) {
+ pressKey(Key.PageUp)
+ expectedSelection(TextRange(4))
+ }
+ }
+
+ @Test
+ fun textField_pageNavigationUp_exactFit() {
+ keysSequenceTest(
+ initText = "A\nB\nC\nD\nE",
+ initSelection = TextRange(8), // just before 5
+ modifier = Modifier.requiredSize(90.dp) // exactly 3 lines fit
+ ) {
+ pressKey(Key.PageUp)
+ expectedSelection(TextRange(2))
+ }
+ }
+
+ @Test
+ fun textField_pageNavigationUp_cantGoUp() {
+ keysSequenceTest(
+ initText = "1\n2\n3\n4\n5",
+ initSelection = TextRange(0),
+ modifier = Modifier.requiredSize(90.dp)
+ ) {
+ pressKey(Key.PageUp)
+ expectedSelection(TextRange(0))
+ }
+ }
+
+ @Test
+ fun textField_tabSingleLine() {
+ keysSequenceTest("text", singleLine = true) {
+ pressKey(Key.Tab)
+ expectedText("text") // no change, should try focus change instead
+ }
+ }
+
+ @Test
+ fun textField_tabMultiLine() {
+ keysSequenceTest("text") {
+ pressKey(Key.Tab)
+ expectedText("\ttext")
+ }
+ }
+
+ @Test
+ fun textField_shiftTabSingleLine() {
+ keysSequenceTest("text", singleLine = true) {
+ press(Key.ShiftLeft + Key.Tab)
+ expectedText("text") // no change, should try focus change instead
+ }
+ }
+
+ @Test
+ fun textField_enterSingleLine() {
+ keysSequenceTest("text", singleLine = true) {
+ pressKey(Key.Enter)
+ expectedText("text") // no change, should do ime action instead
+ }
+ }
+
+ @Test
+ fun textField_enterMultiLine() {
+ keysSequenceTest("text") {
+ pressKey(Key.Enter)
+ expectedText("\ntext")
+ }
+ }
+
+ @Test
+ fun textField_withActiveSelection_tabSingleLine() {
+ keysSequenceTest("text", singleLine = true) {
+ pressKey(Key.DirectionRight)
+ withKeyDown(Key.ShiftLeft) {
+ pressKey(Key.DirectionRight)
+ pressKey(Key.DirectionRight)
+ }
+ pressKey(Key.Tab)
+ expectedText("text") // no change, should try focus change instead
+ }
+ }
+
+ @Test
+ fun textField_withActiveSelection_tabMultiLine() {
+ keysSequenceTest("text") {
+ pressKey(Key.DirectionRight)
+ withKeyDown(Key.ShiftLeft) {
+ pressKey(Key.DirectionRight)
+ pressKey(Key.DirectionRight)
+ }
+ pressKey(Key.Tab)
+ expectedText("t\tt")
+ }
+ }
+
+ @Ignore // TODO(halilibo): Remove ignore when backing buffer supports reversed selection
+ @Test
+ fun textField_selectToLeft() {
+ keysSequenceTest("hello world hello") {
+ pressKey(Key.MoveEnd)
+ expectedSelection(TextRange(17))
+ withKeyDown(Key.ShiftLeft) {
+ pressKey(Key.DirectionLeft)
+ pressKey(Key.DirectionLeft)
+ pressKey(Key.DirectionLeft)
+ }
+ expectedSelection(TextRange(17, 14))
+ }
+ }
+
+ @Test
+ fun textField_withActiveSelection_shiftTabSingleLine() {
+ keysSequenceTest("text", singleLine = true) {
+ pressKey(Key.DirectionRight)
+ withKeyDown(Key.ShiftLeft) {
+ pressKey(Key.DirectionRight)
+ pressKey(Key.DirectionRight)
+ pressKey(Key.Tab)
+ }
+ expectedText("text") // no change, should try focus change instead
+ }
+ }
+
+ @Test
+ fun textField_withActiveSelection_enterSingleLine() {
+ keysSequenceTest("text", singleLine = true) {
+ pressKey(Key.DirectionRight)
+ withKeyDown(Key.ShiftLeft) {
+ pressKey(Key.DirectionRight)
+ pressKey(Key.DirectionRight)
+ }
+ pressKey(Key.Enter)
+ expectedText("text") // no change, should do ime action instead
+ }
+ }
+
+ @Test
+ fun textField_withActiveSelection_enterMultiLine() {
+ keysSequenceTest("text") {
+ pressKey(Key.DirectionRight)
+ withKeyDown(Key.ShiftLeft) {
+ pressKey(Key.DirectionRight)
+ pressKey(Key.DirectionRight)
+ }
+ pressKey(Key.Enter)
+ expectedText("t\nt")
+ }
+ }
+
+ private inner class SequenceScope(
+ val state: TextFieldState,
+ private val keyInjectionScope: KeyInjectionScope
+ ) : KeyInjectionScope by keyInjectionScope {
+
+ fun press(keys: List<Key>) {
+ require(keys.isNotEmpty()) { "At least one key must be specified for press action" }
+ if (keys.size == 1) {
+ pressKey(keys.first())
+ } else {
+ withKeysDown(keys.dropLast(1)) { pressKey(keys.last()) }
+ }
+ }
+
+ infix operator fun Key.plus(other: Key): MutableList<Key> {
+ return mutableListOf(this, other)
+ }
+
+ fun expectedText(text: String) {
+ rule.runOnIdle {
+ assertThat(state.text.toString()).isEqualTo(text)
+ }
+ }
+
+ fun expectedSelection(selection: TextRange) {
+ rule.runOnIdle {
+ assertThat(state.text.selectionInChars).isEqualTo(selection)
+ }
+ }
+ }
+
+ private fun keysSequenceTest(
+ initText: String = "",
+ initSelection: TextRange = TextRange.Zero,
+ modifier: Modifier = Modifier.fillMaxSize(),
+ singleLine: Boolean = false,
+ sequence: SequenceScope.() -> Unit,
+ ) {
+ val state = TextFieldState(initText, initSelection)
+ val focusRequester = FocusRequester()
+ rule.setContent {
+ LocalClipboardManager.current.setText(AnnotatedString("InitialTestText"))
+ CompositionLocalProvider(LocalDensity provides defaultDensity) {
+ BasicTextField2(
+ state = state,
+ textStyle = TextStyle(
+ fontFamily = TEST_FONT_FAMILY,
+ fontSize = 30.sp
+ ),
+ modifier = modifier
+ .focusRequester(focusRequester)
+ .testTag(tag),
+ lineLimits = if (singleLine) SingleLine else MultiLine(),
+ )
+ }
+ }
+
+ rule.runOnIdle { focusRequester.requestFocus() }
+
+ rule.waitForIdle()
+ rule.mainClock.advanceTimeBy(1000)
+
+ rule.onNodeWithTag(tag).performKeyInput {
+ sequence(SequenceScope(state, this@performKeyInput))
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyboardActionsTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyboardActionsTest.kt
new file mode 100644
index 0000000..863924f
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyboardActionsTest.kt
@@ -0,0 +1,428 @@
+/*
+ * 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
+
+import android.view.inputmethod.EditorInfo
+import android.view.inputmethod.InputConnection
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.text.KeyboardActionScope
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardHelper
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.internal.AndroidTextInputAdapter
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.assertIsFocused
+import androidx.compose.ui.test.assertIsNotFocused
+import androidx.compose.ui.test.hasSetTextAction
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performImeAction
+import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class TextFieldKeyboardActionsTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ private val keyboardHelper = KeyboardHelper(rule)
+
+ @Test
+ fun textField_performsImeAction_viaSemantics() {
+ var called = false
+ rule.setContent {
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Send),
+ keyboardActions = KeyboardActions {
+ called = true
+ }
+ )
+ }
+
+ rule.onNode(hasSetTextAction()).performImeAction()
+
+ assertThat(called).isTrue()
+ }
+
+ @Test
+ fun textField_performsImeAction_viaInputConnection() {
+ var called = false
+ var inputConnection: InputConnection? = null
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+ rule.setContent {
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Send),
+ keyboardActions = KeyboardActions {
+ called = true
+ }
+ )
+ }
+
+ rule.onNode(hasSetTextAction()).performSemanticsAction(SemanticsActions.RequestFocus)
+
+ rule.runOnIdle {
+ inputConnection?.performEditorAction(EditorInfo.IME_ACTION_SEND)
+ assertThat(called).isTrue()
+ }
+ }
+
+ @Test
+ fun textField_performsUnexpectedImeAction_fromInputConnection() {
+ var calledFor: ImeAction? = null
+ var inputConnection: InputConnection? = null
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+ rule.setContent {
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Send),
+ keyboardActions = KeyboardActionsAll {
+ calledFor = it
+ }
+ )
+ }
+
+ rule.onNode(hasSetTextAction()).performSemanticsAction(SemanticsActions.RequestFocus)
+
+ rule.runOnIdle {
+ inputConnection?.performEditorAction(EditorInfo.IME_ACTION_SEARCH)
+ assertThat(calledFor).isEqualTo(ImeAction.Search)
+ }
+ }
+
+ @Test
+ fun textField_performsDefaultBehavior_forFocusNext() {
+ rule.setContent {
+ Column {
+ Box(
+ Modifier
+ .size(1.dp)
+ .focusable()
+ .testTag("box1"))
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next)
+ )
+ Box(
+ Modifier
+ .size(1.dp)
+ .focusable()
+ .testTag("box2"))
+ }
+ }
+
+ rule.onNodeWithTag("box2").assertIsNotFocused()
+ rule.onNode(hasSetTextAction()).performImeAction()
+ rule.onNodeWithTag("box2").assertIsFocused()
+ }
+
+ @Test
+ fun textField_performsDefaultBehavior_forFocusPrevious() {
+ rule.setContent {
+ Column {
+ Box(
+ Modifier
+ .size(1.dp)
+ .focusable()
+ .testTag("box1"))
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Previous)
+ )
+ Box(
+ Modifier
+ .size(1.dp)
+ .focusable()
+ .testTag("box2"))
+ }
+ }
+
+ rule.onNodeWithTag("box1").assertIsNotFocused()
+ rule.onNode(hasSetTextAction()).performImeAction()
+ rule.onNodeWithTag("box1").assertIsFocused()
+ }
+
+ @SdkSuppress(minSdkVersion = 23)
+ @Test
+ fun textField_performsDefaultBehavior_forDone() {
+ rule.setContent {
+ keyboardHelper.initialize()
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done)
+ )
+ }
+
+ with(rule.onNode(hasSetTextAction())) {
+ performClick()
+ keyboardHelper.waitForKeyboardVisibility(true)
+ performImeAction()
+ keyboardHelper.waitForKeyboardVisibility(false)
+ assertThat(keyboardHelper.isSoftwareKeyboardShown()).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun textField_canOverrideDefaultBehavior() {
+ rule.setContent {
+ Column {
+ Box(
+ Modifier
+ .size(1.dp)
+ .focusable()
+ .testTag("box1"))
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
+ keyboardActions = KeyboardActionsAll {
+ // don't call default action
+ }
+ )
+ Box(
+ Modifier
+ .size(1.dp)
+ .focusable()
+ .testTag("box2"))
+ }
+ }
+
+ rule.onNodeWithTag("box2").assertIsNotFocused()
+ rule.onNode(hasSetTextAction()).performImeAction()
+ rule.onNode(hasSetTextAction()).assertIsFocused()
+ rule.onNodeWithTag("box2").assertIsNotFocused()
+ }
+
+ @Test
+ fun textField_canRequestDefaultBehavior() {
+ rule.setContent {
+ Column {
+ Box(
+ Modifier
+ .size(1.dp)
+ .focusable()
+ .testTag("box1"))
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
+ keyboardActions = KeyboardActionsAll {
+ defaultKeyboardAction(it)
+ }
+ )
+ Box(
+ Modifier
+ .size(1.dp)
+ .focusable()
+ .testTag("box2"))
+ }
+ }
+
+ rule.onNodeWithTag("box2").assertIsNotFocused()
+ rule.onNode(hasSetTextAction()).performImeAction()
+ rule.onNodeWithTag("box2").assertIsFocused()
+ }
+
+ @Test
+ fun textField_performsGo_whenReceivedImeActionIsGo() {
+ var called = false
+ var inputConnection: InputConnection? = null
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+ rule.setContent {
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardActions = KeyboardActions(onGo = {
+ called = true
+ })
+ )
+ }
+
+ rule.onNode(hasSetTextAction()).performSemanticsAction(SemanticsActions.RequestFocus)
+
+ rule.runOnIdle {
+ inputConnection?.performEditorAction(EditorInfo.IME_ACTION_GO)
+ assertThat(called).isTrue()
+ }
+ }
+
+ @Test
+ fun textField_doesNotPerformGo_whenReceivedImeActionIsNotGo() {
+ var called = false
+ var inputConnection: InputConnection? = null
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
+ inputConnection = ic
+ }
+ rule.setContent {
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardActions = KeyboardActions(onGo = {
+ called = true
+ })
+ )
+ }
+
+ rule.onNode(hasSetTextAction()).performSemanticsAction(SemanticsActions.RequestFocus)
+
+ rule.runOnIdle {
+ inputConnection?.performEditorAction(EditorInfo.IME_ACTION_SEARCH)
+ assertThat(called).isFalse()
+ }
+ }
+
+ @Test
+ fun textField_changingKeyboardActions_usesNewKeyboardActions() {
+ var lastCaller = 0
+ val actions1 = KeyboardActionsAll { lastCaller = 1 }
+ val actions2 = KeyboardActionsAll { lastCaller = 2 }
+ var keyboardActions by mutableStateOf(actions1)
+ rule.setContent {
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
+ keyboardActions = keyboardActions
+ )
+ }
+
+ rule.onNode(hasSetTextAction()).performImeAction()
+ rule.runOnIdle { assertThat(lastCaller).isEqualTo(1) }
+
+ keyboardActions = actions2
+
+ // do not go through focus requests again
+ rule.onNode(hasSetTextAction()).performSemanticsAction(SemanticsActions.OnImeAction)
+ rule.runOnIdle { assertThat(lastCaller).isEqualTo(2) }
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @Test
+ fun textField_singleLinePressEnter_triggersPassedImeAction() {
+ var calledFor: ImeAction? = null
+ rule.setContent {
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Go),
+ keyboardActions = KeyboardActionsAll {
+ calledFor = it
+ },
+ lineLimits = SingleLine
+ )
+ }
+
+ with(rule.onNode(hasSetTextAction())) {
+ performClick()
+ performKeyInput { pressKey(Key.Enter) }
+ }
+ rule.runOnIdle { assertThat(calledFor).isEqualTo(ImeAction.Go) }
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @Test
+ fun textField_multiLinePressEnter_doesNotTriggerPassedImeAction() {
+ var calledFor: ImeAction? = null
+ rule.setContent {
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Go),
+ keyboardActions = KeyboardActionsAll {
+ calledFor = it
+ },
+ lineLimits = MultiLine(maxHeightInLines = 1)
+ )
+ }
+
+ with(rule.onNode(hasSetTextAction())) {
+ performClick()
+ performKeyInput { pressKey(Key.Enter) }
+ }
+ rule.runOnIdle { assertThat(calledFor).isNull() }
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @Test
+ fun textField_singleLinePressEnter_triggersDefaultBehavior() {
+ rule.setContent {
+ Column {
+ Box(
+ Modifier
+ .size(1.dp)
+ .focusable()
+ .testTag("box1"))
+ BasicTextField2(
+ state = TextFieldState(),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
+ lineLimits = SingleLine
+ )
+ Box(
+ Modifier
+ .size(1.dp)
+ .focusable()
+ .testTag("box2"))
+ }
+ }
+
+ rule.onNodeWithTag("box2").assertIsNotFocused()
+ with(rule.onNode(hasSetTextAction())) {
+ performClick()
+ performKeyInput { pressKey(Key.Enter) }
+ }
+ rule.onNodeWithTag("box2").assertIsFocused()
+ }
+}
+
+private fun KeyboardActionsAll(
+ onAny: KeyboardActionScope.(ImeAction) -> Unit
+): KeyboardActions = KeyboardActions(
+ onDone = { onAny(ImeAction.Done) },
+ onGo = { onAny(ImeAction.Go) },
+ onNext = { onAny(ImeAction.Next) },
+ onPrevious = { onAny(ImeAction.Previous) },
+ onSearch = { onAny(ImeAction.Search) },
+ onSend = { onAny(ImeAction.Send) }
+)
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldScrollTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldScrollTest.kt
new file mode 100644
index 0000000..5285a66
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldScrollTest.kt
@@ -0,0 +1,611 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2
+
+import android.os.Build
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.ScrollState
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.text.TextLayoutResultProxy
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldLineLimits
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+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.testutils.assertPixels
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.node.Ref
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.LocalViewConfiguration
+import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.test.assertIsNotFocused
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.test.junit4.StateRestorationTester
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.swipe
+import androidx.compose.ui.test.swipeDown
+import androidx.compose.ui.test.swipeLeft
+import androidx.compose.ui.test.swipeRight
+import androidx.compose.ui.test.swipeUp
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalFoundationApi::class)
+class TextFieldScrollTest {
+
+ private val TextfieldTag = "textField"
+
+ private val longText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " +
+ "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam," +
+ " quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " +
+ "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu " +
+ "fugiat nulla pariatur."
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ private lateinit var testScope: CoroutineScope
+
+ @Before
+ fun before() {
+ isDebugInspectorInfoEnabled = true
+ }
+
+ @After
+ fun after() {
+ isDebugInspectorInfoEnabled = false
+ }
+
+ @Test
+ fun textFieldScroll_horizontal_scrollable_withLongInput() {
+ val scrollState = ScrollState(0)
+
+ rule.setupHorizontallyScrollableContent(
+ TextFieldState(longText), scrollState, Modifier.size(width = 300.dp, height = 50.dp)
+ )
+
+ rule.runOnIdle {
+ assertThat(scrollState.maxValue).isLessThan(Int.MAX_VALUE)
+ assertThat(scrollState.maxValue).isGreaterThan(0)
+ }
+ }
+
+ @Test
+ fun textFieldScroll_vertical_scrollable_withLongInput() {
+ val scrollState = ScrollState(0)
+
+ rule.setupVerticallyScrollableContent(
+ state = TextFieldState(longText),
+ scrollState = scrollState,
+ modifier = Modifier.size(width = 300.dp, height = 50.dp)
+ )
+
+ rule.runOnIdle {
+ assertThat(scrollState.maxValue).isLessThan(Int.MAX_VALUE)
+ assertThat(scrollState.maxValue).isGreaterThan(0)
+ }
+ }
+
+ @Test
+ fun textFieldScroll_vertical_scrollable_withLongInput_whenMaxLinesProvided() {
+ val scrollState = ScrollState(0)
+
+ rule.setupVerticallyScrollableContent(
+ state = TextFieldState(longText),
+ modifier = Modifier.width(100.dp),
+ scrollState = scrollState,
+ maxLines = 3
+ )
+
+ rule.runOnIdle {
+ assertThat(scrollState.maxValue).isLessThan(Int.MAX_VALUE)
+ assertThat(scrollState.maxValue).isGreaterThan(0)
+ }
+ }
+
+ @Test
+ fun textFieldScroll_horizontal_notScrollable_withShortInput() {
+ val scrollState = ScrollState(0)
+
+ rule.setupHorizontallyScrollableContent(
+ state = TextFieldState("text"),
+ scrollState = scrollState,
+ modifier = Modifier.size(width = 300.dp, height = 50.dp)
+ )
+
+ rule.runOnIdle {
+ assertThat(scrollState.maxValue).isEqualTo(0)
+ }
+ }
+
+ @Test
+ fun textFieldScroll_vertical_notScrollable_withShortInput() {
+ val scrollState = ScrollState(0)
+
+ rule.setupVerticallyScrollableContent(
+ state = TextFieldState("text"),
+ scrollState = scrollState,
+ modifier = Modifier.size(width = 300.dp, height = 100.dp)
+ )
+
+ rule.runOnIdle {
+ assertThat(scrollState.maxValue).isEqualTo(0)
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun textField_singleLine_scrolledAndClipped() {
+ val parentSize = 200
+ val textFieldSize = 50
+ val tag = "OuterBox"
+
+ with(rule.density) {
+ rule.setContent {
+ Box(
+ Modifier
+ .size(parentSize.toDp())
+ .background(color = Color.White)
+ .testTag(tag)
+ ) {
+ ScrollableContent(
+ state = TextFieldState(longText),
+ modifier = Modifier.size(textFieldSize.toDp()),
+ scrollState = rememberScrollState(),
+ lineLimits = SingleLine
+ )
+ }
+ }
+ }
+
+ rule.waitForIdle()
+
+ rule.onNodeWithTag(tag)
+ .captureToImage()
+ .assertPixels(expectedSize = IntSize(parentSize, parentSize)) { position ->
+ if (position.x > textFieldSize || position.y > textFieldSize) Color.White else null
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun textField_multiline_scrolledAndClipped() {
+ val parentSize = 200
+ val textFieldSize = 50
+ val tag = "OuterBox"
+
+ with(rule.density) {
+ rule.setContent {
+ Box(
+ Modifier
+ .size(parentSize.toDp())
+ .background(color = Color.White)
+ .testTag(tag)
+ ) {
+ ScrollableContent(
+ state = TextFieldState(longText),
+ modifier = Modifier.size(textFieldSize.toDp()),
+ scrollState = rememberScrollState(),
+ lineLimits = MultiLine()
+ )
+ }
+ }
+ }
+
+ rule.waitForIdle()
+
+ rule.onNodeWithTag(tag)
+ .captureToImage()
+ .assertPixels(expectedSize = IntSize(parentSize, parentSize)) { position ->
+ if (position.x > textFieldSize || position.y > textFieldSize) Color.White else null
+ }
+ }
+
+ @Test
+ fun textFieldScroll_horizontal_swipe_whenLongInput() {
+ val scrollState = ScrollState(0)
+
+ rule.setupHorizontallyScrollableContent(
+ state = TextFieldState(longText),
+ scrollState = scrollState,
+ modifier = Modifier.size(width = 300.dp, height = 50.dp)
+ )
+
+ rule.runOnIdle {
+ assertThat(scrollState.value).isEqualTo(0)
+ }
+
+ rule.onNodeWithTag(TextfieldTag)
+ .performTouchInput { swipeLeft() }
+
+ val firstSwipePosition = rule.runOnIdle {
+ scrollState.value
+ }
+ assertThat(firstSwipePosition).isGreaterThan(0)
+
+ rule.onNodeWithTag(TextfieldTag)
+ .performTouchInput { swipeRight() }
+ rule.runOnIdle {
+ assertThat(scrollState.value).isLessThan(firstSwipePosition)
+ }
+ }
+
+ @Test
+ fun textFieldScroll_vertical_swipe_whenLongInput() {
+ val scrollState = ScrollState(0)
+
+ rule.setupVerticallyScrollableContent(
+ state = TextFieldState(longText),
+ scrollState = scrollState,
+ modifier = Modifier.size(width = 300.dp, height = 50.dp)
+ )
+
+ rule.runOnIdle {
+ assertThat(scrollState.value).isEqualTo(0)
+ }
+
+ rule.onNodeWithTag(TextfieldTag)
+ .performTouchInput { swipeUp() }
+
+ val firstSwipePosition = rule.runOnIdle {
+ scrollState.value
+ }
+ assertThat(firstSwipePosition).isGreaterThan(0)
+
+ rule.onNodeWithTag(TextfieldTag)
+ .performTouchInput { swipeDown() }
+ rule.runOnIdle {
+ assertThat(scrollState.value).isLessThan(firstSwipePosition)
+ }
+ }
+
+ @Test
+ fun textFieldScroll_restoresScrollerPosition() {
+ val restorationTester = StateRestorationTester(rule)
+ var scrollState: ScrollState? = null
+
+ restorationTester.setContent {
+ scrollState = rememberScrollState()
+ ScrollableContent(
+ state = TextFieldState(longText),
+ modifier = Modifier.size(width = 300.dp, height = 50.dp),
+ scrollState = scrollState!!,
+ lineLimits = SingleLine
+ )
+ }
+
+ rule.onNodeWithTag(TextfieldTag)
+ .performTouchInput { swipeLeft() }
+
+ val swipePosition = rule.runOnIdle { scrollState!!.value }
+ assertThat(swipePosition).isGreaterThan(0)
+
+ rule.runOnIdle {
+ scrollState = ScrollState(0)
+ assertThat(scrollState!!.value).isEqualTo(0)
+ }
+
+ restorationTester.emulateSavedInstanceStateRestore()
+
+ rule.runOnIdle {
+ assertThat(scrollState!!.value).isEqualTo(swipePosition)
+ }
+ }
+
+ @Test
+ fun textFieldScrollStateChange_shouldResetTheScroll() {
+ val scrollState1 = ScrollState(0)
+ val scrollState2 = ScrollState(0)
+
+ var stateToggle by mutableStateOf(true)
+
+ rule.setContent {
+ ScrollableContent(
+ state = TextFieldState(longText),
+ scrollState = if (stateToggle) scrollState1 else scrollState2,
+ modifier = Modifier.size(width = 300.dp, height = 50.dp),
+ lineLimits = SingleLine
+ )
+ }
+
+ rule.runOnIdle {
+ assertThat(scrollState1.maxValue).isLessThan(Int.MAX_VALUE)
+ assertThat(scrollState1.maxValue).isGreaterThan(0)
+
+ assertThat(scrollState2.maxValue).isEqualTo(Int.MAX_VALUE) // when it's not set
+ assertThat(scrollState2.value).isEqualTo(0)
+ }
+
+ rule.onNodeWithTag(TextfieldTag).performTouchInput { swipeLeft() }
+
+ rule.runOnIdle {
+ assertThat(scrollState1.value).isGreaterThan(0)
+ }
+
+ stateToggle = false
+
+ rule.runOnIdle {
+ assertThat(scrollState2.maxValue).isLessThan(Int.MAX_VALUE)
+ assertThat(scrollState2.maxValue).isGreaterThan(0)
+
+ assertThat(scrollState2.value).isEqualTo(0)
+ }
+ }
+
+ @Test
+ fun textFieldDoesNotFollowCursor_whenNotFocused() {
+ val state = TextFieldState(longText)
+ val scrollState = ScrollState(0)
+ rule.setContent {
+ ScrollableContent(
+ state = state,
+ scrollState = scrollState,
+ modifier = Modifier.size(width = 300.dp, height = 50.dp),
+ lineLimits = SingleLine
+ )
+ }
+
+ rule.onNodeWithTag(TextfieldTag).assertIsNotFocused()
+
+ // move cursor to the end
+ // TODO
+ state.editProcessor.reset(
+ TextFieldCharSequence(state.text, selection = TextRange(longText.length))
+ )
+
+ rule.runOnIdle {
+ assertThat(scrollState.value).isEqualTo(0)
+ }
+ }
+
+ @Test
+ fun textFieldFollowsCursor_whenFocused() {
+ val state = TextFieldState(longText)
+ val scrollState = ScrollState(0)
+ rule.setContent {
+ ScrollableContent(
+ state = state,
+ scrollState = scrollState,
+ modifier = Modifier.size(width = 300.dp, height = 50.dp),
+ lineLimits = SingleLine
+ )
+ }
+
+ rule.onNodeWithTag(TextfieldTag).performSemanticsAction(SemanticsActions.RequestFocus)
+
+ // move cursor to the end
+ state.editProcessor.reset(
+ TextFieldCharSequence(state.text, selection = TextRange(longText.length))
+ )
+
+ rule.runOnIdle {
+ assertThat(scrollState.value).isEqualTo(scrollState.maxValue)
+ }
+ }
+
+ @Test
+ fun textFieldDoesNotFollowCursor_whenScrollStateChanges_butCursorRemainsTheSame() {
+ val state = TextFieldState(longText, initialSelectionInChars = TextRange(5))
+ val scrollState = ScrollState(0)
+ rule.setContent {
+ ScrollableContent(
+ state = state,
+ scrollState = scrollState,
+ modifier = Modifier.size(width = 300.dp, height = 50.dp),
+ lineLimits = SingleLine
+ )
+ }
+
+ rule.onNodeWithTag(TextfieldTag).performSemanticsAction(SemanticsActions.RequestFocus)
+ rule.waitForIdle()
+
+ runBlockingAndAwaitIdle { scrollState.scrollTo(scrollState.maxValue) }
+
+ rule.runOnIdle {
+ assertThat(scrollState.value).isEqualTo(scrollState.maxValue)
+ assertThat(state.text.selectionInChars).isEqualTo(TextRange(5))
+ }
+ }
+
+ @Test
+ fun textFieldRtl_horizontalScroll_isReversed() {
+ val scrollState = ScrollState(0)
+
+ rule.setupHorizontallyScrollableContent(
+ state = TextFieldState(longText),
+ scrollState = scrollState,
+ modifier = Modifier.size(width = 300.dp, height = 50.dp),
+ isRtl = true
+ )
+
+ rule.runOnIdle {
+ assertThat(scrollState.value).isEqualTo(0)
+ }
+
+ rule.onNodeWithTag(TextfieldTag).performTouchInput { swipeLeft() }
+
+ // swiping left at initial position should be no-op in RTL layout
+ val firstSwipePosition = rule.runOnIdle { scrollState.value }
+ assertThat(firstSwipePosition).isEqualTo(0)
+
+ rule.onNodeWithTag(TextfieldTag).performTouchInput { swipeRight() }
+ rule.runOnIdle {
+ assertThat(scrollState.value).isGreaterThan(firstSwipePosition)
+ }
+ }
+
+ @Test
+ fun textFieldScroll_testNestedScrolling() = runBlocking {
+ val size = 300.dp
+ val text = """
+ First Line
+ Second Line
+ Third Line
+ Fourth Line
+ """.trimIndent()
+
+ val textFieldScrollState = ScrollState(0)
+ val columnScrollState = ScrollState(0)
+ var touchSlop = 0f
+ val height = 60.dp
+
+ rule.setContent {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ Column(
+ Modifier
+ .size(size)
+ .verticalScroll(columnScrollState)
+ ) {
+ ScrollableContent(
+ state = TextFieldState(text),
+ modifier = Modifier.size(size, height),
+ scrollState = textFieldScrollState,
+ lineLimits = MultiLine()
+ )
+ Box(Modifier.size(size))
+ Box(Modifier.size(size))
+ }
+ }
+
+ assertThat(textFieldScrollState.value).isEqualTo(0)
+ assertThat(textFieldScrollState.maxValue).isGreaterThan(0)
+ assertThat(columnScrollState.value).isEqualTo(0)
+
+ with(rule.density) {
+ val x = 10.dp.toPx()
+ val desiredY = textFieldScrollState.maxValue + 10.dp.roundToPx()
+ val nearEdge = (height - 1.dp)
+ // not to exceed size
+ val slopStartY = minOf(desiredY + touchSlop, nearEdge.toPx())
+ val slopStart = Offset(x, slopStartY)
+ val end = Offset(x, 0f)
+ rule.onNodeWithTag(TextfieldTag)
+ .performTouchInput {
+ swipe(slopStart, end)
+ }
+ }
+
+ assertThat(textFieldScrollState.value).isGreaterThan(0)
+ assertThat(textFieldScrollState.value).isEqualTo(textFieldScrollState.maxValue)
+ assertThat(columnScrollState.value).isGreaterThan(0)
+ }
+
+ private fun ComposeContentTestRule.setupHorizontallyScrollableContent(
+ state: TextFieldState,
+ scrollState: ScrollState,
+ modifier: Modifier = Modifier,
+ isRtl: Boolean = false
+ ) {
+ setContent {
+ val direction = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
+ CompositionLocalProvider(LocalLayoutDirection provides direction) {
+ ScrollableContent(
+ state = state,
+ scrollState = scrollState,
+ modifier = modifier,
+ lineLimits = SingleLine
+ )
+ }
+ }
+ }
+
+ private fun ComposeContentTestRule.setupVerticallyScrollableContent(
+ state: TextFieldState,
+ scrollState: ScrollState,
+ modifier: Modifier = Modifier,
+ maxLines: Int = Int.MAX_VALUE,
+ isRtl: Boolean = false
+ ) {
+ setContent {
+ val direction = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
+ CompositionLocalProvider(LocalLayoutDirection provides direction) {
+ ScrollableContent(
+ state = state,
+ scrollState = scrollState,
+ modifier = modifier,
+ lineLimits = MultiLine(maxHeightInLines = maxLines)
+ )
+ }
+ }
+ }
+
+ @Composable
+ private fun ScrollableContent(
+ modifier: Modifier,
+ state: TextFieldState,
+ scrollState: ScrollState,
+ lineLimits: TextFieldLineLimits
+ ) {
+ val textLayoutResultRef: Ref<TextLayoutResultProxy?> = remember { Ref() }
+
+ testScope = rememberCoroutineScope()
+ BasicTextField2(
+ state = state,
+ scrollState = scrollState,
+ onTextLayout = {
+ textLayoutResultRef.value = TextLayoutResultProxy(it)
+ },
+ lineLimits = lineLimits,
+ modifier = modifier.testTag(TextfieldTag)
+ )
+ }
+
+ private fun runBlockingAndAwaitIdle(block: suspend CoroutineScope.() -> Unit) {
+ val job = testScope.launch(block = block)
+ rule.waitForIdle()
+ runBlocking {
+ job.join()
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldStateRestorationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldStateRestorationTest.kt
new file mode 100644
index 0000000..cae64e7
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldStateRestorationTest.kt
@@ -0,0 +1,71 @@
+/*
+ * 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
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.rememberTextFieldState
+import androidx.compose.foundation.text2.input.selectAll
+import androidx.compose.runtime.remember
+import androidx.compose.ui.test.junit4.StateRestorationTester
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.text.TextRange
+import androidx.test.ext.junit.runners.AndroidJUnit4
+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
+
+@OptIn(ExperimentalFoundationApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TextFieldStateRestorationTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ private val restorationTester = StateRestorationTester(rule)
+
+ @Test
+ fun rememberTextFieldState_restoresTextAndSelection() {
+ lateinit var originalState: TextFieldState
+ lateinit var restoredState: TextFieldState
+ var rememberCount = 0
+ restorationTester.setContent {
+ val state = rememberTextFieldState()
+ if (remember { rememberCount++ } == 0) {
+ originalState = state
+ } else {
+ restoredState = state
+ }
+ }
+ rule.runOnIdle {
+ originalState.edit {
+ append("hello, world")
+ selectAll()
+ }
+ }
+
+ restorationTester.emulateSavedInstanceStateRestore()
+
+ rule.runOnIdle {
+ assertThat(restoredState.text.toString()).isEqualTo("hello, world")
+ assertThat(restoredState.text.selectionInChars).isEqualTo(TextRange(0, 12))
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapterTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapterTest.kt
new file mode 100644
index 0000000..2c65d65
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapterTest.kt
@@ -0,0 +1,331 @@
+/*
+ * 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.input.internal
+
+import android.text.InputType
+import android.view.inputmethod.EditorInfo
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.text.KeyboardHelper
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.platform.LocalPlatformTextInputPluginRegistry
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.ImeAction
+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.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 kotlin.test.assertFalse
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AndroidTextInputAdapterTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ private lateinit var adapter: AndroidTextInputAdapter
+
+ private val keyboardHelper = KeyboardHelper(rule)
+
+ private val focusRequester = FocusRequester()
+
+ @Before
+ fun setup() {
+ rule.setContent {
+ keyboardHelper.initialize()
+ LaunchedEffect(Unit) {
+ focusRequester.requestFocus()
+ }
+ Box(modifier = Modifier
+ .size(1.dp)
+ .focusRequester(focusRequester)
+ .focusable()
+ ) {
+ val adapterProvider = LocalPlatformTextInputPluginRegistry.current
+ adapter = adapterProvider.rememberAdapter(AndroidTextInputPlugin)
+ }
+ }
+ rule.waitForIdle()
+ }
+
+ @Test
+ fun startInputSession_returnsOpenSession() {
+ rule.runOnUiThread {
+ val session = adapter.startInputSessionWithDefaultsForTest()
+ assertThat(session.isOpen).isTrue()
+ }
+ }
+
+ @Test
+ fun disposedSession_returnsClosed() {
+ rule.runOnUiThread {
+ val session = adapter.startInputSessionWithDefaultsForTest()
+ session.dispose()
+ assertThat(session.isOpen).isFalse()
+ }
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun startingInputSessionOnNonMainThread_throwsIllegalStateException() {
+ adapter.startInputSessionWithDefaultsForTest()
+ }
+
+ @Test
+ fun creatingSecondInputSession_closesFirstOne() {
+ rule.runOnUiThread {
+ val session1 = adapter.startInputSessionWithDefaultsForTest()
+ val session2 = adapter.startInputSessionWithDefaultsForTest()
+
+ assertThat(session1.isOpen).isFalse()
+ assertThat(session2.isOpen).isTrue()
+ }
+ }
+
+ @Test
+ fun createInputConnection_modifiesEditorInfo() {
+ val state = TextFieldState("hello", initialSelectionInChars = TextRange(0, 5))
+ rule.runOnUiThread {
+ adapter.startInputSessionWithDefaultsForTest(state)
+ val editorInfo = EditorInfo()
+ adapter.createInputConnection(editorInfo)
+
+ assertThat(editorInfo.initialSelStart).isEqualTo(0)
+ assertThat(editorInfo.initialSelEnd).isEqualTo(5)
+ assertThat(editorInfo.inputType).isEqualTo(
+ InputType.TYPE_CLASS_TEXT or
+ InputType.TYPE_TEXT_FLAG_MULTI_LINE or
+ InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
+ )
+ assertThat(editorInfo.imeOptions).isEqualTo(
+ EditorInfo.IME_FLAG_NO_FULLSCREEN or
+ EditorInfo.IME_FLAG_NO_ENTER_ACTION
+ )
+ }
+ }
+
+ @Test
+ fun inputConnection_sendsUpdates_toActiveSession() {
+ val state1 = TextFieldState()
+ val state2 = TextFieldState()
+ rule.runOnUiThread {
+ adapter.startInputSessionWithDefaultsForTest(state1)
+ adapter.startInputSessionWithDefaultsForTest(state2)
+
+ val connection = adapter.createInputConnection(EditorInfo())
+
+ connection.commitText("Hello", 0)
+
+ assertThat(state1.text.toString()).isEqualTo("")
+ assertThat(state2.text.toString()).isEqualTo("Hello")
+ }
+ }
+
+ @Test
+ fun inputConnection_sendsEditorAction_toActiveSession() {
+ var imeActionFromOne: ImeAction? = null
+ var imeActionFromTwo: ImeAction? = null
+ rule.runOnUiThread {
+ adapter.startInputSessionWithDefaultsForTest(
+ imeOptions = ImeOptions(imeAction = ImeAction.Done),
+ onImeAction = {
+ imeActionFromOne = it
+ }
+ )
+
+ val connection = adapter.createInputConnection(EditorInfo())
+ connection.performEditorAction(EditorInfo.IME_ACTION_DONE)
+
+ assertThat(imeActionFromOne).isEqualTo(ImeAction.Done)
+ assertThat(imeActionFromTwo).isNull()
+
+ adapter.startInputSessionWithDefaultsForTest(
+ imeOptions = ImeOptions(imeAction = ImeAction.Go),
+ onImeAction = {
+ imeActionFromTwo = it
+ }
+ )
+ connection.performEditorAction(EditorInfo.IME_ACTION_GO)
+
+ assertThat(imeActionFromOne).isEqualTo(ImeAction.Done)
+ assertThat(imeActionFromTwo).isEqualTo(ImeAction.Go)
+ }
+ }
+
+ @Test
+ fun createInputConnection_updatesEditorInfo() {
+ var editorInfo: EditorInfo? = null
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { ei, _ ->
+ editorInfo = ei
+ }
+ rule.runOnUiThread {
+ adapter.startInputSessionWithDefaultsForTest(
+ imeOptions = ImeOptions(
+ singleLine = true,
+ keyboardType = KeyboardType.Email,
+ autoCorrect = false,
+ imeAction = ImeAction.Search,
+ capitalization = KeyboardCapitalization.Words
+ )
+ )
+ }
+
+ // wait until input gets started to make sure we are not running assertions before
+ // the listener triggers.
+ keyboardHelper.waitForKeyboardVisibility(true)
+
+ rule.runOnIdle {
+ assertThat(editorInfo?.inputType).isEqualTo(
+ InputType.TYPE_CLASS_TEXT or
+ InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS or
+ InputType.TYPE_TEXT_FLAG_CAP_WORDS
+ )
+ assertThat(editorInfo?.imeOptions).isEqualTo(
+ EditorInfo.IME_ACTION_SEARCH or EditorInfo.IME_FLAG_NO_FULLSCREEN
+ )
+ }
+ }
+
+ @Test
+ fun createInputConnection_updatesEditorInfo_withTheLatestSession() {
+ var editorInfo: EditorInfo? = null
+ AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { ei, _ ->
+ editorInfo = ei
+ }
+ rule.runOnUiThread {
+ adapter.startInputSessionWithDefaultsForTest(
+ imeOptions = ImeOptions(
+ keyboardType = KeyboardType.Number
+ )
+ )
+ adapter.startInputSessionWithDefaultsForTest(
+ imeOptions = ImeOptions(
+ singleLine = true,
+ keyboardType = KeyboardType.Email,
+ autoCorrect = false,
+ imeAction = ImeAction.Search,
+ capitalization = KeyboardCapitalization.Words
+ )
+ )
+ }
+
+ // wait until input gets started to make sure we are not running assertions before
+ // the listener triggers.
+ keyboardHelper.waitForKeyboardVisibility(true)
+
+ rule.runOnIdle {
+ assertThat(editorInfo?.inputType).isEqualTo(
+ InputType.TYPE_CLASS_TEXT or
+ InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS or
+ InputType.TYPE_TEXT_FLAG_CAP_WORDS
+ )
+ assertThat(editorInfo?.imeOptions).isEqualTo(
+ EditorInfo.IME_ACTION_SEARCH or EditorInfo.IME_FLAG_NO_FULLSCREEN
+ )
+ }
+ }
+
+ @Test
+ fun createInputConnection_updatesEditorInfo_noActiveSession() {
+ val noActiveSessionEI = EditorInfo()
+ val activeSessionEI = EditorInfo()
+ val disposedSessionEI = EditorInfo()
+ rule.runOnUiThread {
+ adapter.createInputConnection(noActiveSessionEI)
+ val session = adapter.startInputSessionWithDefaultsForTest(
+ imeOptions = ImeOptions(
+ keyboardType = KeyboardType.Number
+ )
+ )
+ adapter.createInputConnection(activeSessionEI)
+ session.dispose()
+ adapter.createInputConnection(disposedSessionEI)
+
+ assertThat(noActiveSessionEI.inputType).isNotEqualTo(activeSessionEI.inputType)
+ assertThat(noActiveSessionEI.imeOptions).isNotEqualTo(activeSessionEI.imeOptions)
+
+ assertThat(noActiveSessionEI.inputType).isEqualTo(disposedSessionEI.inputType)
+ assertThat(noActiveSessionEI.imeOptions).isEqualTo(disposedSessionEI.imeOptions)
+ }
+ }
+
+ @Test
+ fun showSoftwareKeyboard_fromActiveInputSession_showsTheKeyboard() {
+ var session: TextInputSession? = null
+
+ rule.runOnUiThread {
+ session = adapter.startInputSessionWithDefaultsForTest()
+ }
+
+ keyboardHelper.hideKeyboardIfShown()
+ keyboardHelper.waitForKeyboardVisibility(false)
+
+ session?.showSoftwareKeyboard()
+ keyboardHelper.waitForKeyboardVisibility(true)
+ assertThat(keyboardHelper.isSoftwareKeyboardShown()).isTrue()
+ }
+
+ @SdkSuppress(minSdkVersion = 23)
+ @Test
+ fun hideSoftwareKeyboard_fromActiveInputSession_hidesTheKeyboard() {
+ var session: TextInputSession? = null
+
+ rule.runOnUiThread {
+ session = adapter.startInputSessionWithDefaultsForTest()
+ }
+
+ keyboardHelper.waitForKeyboardVisibility(true)
+
+ session?.hideSoftwareKeyboard()
+ keyboardHelper.waitForKeyboardVisibility(false)
+ assertThat(keyboardHelper.isSoftwareKeyboardShown()).isFalse()
+ }
+
+ @Test
+ fun debugMode_isDisabled() {
+ // run this in presubmit to check that we are not accidentally enabling logs on prod
+ assertFalse(
+ TIA_DEBUG,
+ "Oops, looks like you accidentally enabled logging. Don't worry, we've all " +
+ "been there. Just remember to turn it off before you deploy your code."
+ )
+ }
+
+ private fun AndroidTextInputAdapter.startInputSessionWithDefaultsForTest(
+ state: TextFieldState = TextFieldState(),
+ imeOptions: ImeOptions = ImeOptions.Default,
+ initialFilter: TextEditFilter? = null,
+ onImeAction: (ImeAction) -> Unit = {}
+ ) = startInputSession(state, imeOptions, initialFilter, onImeAction)
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/BackspaceCommandTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/BackspaceCommandTest.kt
new file mode 100644
index 0000000..d20e643
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/BackspaceCommandTest.kt
@@ -0,0 +1,133 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.TextRange
+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.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BackspaceCommandTest {
+
+ // Test sample surrogate pair characters.
+ private val SP1 = "\uD83D\uDE00" // U+1F600: GRINNING FACE
+ private val SP2 = "\uD83D\uDE01" // U+1F601: GRINNING FACE WITH SMILING EYES
+ private val SP3 = "\uD83D\uDE02" // U+1F602: FACE WITH TEARS OF JOY
+ private val SP4 = "\uD83D\uDE03" // U+1F603: SMILING FACE WITH OPEN MOUTH
+ private val SP5 = "\uD83D\uDE04" // U+1F604: SMILING FACE WITH OPEN MOUTH AND SMILING EYES
+
+ // Family ZWJ Emoji: U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466
+ private val ZWJ_EMOJI = "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66"
+
+ @Test
+ fun test_delete() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+
+ eb.update(BackspaceCommand)
+
+ assertThat(eb.toString()).isEqualTo("BCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_from_offset0() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(BackspaceCommand)
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_with_selection() {
+ val eb = EditingBuffer("ABCDE", TextRange(2, 3))
+
+ eb.update(BackspaceCommand)
+
+ assertThat(eb.toString()).isEqualTo("ABDE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_with_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+ eb.setComposition(2, 3)
+
+ eb.update(BackspaceCommand)
+
+ assertThat(eb.toString()).isEqualTo("ABDE")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_surrogate_pair() {
+ val eb = EditingBuffer("$SP1$SP2$SP3$SP4$SP5", TextRange(2))
+
+ eb.update(BackspaceCommand)
+
+ assertThat(eb.toString()).isEqualTo("$SP2$SP3$SP4$SP5")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_with_selection_surrogate_pair() {
+ val eb = EditingBuffer("$SP1$SP2$SP3$SP4$SP5", TextRange(4, 6))
+
+ eb.update(BackspaceCommand)
+
+ assertThat(eb.toString()).isEqualTo("$SP1$SP2$SP4$SP5")
+ assertThat(eb.cursor).isEqualTo(4)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_with_composition_surrogate_pair() {
+ val eb = EditingBuffer("$SP1$SP2$SP3$SP4$SP5", TextRange(2))
+ eb.setComposition(4, 6)
+
+ eb.update(BackspaceCommand)
+
+ assertThat(eb.toString()).isEqualTo("$SP1$SP2$SP4$SP5")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 26)
+ fun test_delete_with_composition_zwj_emoji() {
+ val eb = EditingBuffer(
+ "$ZWJ_EMOJI$ZWJ_EMOJI",
+ TextRange(ZWJ_EMOJI.length)
+ )
+
+ eb.update(BackspaceCommand)
+
+ assertThat(eb.toString()).isEqualTo(ZWJ_EMOJI)
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/ComposeInputMethodManagerTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/ComposeInputMethodManagerTest.kt
new file mode 100644
index 0000000..1f86e04
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/ComposeInputMethodManagerTest.kt
@@ -0,0 +1,122 @@
+/*
+ * 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.input.internal
+
+import android.content.Context
+import android.view.View
+import android.view.inputmethod.EditorInfo
+import android.view.inputmethod.InputConnection
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.test.ext.junit.runners.AndroidJUnit4
+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
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ComposeInputMethodManagerTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun restartInput_startsNewInputConnection() {
+ var calledCreateInputConnection: EditorInfo? = null
+ var imm: ComposeInputMethodManager? = null
+ var view: View? = null
+ rule.setContent {
+ AndroidView(factory = { context ->
+ TestView(context) { editorInfo ->
+ calledCreateInputConnection = editorInfo
+ null
+ }.also {
+ view = it
+ imm = ComposeInputMethodManager(it)
+ }
+ })
+ }
+
+ rule.runOnUiThread {
+ view?.requestFocus()
+ imm?.restartInput()
+ }
+
+ rule.runOnIdle {
+ assertThat(calledCreateInputConnection).isNotNull()
+ }
+ }
+
+ @Test
+ fun everyRestartInput_createsNewInputConnection() {
+ var createInputConnectionCalled = 0
+ var imm: ComposeInputMethodManager? = null
+ var view: View? = null
+ rule.setContent {
+ AndroidView(factory = { context ->
+ TestView(context) {
+ createInputConnectionCalled++
+ null
+ }.also {
+ view = it
+ imm = ComposeInputMethodManager(it)
+ }
+ })
+ }
+
+ rule.runOnUiThread {
+ view?.requestFocus()
+ imm?.restartInput()
+ }
+
+ rule.runOnIdle {
+ // when first time we start input, checkFocus in platform code causes
+ // onCreateInputConnection to be called twice.
+ assertThat(createInputConnectionCalled).isEqualTo(2)
+ }
+
+ rule.runOnUiThread {
+ imm?.restartInput()
+ }
+
+ rule.runOnIdle {
+ assertThat(createInputConnectionCalled).isEqualTo(3)
+ }
+ }
+}
+
+private class TestView(
+ context: Context,
+ val createInputConnection: (EditorInfo?) -> InputConnection? = { null }
+) : View(context) {
+
+ init {
+ isFocusable = true
+ isFocusableInTouchMode = true
+ isEnabled = true
+ }
+
+ override fun onCreateInputConnection(outAttrs: EditorInfo?): InputConnection? {
+ return createInputConnection(outAttrs)
+ }
+
+ override fun isInEditMode(): Boolean {
+ return true
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/EditorInfoTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/EditorInfoTest.kt
new file mode 100644
index 0000000..dc4fe4c
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/EditorInfoTest.kt
@@ -0,0 +1,544 @@
+/*
+ * 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.input.internal
+
+import android.text.InputType
+import android.view.inputmethod.EditorInfo
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.ImeOptions
+import androidx.compose.ui.text.input.KeyboardCapitalization
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class EditorInfoTest {
+
+ @Test
+ fun test_fill_editor_info_text() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Text,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_ascii() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_number() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_NUMBER and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_phone() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Phone,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_PHONE and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_uri() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Uri,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_VARIATION_URI and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_email() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Email,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS and info.inputType) != 0)
+ .isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_password() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Password,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_VARIATION_PASSWORD and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_number_password() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.NumberPassword,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_NUMBER and info.inputType) != 0).isTrue()
+ assertThat((InputType.TYPE_NUMBER_VARIATION_PASSWORD and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_decimal_number() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Decimal,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_NUMBER and info.inputType) != 0).isTrue()
+ assertThat((InputType.TYPE_NUMBER_FLAG_DECIMAL and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_none() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.None
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_NONE
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_go() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Go
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_GO
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_next() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Next
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_NEXT
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_previous() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Previous
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_PREVIOUS
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_search() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Search,
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_SEARCH
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_send() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Send
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_SEND
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_done() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_DONE
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_multi_line() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ singleLine = false,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isFalse()
+ assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_multi_line_with_default_action() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ singleLine = false,
+ keyboardType = KeyboardType.Text,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isFalse()
+ assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isFalse()
+ }
+
+ @Test
+ fun test_fill_editor_info_single_line() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ singleLine = true,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_single_line_changes_ime_from_unspecified_to_done() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ singleLine = true,
+ keyboardType = KeyboardType.Text,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((EditorInfo.IME_ACTION_DONE and info.imeOptions) == 0).isFalse()
+ assertThat((EditorInfo.IME_ACTION_UNSPECIFIED and info.imeOptions) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_multi_line_not_set_when_input_type_is_not_text() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ singleLine = false,
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_capitalization_none() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ capitalization = KeyboardCapitalization.None,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_capitalization_characters() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ capitalization = KeyboardCapitalization.Characters,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isFalse()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_capitalization_words() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ capitalization = KeyboardCapitalization.Words,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isFalse()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_capitalization_sentences() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ capitalization = KeyboardCapitalization.Sentences,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done,
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isFalse()
+ }
+
+ @Test
+ fun test_fill_editor_info_capitalization_not_added_when_input_type_is_not_text() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ capitalization = KeyboardCapitalization.Sentences,
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Done,
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_auto_correct_on() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ autoCorrect = true,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_AUTO_CORRECT and info.inputType) == 0).isFalse()
+ }
+
+ @Test
+ fun test_fill_editor_info_auto_correct_off() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ autoCorrect = false,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_AUTO_CORRECT and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun autocorrect_not_added_when_input_type_is_not_text() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ autoCorrect = true,
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_AUTO_CORRECT and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun initial_default_selection_info_is_set() {
+ val info = EditorInfo()
+ info.update(ImeOptions.Default)
+
+ assertThat(info.initialSelStart).isEqualTo(0)
+ assertThat(info.initialSelEnd).isEqualTo(0)
+ }
+
+ @Test
+ fun initial_selection_info_is_set() {
+ val selection = TextRange(1, 2)
+ val info = EditorInfo()
+ info.update(TextFieldCharSequence("abc", selection), ImeOptions.Default)
+
+ assertThat(info.initialSelStart).isEqualTo(selection.start)
+ assertThat(info.initialSelEnd).isEqualTo(selection.end)
+ }
+
+ private fun EditorInfo.update(imeOptions: ImeOptions) {
+ this.update(TextFieldCharSequence(), imeOptions)
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/MoveCursorCommandTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/MoveCursorCommandTest.kt
new file mode 100644
index 0000000..79f0a81
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/MoveCursorCommandTest.kt
@@ -0,0 +1,172 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.TextRange
+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.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MoveCursorCommandTest {
+ private val CH1 = "\uD83D\uDE00" // U+1F600
+ private val CH2 = "\uD83D\uDE01" // U+1F601
+ private val CH3 = "\uD83D\uDE02" // U+1F602
+ private val CH4 = "\uD83D\uDE03" // U+1F603
+ private val CH5 = "\uD83D\uDE04" // U+1F604
+
+ // U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466
+ private val FAMILY = "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66"
+
+ @Test
+ fun test_left() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.update(MoveCursorCommand(-1))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_left_multiple() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.update(MoveCursorCommand(-2))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_left_from_offset0() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(MoveCursorCommand(-1))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_right() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.update(MoveCursorCommand(1))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(4)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_right_multiple() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.update(MoveCursorCommand(2))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(5)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_right_from_offset_length() {
+ val eb = EditingBuffer("ABCDE", TextRange(5))
+
+ eb.update(MoveCursorCommand(1))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(5)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_left_surrogate_pair() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.update(MoveCursorCommand(-1))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH3$CH4$CH5")
+ assertThat(eb.cursor).isEqualTo(4)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_left_multiple_surrogate_pair() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.update(MoveCursorCommand(-2))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH3$CH4$CH5")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_right_surrogate_pair() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.update(MoveCursorCommand(1))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH3$CH4$CH5")
+ assertThat(eb.cursor).isEqualTo(8)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_right_multiple_surrogate_pair() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.update(MoveCursorCommand(2))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH3$CH4$CH5")
+ assertThat(eb.cursor).isEqualTo(10)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 26)
+ fun test_left_emoji() {
+ val eb = EditingBuffer("$FAMILY$FAMILY", TextRange(FAMILY.length))
+
+ eb.update(MoveCursorCommand(-1))
+
+ assertThat(eb.toString()).isEqualTo("$FAMILY$FAMILY")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 26)
+ fun test_right_emoji() {
+ val eb = EditingBuffer("$FAMILY$FAMILY", TextRange(FAMILY.length))
+
+ eb.update(MoveCursorCommand(1))
+
+ assertThat(eb.toString()).isEqualTo("$FAMILY$FAMILY")
+ assertThat(eb.cursor).isEqualTo(2 * FAMILY.length)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnectionTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnectionTest.kt
new file mode 100644
index 0000000..e04e539
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnectionTest.kt
@@ -0,0 +1,655 @@
+/*
+ * 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.input.internal
+
+import android.view.KeyEvent
+import android.view.inputmethod.EditorInfo
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.ImeOptions
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class StatelessInputConnectionTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ private lateinit var ic: StatelessInputConnection
+ private var activeSession: EditableTextInputSession? = null
+
+ private var isOpen: Boolean = true
+ private var value: TextFieldCharSequence = TextFieldCharSequence()
+ private var imeOptions: ImeOptions = ImeOptions.Default
+ private var onRequestEdits: ((List<EditCommand>) -> Unit)? = null
+ private var onSendKeyEvent: ((KeyEvent) -> Unit)? = null
+ private var onImeAction: ((ImeAction) -> Unit)? = null
+
+ private val activeSessionProvider: () -> EditableTextInputSession? = { activeSession }
+
+ @Before
+ fun setup() {
+ ic = StatelessInputConnection(activeSessionProvider)
+ activeSession = object : EditableTextInputSession {
+ override val isOpen: Boolean
+ get() = this@StatelessInputConnectionTest.isOpen
+
+ override val value: TextFieldCharSequence
+ get() = this@StatelessInputConnectionTest.value
+
+ override val imeOptions: ImeOptions
+ get() = this@StatelessInputConnectionTest.imeOptions
+
+ override fun setFilter(filter: TextEditFilter?) {
+ // Noop.
+ }
+
+ override fun showSoftwareKeyboard() {
+ // noop
+ }
+
+ override fun hideSoftwareKeyboard() {
+ // noop
+ }
+
+ override fun onImeAction(imeAction: ImeAction) {
+ this@StatelessInputConnectionTest.onImeAction?.invoke(imeAction)
+ }
+
+ override fun requestEdits(editCommands: List<EditCommand>) {
+ onRequestEdits?.invoke(editCommands)
+ }
+
+ override fun sendKeyEvent(keyEvent: KeyEvent) {
+ onSendKeyEvent?.invoke(keyEvent)
+ }
+
+ override fun dispose() {
+ this@StatelessInputConnectionTest.isOpen = false
+ }
+ }
+ }
+
+ @Test
+ fun getTextBeforeAndAfterCursorTest() {
+ assertThat(ic.getTextBeforeCursor(100, 0)).isEqualTo("")
+ assertThat(ic.getTextAfterCursor(100, 0)).isEqualTo("")
+
+ // Set "Hello, World", and place the cursor at the beginning of the text.
+ value = TextFieldCharSequence(
+ text = "Hello, World",
+ selection = TextRange.Zero
+ )
+
+ assertThat(ic.getTextBeforeCursor(100, 0)).isEqualTo("")
+ assertThat(ic.getTextAfterCursor(100, 0)).isEqualTo("Hello, World")
+
+ // Set "Hello, World", and place the cursor between "H" and "e".
+ value = TextFieldCharSequence(
+ text = "Hello, World",
+ selection = TextRange(1)
+ )
+
+ assertThat(ic.getTextBeforeCursor(100, 0)).isEqualTo("H")
+ assertThat(ic.getTextAfterCursor(100, 0)).isEqualTo("ello, World")
+
+ // Set "Hello, World", and place the cursor at the end of the text.
+ value = TextFieldCharSequence(
+ text = "Hello, World",
+ selection = TextRange(12)
+ )
+
+ assertThat(ic.getTextBeforeCursor(100, 0)).isEqualTo("Hello, World")
+ assertThat(ic.getTextAfterCursor(100, 0)).isEqualTo("")
+ }
+
+ @Test
+ fun getTextBeforeAndAfterCursorTest_maxCharTest() {
+ // Set "Hello, World", and place the cursor at the beginning of the text.
+ value = TextFieldCharSequence(
+ text = "Hello, World",
+ selection = TextRange.Zero
+ )
+
+ assertThat(ic.getTextBeforeCursor(5, 0)).isEqualTo("")
+ assertThat(ic.getTextAfterCursor(5, 0)).isEqualTo("Hello")
+
+ // Set "Hello, World", and place the cursor between "H" and "e".
+ value = TextFieldCharSequence(
+ text = "Hello, World",
+ selection = TextRange(1)
+ )
+
+ assertThat(ic.getTextBeforeCursor(5, 0)).isEqualTo("H")
+ assertThat(ic.getTextAfterCursor(5, 0)).isEqualTo("ello,")
+
+ // Set "Hello, World", and place the cursor at the end of the text.
+ value = TextFieldCharSequence(
+ text = "Hello, World",
+ selection = TextRange(12)
+ )
+
+ assertThat(ic.getTextBeforeCursor(5, 0)).isEqualTo("World")
+ assertThat(ic.getTextAfterCursor(5, 0)).isEqualTo("")
+ }
+
+ @Test
+ fun getSelectedTextTest() {
+ // Set "Hello, World", and place the cursor at the beginning of the text.
+ value = TextFieldCharSequence(
+ text = "Hello, World",
+ selection = TextRange.Zero
+ )
+
+ assertThat(ic.getSelectedText(0)).isNull()
+
+ // Set "Hello, World", and place the cursor between "H" and "e".
+ value = TextFieldCharSequence(
+ text = "Hello, World",
+ selection = TextRange(0, 1)
+ )
+
+ assertThat(ic.getSelectedText(0)).isEqualTo("H")
+
+ // Set "Hello, World", and place the cursor at the end of the text.
+ value = TextFieldCharSequence(
+ text = "Hello, World",
+ selection = TextRange(0, 12)
+ )
+
+ assertThat(ic.getSelectedText(0)).isEqualTo("Hello, World")
+ }
+
+ @Test
+ fun commitTextTest() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "", selection = TextRange.Zero)
+
+ // Inserting "Hello, " into the empty text field.
+ assertThat(ic.commitText("Hello, ", 1)).isTrue()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(1)
+ assertThat(editCommands[0]).isEqualTo(CommitTextCommand("Hello, ", 1))
+ }
+
+ @Test
+ fun commitTextTest_batchSession() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "", selection = TextRange.Zero)
+
+ // IME set text "Hello, World." with two commitText API within the single batch session.
+ // Do not callback to listener during batch session.
+ ic.beginBatchEdit()
+
+ assertThat(ic.commitText("Hello, ", 1)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ assertThat(ic.commitText("World.", 1)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ ic.endBatchEdit()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(2)
+ assertThat(editCommands[0]).isEqualTo(CommitTextCommand("Hello, ", 1))
+ assertThat(editCommands[1]).isEqualTo(CommitTextCommand("World.", 1))
+ }
+
+ @Test
+ fun setComposingRegion() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "Hello, World.", selection = TextRange.Zero)
+
+ // Mark first "H" as composition.
+ assertThat(ic.setComposingRegion(0, 1)).isTrue()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(1)
+ assertThat(editCommands[0]).isEqualTo(SetComposingRegionCommand(0, 1))
+ }
+
+ @Test
+ fun setComposingRegion_batchSession() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "Hello, World", selection = TextRange.Zero)
+
+ // Do not callback to listener during batch session.
+ ic.beginBatchEdit()
+
+ assertThat(ic.setComposingRegion(0, 1)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ assertThat(ic.setComposingRegion(1, 2)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ ic.endBatchEdit()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(2)
+ assertThat(editCommands[0]).isEqualTo(SetComposingRegionCommand(0, 1))
+ assertThat(editCommands[1]).isEqualTo(SetComposingRegionCommand(1, 2))
+ }
+
+ @Test
+ fun setComposingTextTest() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "", selection = TextRange.Zero)
+
+ // Inserting "Hello, " into the empty text field.
+ assertThat(ic.setComposingText("Hello, ", 1)).isTrue()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(1)
+ assertThat(editCommands[0]).isEqualTo(SetComposingTextCommand("Hello, ", 1))
+ }
+
+ @Test
+ fun setComposingTextTest_batchSession() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "", selection = TextRange.Zero)
+
+ // IME set text "Hello, World." with two setComposingText API within the single batch
+ // session. Do not callback to listener during batch session.
+ ic.beginBatchEdit()
+
+ assertThat(ic.setComposingText("Hello, ", 1)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ assertThat(ic.setComposingText("World.", 1)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ ic.endBatchEdit()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(2)
+ assertThat(editCommands[0]).isEqualTo(SetComposingTextCommand("Hello, ", 1))
+ assertThat(editCommands[1]).isEqualTo(SetComposingTextCommand("World.", 1))
+ }
+
+ @Test
+ fun deleteSurroundingText() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "Hello, World.", selection = TextRange.Zero)
+
+ // Delete first "Hello, " characters
+ assertTrue(ic.deleteSurroundingText(0, 6))
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(1)
+ assertThat(editCommands[0]).isEqualTo(DeleteSurroundingTextCommand(0, 6))
+ }
+
+ @Test
+ fun deleteSurroundingText_batchSession() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "Hello, World", selection = TextRange.Zero)
+
+ // Do not callback to listener during batch session.
+ ic.beginBatchEdit()
+
+ assertThat(ic.deleteSurroundingText(0, 6)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ assertThat(ic.deleteSurroundingText(0, 5)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ ic.endBatchEdit()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(2)
+ assertThat(editCommands[0]).isEqualTo(DeleteSurroundingTextCommand(0, 6))
+ assertThat(editCommands[1]).isEqualTo(DeleteSurroundingTextCommand(0, 5))
+ }
+
+ @Test
+ fun deleteSurroundingTextInCodePoints() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "Hello, World.", selection = TextRange.Zero)
+
+ // Delete first "Hello, " characters
+ assertThat(ic.deleteSurroundingTextInCodePoints(0, 6)).isTrue()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(1)
+ assertThat(editCommands[0]).isEqualTo(DeleteSurroundingTextInCodePointsCommand(0, 6))
+ }
+
+ @Test
+ fun deleteSurroundingTextInCodePoints_batchSession() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "Hello, World", selection = TextRange.Zero)
+
+ // Do not callback to listener during batch session.
+ ic.beginBatchEdit()
+
+ assertThat(ic.deleteSurroundingTextInCodePoints(0, 6)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ assertThat(ic.deleteSurroundingTextInCodePoints(0, 5)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ ic.endBatchEdit()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(2)
+ assertThat(editCommands[0]).isEqualTo(DeleteSurroundingTextInCodePointsCommand(0, 6))
+ assertThat(editCommands[1]).isEqualTo(DeleteSurroundingTextInCodePointsCommand(0, 5))
+ }
+
+ @Test
+ fun setSelection() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "Hello, World.", selection = TextRange.Zero)
+
+ // Select "Hello, "
+ assertThat(ic.setSelection(0, 6)).isTrue()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(1)
+ assertThat(editCommands[0]).isEqualTo(SetSelectionCommand(0, 6))
+ }
+
+ @Test
+ fun setSelection_batchSession() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "Hello, World", selection = TextRange.Zero)
+
+ // Do not callback to listener during batch session.
+ ic.beginBatchEdit()
+
+ assertThat(ic.setSelection(0, 6)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ assertThat(ic.setSelection(6, 11)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ ic.endBatchEdit()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(2)
+ assertThat(editCommands[0]).isEqualTo(SetSelectionCommand(0, 6))
+ assertThat(editCommands[1]).isEqualTo(SetSelectionCommand(6, 11))
+ }
+
+ @Test
+ fun finishComposingText() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "Hello, World.", selection = TextRange.Zero)
+
+ // Cancel any ongoing composition. In this example, there is no composition range, but
+ // should record the API call
+ assertTrue(ic.finishComposingText())
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(1)
+ assertThat(editCommands[0]).isEqualTo(FinishComposingTextCommand)
+ }
+
+ @Test
+ fun finishComposingText_batchSession() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "Hello, World", selection = TextRange.Zero)
+
+ // Do not callback to listener during batch session.
+ ic.beginBatchEdit()
+
+ assertThat(ic.finishComposingText()).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ assertThat(ic.finishComposingText()).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ ic.endBatchEdit()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(2)
+ assertThat(editCommands[0]).isEqualTo(FinishComposingTextCommand)
+ assertThat(editCommands[1]).isEqualTo(FinishComposingTextCommand)
+ }
+
+ @Test
+ fun mixedAPICalls_batchSession() {
+ var editCommands = listOf<EditCommand>()
+ var requestEditsCalled = 0
+ onRequestEdits = {
+ requestEditsCalled++
+ editCommands = it
+ }
+ value = TextFieldCharSequence(text = "", selection = TextRange.Zero)
+
+ // Do not callback to listener during batch session.
+ ic.beginBatchEdit()
+
+ assertThat(ic.setComposingText("Hello, ", 1)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ assertThat(ic.finishComposingText()).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ assertThat(ic.commitText("World.", 1)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ assertThat(ic.setSelection(0, 12)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ assertThat(ic.commitText("", 1)).isTrue()
+ assertThat(requestEditsCalled).isEqualTo(0)
+
+ ic.endBatchEdit()
+
+ assertThat(requestEditsCalled).isEqualTo(1)
+ assertThat(editCommands.size).isEqualTo(5)
+ assertThat(editCommands[0]).isEqualTo(SetComposingTextCommand("Hello, ", 1))
+ assertThat(editCommands[1]).isEqualTo(FinishComposingTextCommand)
+ assertThat(editCommands[2]).isEqualTo(CommitTextCommand("World.", 1))
+ assertThat(editCommands[3]).isEqualTo(SetSelectionCommand(0, 12))
+ assertThat(editCommands[4]).isEqualTo(CommitTextCommand("", 1))
+ }
+
+ @Test
+ fun closeConnection() {
+ // Everything is internal and there is nothing to expect.
+ // Just make sure it is not crashed by calling method.
+ ic.closeConnection()
+ }
+
+ @Test
+ fun do_not_callback_if_only_readonly_ops() {
+ var requestEditsCalled = 0
+ onRequestEdits = { requestEditsCalled++ }
+ ic.beginBatchEdit()
+ ic.getSelectedText(1)
+ ic.endBatchEdit()
+ assertThat(requestEditsCalled).isEqualTo(0)
+ }
+
+ @Test
+ fun sendKeyEvent_whenIMERequests() {
+ val keyEvents = mutableListOf<KeyEvent>()
+ onSendKeyEvent = {
+ keyEvents += it
+ }
+ val keyEvent1 = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0)
+ val keyEvent2 = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0)
+ ic.sendKeyEvent(keyEvent1)
+ ic.sendKeyEvent(keyEvent2)
+
+ assertThat(keyEvents.size).isEqualTo(2)
+ assertThat(keyEvents.first()).isEqualTo(keyEvent1)
+ assertThat(keyEvents.last()).isEqualTo(keyEvent2)
+ }
+
+ @Test
+ fun sendKeyEvent_noActiveSession() {
+ val keyEvents = mutableListOf<KeyEvent>()
+ onSendKeyEvent = {
+ keyEvents += it
+ }
+ val keyEvent1 = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0)
+ val keyEvent2 = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0)
+ activeSession = null
+
+ ic.sendKeyEvent(keyEvent1)
+ ic.sendKeyEvent(keyEvent2)
+
+ assertThat(keyEvents.size).isEqualTo(0)
+ }
+
+ @Test
+ fun performImeAction_whenIMERequests() {
+ val receivedImeActions = mutableListOf<ImeAction>()
+ onImeAction = {
+ receivedImeActions += it
+ }
+ ic.performEditorAction(EditorInfo.IME_ACTION_DONE)
+ ic.performEditorAction(EditorInfo.IME_ACTION_GO)
+ ic.performEditorAction(EditorInfo.IME_ACTION_NEXT)
+ ic.performEditorAction(EditorInfo.IME_ACTION_NONE)
+ ic.performEditorAction(EditorInfo.IME_ACTION_PREVIOUS)
+ ic.performEditorAction(EditorInfo.IME_ACTION_SEARCH)
+ ic.performEditorAction(EditorInfo.IME_ACTION_SEND)
+ ic.performEditorAction(EditorInfo.IME_ACTION_UNSPECIFIED)
+ ic.performEditorAction(-1)
+
+ assertThat(receivedImeActions).isEqualTo(listOf(
+ ImeAction.Done,
+ ImeAction.Go,
+ ImeAction.Next,
+ ImeAction.Default, // None is evaluated back to Default.
+ ImeAction.Previous,
+ ImeAction.Search,
+ ImeAction.Send,
+ ImeAction.Default, // Unspecified is evaluated back to Default.
+ ImeAction.Default // Unrecognized is evaluated back to Default.
+ ))
+ }
+
+ @Test
+ fun performImeAction_noActiveSession() {
+ val receivedImeActions = mutableListOf<ImeAction>()
+ onImeAction = {
+ receivedImeActions += it
+ }
+ activeSession = null
+ ic.performEditorAction(EditorInfo.IME_ACTION_DONE)
+ ic.performEditorAction(EditorInfo.IME_ACTION_GO)
+ ic.performEditorAction(EditorInfo.IME_ACTION_NEXT)
+ ic.performEditorAction(EditorInfo.IME_ACTION_NONE)
+ ic.performEditorAction(EditorInfo.IME_ACTION_PREVIOUS)
+ ic.performEditorAction(EditorInfo.IME_ACTION_SEARCH)
+ ic.performEditorAction(EditorInfo.IME_ACTION_SEND)
+ ic.performEditorAction(EditorInfo.IME_ACTION_UNSPECIFIED)
+ ic.performEditorAction(-1)
+
+ assertThat(receivedImeActions).isEqualTo(listOf<ImeAction>())
+ }
+
+ @Test
+ fun debugMode_isDisabled() {
+ // run this in presubmit to check that we are not accidentally enabling logs on prod
+ assertFalse(
+ SIC_DEBUG,
+ "Oops, looks like you accidentally enabled logging. Don't worry, we've all " +
+ "been there. Just remember to turn it off before you deploy your code."
+ )
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldSelectionTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldSelectionTest.kt
index 5abb731..b2182be 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldSelectionTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldSelectionTest.kt
@@ -23,6 +23,9 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.platform.LocalTextToolbar
+import androidx.compose.ui.platform.TextToolbar
+import androidx.compose.ui.platform.TextToolbarStatus
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertCountEquals
import androidx.compose.ui.test.assertIsDisplayed
@@ -143,6 +146,37 @@
}
@Test
+ fun textField_tapsCursorHandle_showsTextToolbar() {
+ val textFieldValue = mutableStateOf(TextFieldValue("text"))
+ lateinit var textToolbar: TextToolbar
+
+ rule.setContent {
+ textToolbar = LocalTextToolbar.current
+ BasicTextField(
+ value = textFieldValue.value,
+ onValueChange = { textFieldValue.value = it },
+ modifier = Modifier.testTag(testTag)
+ )
+ }
+
+ // selection and cursor are hidden
+ rule.onAllNodes(isPopup()).assertCountEquals(0)
+ assertThat(textToolbar.status).isEqualTo(TextToolbarStatus.Hidden)
+
+ // focus textfield, cursor should show at the very beginning of textfield
+ rule.onNodeWithTag(testTag).performTouchInput { click(Offset.Zero) }
+ rule.waitForIdle()
+
+ assertThat(textFieldValue.value.selection.start).isEqualTo(0)
+ assertThat(textToolbar.status).isEqualTo(TextToolbarStatus.Hidden)
+
+ rule.onNode(isSelectionHandle(Handle.Cursor))
+ .performTouchInput { click() }
+
+ assertThat(textToolbar.status).isEqualTo(TextToolbarStatus.Shown)
+ }
+
+ @Test
fun textField_dragsCursorHandle() {
textField_dragsCursorHandle(
text = "text text text",
@@ -176,7 +210,9 @@
) {
val textFieldValue = mutableStateOf(TextFieldValue(text, TextRange(Int.MAX_VALUE)))
val cursorPositions = mutableListOf<Int>()
+ lateinit var textToolbar: TextToolbar
rule.setContent {
+ textToolbar = LocalTextToolbar.current
BasicTextField(
value = textFieldValue.value,
onValueChange = {
@@ -194,16 +230,19 @@
// selection and cursor are hidden
rule.onAllNodes(isPopup()).assertCountEquals(0)
+ assertThat(textToolbar.status).isEqualTo(TextToolbarStatus.Hidden)
// focus textfield, cursor should show at the very beginning of textfield
rule.onNodeWithTag(testTag).performTouchInput { click(Offset.Zero) }
rule.waitForIdle()
assertThat(textFieldValue.value.selection.start).isEqualTo(0)
+ assertThat(textToolbar.status).isEqualTo(TextToolbarStatus.Hidden)
performHandleDrag(Handle.Cursor, false)
assertThat(cursorPositions).isEqualTo(expectedCursorPositions)
+ assertThat(textToolbar.status).isEqualTo(TextToolbarStatus.Hidden)
}
@Ignore // b/265023621
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldTest.kt
index cbb944d..1f57f12 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldTest.kt
@@ -1250,6 +1250,7 @@
assertThat(actual).isEqualTo(expected)
}
+ @Ignore // b/284408746
@OptIn(ExperimentalTestApi::class)
@Test
fun whenPartiallySelectedTextIsRemoved_SelectionCoercesToEdges() {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldVisualTransformationSelectionBoundsTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldVisualTransformationSelectionBoundsTest.kt
index aecaba0..2d28354 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldVisualTransformationSelectionBoundsTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldVisualTransformationSelectionBoundsTest.kt
@@ -156,6 +156,7 @@
assertValidMessage(error, sourceIndex = null, toTransformed = false)
}
+ @Ignore // b/268254956
@Test
fun selectionStart_throws_onStart_whenInvalidOriginalToTransformed() {
rule.runOnIdle {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/res/drawable-nodpi/webp_test.webp b/compose/foundation/foundation/src/androidAndroidTest/res/drawable-nodpi/webp_test.webp
new file mode 100644
index 0000000..7b1009f
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/res/drawable-nodpi/webp_test.webp
Binary files differ
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher.android.kt
index db7cb63..eddfb44 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher.android.kt
@@ -145,7 +145,8 @@
// a next frame callback in which we will post the message in the handler again.
if (enoughTimeLeft(beforeTimeNs, nextFrameNs, timeTracker.compositionTimeNs)) {
val key = itemProvider.getKey(request.index)
- val content = itemContentFactory.getContent(request.index, key)
+ val contentType = itemProvider.getContentType(request.index)
+ val content = itemContentFactory.getContent(request.index, key, contentType)
timeTracker.trackComposition {
request.precomposeHandle =
subcomposeLayoutState.precompose(key, content)
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicSecureTextField.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicSecureTextField.kt
new file mode 100644
index 0000000..81e3f04
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicSecureTextField.kt
@@ -0,0 +1,306 @@
+/*
+ * 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
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.ScrollState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.foundation.text2.input.CodepointTransformation
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldBufferWithSelection
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldLineLimits
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.TextObfuscationMode
+import androidx.compose.foundation.text2.input.mask
+import androidx.compose.foundation.text2.input.then
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.onFocusChanged
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.semantics.password
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.unit.Density
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.consumeAsFlow
+import kotlinx.coroutines.launch
+
+/**
+ * BasicSecureTextField is a new text input component that is still in heavy development.
+ * We strongly advise against using it in production as its API and implementation are currently
+ * unstable. Many essential features such as selection, cursor, gestures, etc. may not work
+ * correctly or may not even exist yet.
+ *
+ * BasicSecureTextField is specifically designed for password entry fields and is a preconfigured
+ * alternative to BasicTextField2. It only supports a single line of content and comes with default
+ * settings for KeyboardOptions, filter, and codepointTransformation that are appropriate for
+ * entering secure content. Additionally, some context menu actions like cut, copy, and drag are
+ * disabled for added security.
+ *
+ * @param state [TextFieldState] object that holds the internal state of a [BasicTextField2].
+ * @param modifier optional [Modifier] for this text field.
+ * @param enabled controls the enabled state of the [BasicTextField2]. When `false`, the text
+ * field will be neither editable nor focusable, the input of the text field will not be selectable.
+ * @param onSubmit Called when the user submits a form either by pressing the action button in the
+ * input method editor (IME), or by pressing the enter key on a hardware keyboard. If the user
+ * submits the form by pressing the action button in the IME, the provided IME action is passed to
+ * the function. If the user submits the form by pressing the enter key on a hardware keyboard,
+ * the defined [imeAction] parameter is passed to the function. Return true to indicate that the
+ * action has been handled completely, which will skip the default behavior, such as hiding the
+ * keyboard for the [ImeAction.Done] action.
+ * @param imeAction The IME action. This IME action is honored by keyboard and may show specific
+ * icons on the keyboard.
+ * @param textObfuscationMode Determines the method used to obscure the input text.
+ * @param keyboardType The keyboard type to be used in this text field. It is set to
+ * [KeyboardType.Password] by default. Use [KeyboardType.NumberPassword] for numerical password
+ * fields.
+ * @param filter Optional [TextEditFilter] that will be used to filter changes to the
+ * [TextFieldState] made by the user. The filter will be applied to changes made by hardware and
+ * software keyboard events, pasting or dropping text, accessibility services, and tests. The filter
+ * will _not_ be applied when changing the [state] programmatically, or when the filter is changed.
+ * If the filter is changed on an existing text field, it will be applied to the next user edit.
+ * the filter will not immediately affect the current [state].
+ * @param textStyle Style configuration for text content that's displayed in the editor.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this TextField. You can create and pass in your own remembered [MutableInteractionSource]
+ * if you want to observe [Interaction]s and customize the appearance / behavior of this TextField
+ * for different [Interaction]s.
+ * @param cursorBrush [Brush] to paint cursor with. If [SolidColor] with [Color.Unspecified]
+ * provided, there will be no cursor drawn
+ * @param scrollState Used to manage the horizontal scroll when the input content exceeds the
+ * bounds of the text field. It controls the state of the scroll for the text field.
+ * @param onTextLayout Callback that is executed when a new text layout is calculated. A
+ * [TextLayoutResult] object that callback provides contains paragraph information, size of the
+ * text, baselines and other details. The callback can be used to add additional decoration or
+ * functionality to the text. For example, to draw a cursor or selection around the text. [Density]
+ * scope is the one that was used while creating the given text layout.
+ * @param decorationBox Composable lambda that allows to add decorations around text field, such
+ * as icon, placeholder, helper messages or similar, and automatically increase the hit target area
+ * of the text field. To allow you to control the placement of the inner text field relative to your
+ * decorations, the text field implementation will pass in a framework-controlled composable
+ * parameter "innerTextField" to the decorationBox lambda you provide. You must call
+ * innerTextField exactly once.
+ */
+@ExperimentalFoundationApi
+@Composable
+fun BasicSecureTextField(
+ state: TextFieldState,
+ modifier: Modifier = Modifier,
+ onSubmit: ((ImeAction) -> Boolean)? = null,
+ imeAction: ImeAction = ImeAction.Default,
+ textObfuscationMode: TextObfuscationMode = TextObfuscationMode.RevealLastTyped,
+ keyboardType: KeyboardType = KeyboardType.Password,
+ enabled: Boolean = true,
+ filter: TextEditFilter? = null,
+ textStyle: TextStyle = TextStyle.Default,
+ interactionSource: MutableInteractionSource? = null,
+ cursorBrush: Brush = SolidColor(Color.Black),
+ scrollState: ScrollState = rememberScrollState(),
+ onTextLayout: Density.(TextLayoutResult) -> Unit = {},
+ decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
+ @Composable { innerTextField -> innerTextField() }
+) {
+ val coroutineScope = rememberCoroutineScope()
+ val secureTextFieldController = remember(coroutineScope) {
+ SecureTextFieldController(coroutineScope)
+ }
+
+ // revealing last typed character depends on two conditions;
+ // 1 - Requested Obfuscation method
+ // 2 - if the system allows it
+ val revealLastTypedEnabled = textObfuscationMode == TextObfuscationMode.RevealLastTyped
+
+ // while toggling between obfuscation methods if the revealing gets disabled, reset the reveal.
+ if (!revealLastTypedEnabled) {
+ secureTextFieldController.passwordRevealFilter.hide()
+ }
+
+ val codepointTransformation = when {
+ revealLastTypedEnabled -> {
+ secureTextFieldController.codepointTransformation
+ }
+
+ textObfuscationMode == TextObfuscationMode.Hidden -> {
+ CodepointTransformation.mask('\u2022')
+ }
+
+ else -> {
+ CodepointTransformation.None
+ }
+ }
+
+ val secureTextFieldModifier = modifier
+ .semantics(mergeDescendants = true) { password() }
+ .then(
+ if (revealLastTypedEnabled) {
+ secureTextFieldController.focusChangeModifier
+ } else {
+ Modifier
+ }
+ )
+
+ BasicTextField2(
+ state = state,
+ modifier = secureTextFieldModifier,
+ enabled = enabled,
+ readOnly = false,
+ filter = if (revealLastTypedEnabled) {
+ filter?.then(secureTextFieldController.passwordRevealFilter)
+ ?: secureTextFieldController.passwordRevealFilter
+ } else filter,
+ textStyle = textStyle,
+ interactionSource = interactionSource,
+ cursorBrush = cursorBrush,
+ lineLimits = TextFieldLineLimits.SingleLine,
+ scrollState = scrollState,
+ keyboardOptions = KeyboardOptions(
+ autoCorrect = false,
+ keyboardType = keyboardType,
+ imeAction = imeAction
+ ),
+ keyboardActions = onSubmit?.let { KeyboardActions(onSubmit = it) }
+ ?: KeyboardActions.Default,
+ onTextLayout = onTextLayout,
+ codepointTransformation = codepointTransformation,
+ decorationBox = decorationBox,
+ )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+internal class SecureTextFieldController(
+ coroutineScope: CoroutineScope
+) {
+ /**
+ * A special [TextEditFilter] that tracks changes to the content to identify the last typed
+ * character to reveal. `scheduleHide` lambda is delegated to a member function to be able to
+ * use [passwordRevealFilter] instance.
+ */
+ val passwordRevealFilter = PasswordRevealFilter(::scheduleHide)
+
+ /**
+ * Pass to [BasicTextField2] for obscuring text input.
+ */
+ val codepointTransformation = CodepointTransformation { codepointIndex, codepoint ->
+ if (codepointIndex == passwordRevealFilter.revealCodepointIndex) {
+ // reveal the last typed character by not obscuring it
+ codepoint
+ } else {
+ 0x2022
+ }
+ }
+
+ val focusChangeModifier = Modifier.onFocusChanged {
+ if (!it.isFocused) passwordRevealFilter.hide()
+ }
+
+ private val resetTimerSignal = Channel<Unit>(Channel.UNLIMITED)
+
+ init {
+ // start a coroutine that listens for scheduled hide events.
+ coroutineScope.launch {
+ resetTimerSignal.consumeAsFlow()
+ .collectLatest {
+ delay(LAST_TYPED_CHARACTER_REVEAL_DURATION_MILLIS)
+ passwordRevealFilter.hide()
+ }
+ }
+ }
+
+ private fun scheduleHide() {
+ // signal the listener that a new hide call is scheduled.
+ val result = resetTimerSignal.trySend(Unit)
+ if (!result.isSuccess) {
+ passwordRevealFilter.hide()
+ }
+ }
+}
+
+/**
+ * Special filter that tracks the changes in a TextField to identify the last typed character and
+ * mark it for reveal in password fields.
+ *
+ * @param scheduleHide A lambda that schedules a [hide] call into future after a new character is
+ * typed.
+ */
+@OptIn(ExperimentalFoundationApi::class)
+internal class PasswordRevealFilter(
+ val scheduleHide: () -> Unit
+) : TextEditFilter {
+ // TODO: Consider setting this as a tracking annotation in AnnotatedString.
+ internal var revealCodepointIndex by mutableIntStateOf(-1)
+ private set
+
+ override fun filter(
+ originalValue: TextFieldCharSequence,
+ valueWithChanges: TextFieldBufferWithSelection
+ ) {
+ // We only care about a single character insertion changes
+ val singleCharacterInsertion = valueWithChanges.changes.changeCount == 1 &&
+ valueWithChanges.changes.getRange(0).length == 1 &&
+ valueWithChanges.changes.getOriginalRange(0).length == 0
+
+ // if there is an expanded selection, don't reveal anything
+ if (!singleCharacterInsertion || valueWithChanges.hasSelection) {
+ revealCodepointIndex = -1
+ return
+ }
+
+ val insertionPoint = valueWithChanges.changes.getRange(0).min
+ if (revealCodepointIndex != insertionPoint) {
+ // start the timer for auto hide
+ scheduleHide()
+ revealCodepointIndex = insertionPoint
+ }
+ }
+
+ /**
+ * Removes any revealed character index. Everything goes back into hiding.
+ */
+ fun hide() {
+ revealCodepointIndex = -1
+ }
+}
+
+// adopted from PasswordTransformationMethod from Android platform.
+private const val LAST_TYPED_CHARACTER_REVEAL_DURATION_MILLIS = 1500L
+
+private fun KeyboardActions(onSubmit: (ImeAction) -> Boolean) = KeyboardActions(
+ onDone = { if (!onSubmit(ImeAction.Done)) defaultKeyboardAction(ImeAction.Done) },
+ onGo = { if (!onSubmit(ImeAction.Go)) defaultKeyboardAction(ImeAction.Go) },
+ onNext = { if (!onSubmit(ImeAction.Next)) defaultKeyboardAction(ImeAction.Next) },
+ onPrevious = { if (!onSubmit(ImeAction.Previous)) defaultKeyboardAction(ImeAction.Previous) },
+ onSearch = { if (!onSubmit(ImeAction.Search)) defaultKeyboardAction(ImeAction.Search) },
+ onSend = { if (!onSubmit(ImeAction.Send)) defaultKeyboardAction(ImeAction.Send) },
+)
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt
new file mode 100644
index 0000000..90bfb89
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt
@@ -0,0 +1,273 @@
+/*
+ * 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
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.ScrollState
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.ScrollableDefaults
+import androidx.compose.foundation.gestures.scrollable
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.collectIsFocusedAsState
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.text.InternalFoundationTextApi
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.foundation.text.TextDelegate
+import androidx.compose.foundation.text.heightInLines
+import androidx.compose.foundation.text.textFieldMinSize
+import androidx.compose.foundation.text2.input.CodepointTransformation
+import androidx.compose.foundation.text2.input.SingleLineCodepointTransformation
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldLineLimits
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.internal.AndroidTextInputPlugin
+import androidx.compose.foundation.text2.input.internal.TextFieldCoreModifier
+import androidx.compose.foundation.text2.input.internal.TextFieldDecoratorModifier
+import androidx.compose.foundation.text2.input.internal.TextLayoutState
+import androidx.compose.foundation.text2.input.toVisualText
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clipToBounds
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.layout.FirstBaseline
+import androidx.compose.ui.layout.LastBaseline
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalFontFamilyResolver
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.LocalPlatformTextInputPluginRegistry
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.unit.Density
+import kotlin.math.roundToInt
+
+/**
+ * BasicTextField2 is a new text input Composable under heavy development. Please refrain from
+ * using it in production since it has a very unstable API and implementation for the time being.
+ * Many core features like selection, cursor, gestures, etc. may fail or simply not exist.
+ *
+ * Basic text composable that provides an interactive box that accepts text input through software
+ * or hardware keyboard.
+ *
+ * All the editing state of this composable is hoisted through [state]. Whenever the contents of
+ * this composable change via user input or semantics, [TextFieldState.text] gets updated.
+ * Similarly, all the programmatic updates made to [state] also reflect on this composable.
+ *
+ * @param state [TextFieldState] object that holds the internal editing state of [BasicTextField2].
+ * @param modifier optional [Modifier] for this text field.
+ * @param enabled controls the enabled state of the [BasicTextField2]. When `false`, the text
+ * field will be neither editable nor focusable, the input of the text field will not be selectable.
+ * @param readOnly controls the editable state of the [BasicTextField2]. When `true`, the text
+ * field can not be modified, however, a user can focus it and copy text from it. Read-only text
+ * fields are usually used to display pre-filled forms that user can not edit.
+ * @param filter Optional [TextEditFilter] that will be used to filter changes to the
+ * [TextFieldState] made by the user. The filter will be applied to changes made by hardware and
+ * software keyboard events, pasting or dropping text, accessibility services, and tests. The filter
+ * will _not_ be applied when changing the [state] programmatically, or when the filter is changed.
+ * If the filter is changed on an existing text field, it will be applied to the next user edit.
+ * the filter will not immediately affect the current [state].
+ * @param textStyle Typographic and graphic style configuration for text content that's displayed
+ * in the editor.
+ * @param keyboardOptions Software keyboard options that contain configurations such as
+ * [KeyboardType] and [ImeAction].
+ * @param keyboardActions When the input service emits an IME action, the corresponding callback
+ * is called. Note that this IME action may be different from what you specified in
+ * [KeyboardOptions.imeAction].
+ * @param lineLimits Whether the text field should be [SingleLine], scroll horizontally, and
+ * ignore newlines; or [MultiLine] and grow and scroll vertically. If [SingleLine] is passed without
+ * specifying the [codepointTransformation] parameter, a [CodepointTransformation] is automatically
+ * applied. This transformation replaces any newline characters ('\n') within the text with regular
+ * whitespace (' '), ensuring that the contents of the text field are presented in a single line.
+ * @param onTextLayout Callback that is executed when a new text layout is calculated. A
+ * [TextLayoutResult] object contains paragraph information, size of the text, baselines and other
+ * details. The callback can be used to add additional decoration or functionality to the text.
+ * For example, to draw a cursor or selection around the text. [Density] scope is the one that was
+ * used while creating the given text layout.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this TextField. You can create and pass in your own remembered [MutableInteractionSource]
+ * if you want to observe [Interaction]s and customize the appearance / behavior of this TextField
+ * for different [Interaction]s.
+ * @param cursorBrush [Brush] to paint cursor with. If [SolidColor] with [Color.Unspecified]
+ * provided, then no cursor will be drawn.
+ * @param scrollState Scroll state that manages either horizontal or vertical scroll of TextField.
+ * If [lineLimits] is [SingleLine], this text field is treated as single line with horizontal
+ * scroll behavior. In other cases the text field becomes vertically scrollable.
+ * @param codepointTransformation Visual transformation interface that provides a 1-to-1 mapping of
+ * codepoints.
+ * @param decorationBox Composable lambda that allows to add decorations around text field, such
+ * as icon, placeholder, helper messages or similar, and automatically increase the hit target area
+ * of the text field. To allow you to control the placement of the inner text field relative to your
+ * decorations, the text field implementation will pass in a framework-controlled composable
+ * parameter "innerTextField" to the decorationBox lambda you provide. You must call
+ * innerTextField exactly once.
+ */
+@ExperimentalFoundationApi
+@OptIn(InternalFoundationTextApi::class)
+@Composable
+fun BasicTextField2(
+ state: TextFieldState,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ readOnly: Boolean = false,
+ filter: TextEditFilter? = null,
+ textStyle: TextStyle = TextStyle.Default,
+ keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
+ keyboardActions: KeyboardActions = KeyboardActions.Default,
+ lineLimits: TextFieldLineLimits = TextFieldLineLimits.Default,
+ onTextLayout: Density.(TextLayoutResult) -> Unit = {},
+ interactionSource: MutableInteractionSource? = null,
+ cursorBrush: Brush = SolidColor(Color.Black),
+ scrollState: ScrollState = rememberScrollState(),
+ codepointTransformation: CodepointTransformation? = null,
+ decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
+ @Composable { innerTextField -> innerTextField() }
+) {
+ // only read from local and create an adapter if this text field is enabled and editable
+ val textInputAdapter = LocalPlatformTextInputPluginRegistry.takeIf { enabled && !readOnly }
+ ?.current?.rememberAdapter(AndroidTextInputPlugin)
+
+ val fontFamilyResolver = LocalFontFamilyResolver.current
+ val density = LocalDensity.current
+ val layoutDirection = LocalLayoutDirection.current
+ val singleLine = lineLimits == SingleLine
+ // We're using this to communicate focus state to cursor for now.
+ @Suppress("NAME_SHADOWING")
+ val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
+
+ val orientation = if (singleLine) Orientation.Horizontal else Orientation.Vertical
+
+ val textLayoutState = remember {
+ TextLayoutState(
+ TextDelegate(
+ text = AnnotatedString(state.text.toString()),
+ style = textStyle,
+ density = density,
+ fontFamilyResolver = fontFamilyResolver,
+ softWrap = true,
+ placeholders = emptyList()
+ )
+ )
+ }
+
+ val decorationModifiers = modifier
+ .then(
+ // semantics + some focus + input session + touch to focus
+ TextFieldDecoratorModifier(
+ textFieldState = state,
+ textLayoutState = textLayoutState,
+ textInputAdapter = textInputAdapter,
+ filter = filter,
+ enabled = enabled,
+ readOnly = readOnly,
+ keyboardOptions = keyboardOptions,
+ keyboardActions = keyboardActions,
+ singleLine = singleLine,
+ )
+ )
+ .focusable(interactionSource = interactionSource, enabled = enabled)
+ .scrollable(
+ orientation = orientation,
+ reverseDirection = ScrollableDefaults.reverseDirection(
+ layoutDirection = layoutDirection,
+ orientation = orientation,
+ reverseScrolling = false
+ ),
+ state = scrollState,
+ interactionSource = interactionSource,
+ enabled = enabled && scrollState.maxValue > 0
+ )
+
+ Box(decorationModifiers, propagateMinConstraints = true) {
+ decorationBox(innerTextField = {
+ val minLines: Int
+ val maxLines: Int
+ if (lineLimits is MultiLine) {
+ minLines = lineLimits.minHeightInLines
+ maxLines = lineLimits.maxHeightInLines
+ } else {
+ minLines = 1
+ maxLines = 1
+ }
+
+ val coreModifiers = Modifier
+ .heightInLines(
+ textStyle = textStyle,
+ minLines = minLines,
+ maxLines = maxLines
+ )
+ .textFieldMinSize(textStyle)
+ .clipToBounds()
+ .then(
+ TextFieldCoreModifier(
+ isFocused = interactionSource.collectIsFocusedAsState().value,
+ textLayoutState = textLayoutState,
+ textFieldState = state,
+ cursorBrush = cursorBrush,
+ writeable = enabled && !readOnly,
+ scrollState = scrollState,
+ orientation = orientation
+ )
+ )
+
+ Layout(modifier = coreModifiers) { _, constraints ->
+ val result = with(textLayoutState) {
+ // First prefer provided codepointTransformation if not null, e.g.
+ // BasicSecureTextField would send Password Transformation.
+ // Second, apply a SingleLineCodepointTransformation if text field is configured
+ // to be single line.
+ // Else, don't apply any visual transformation.
+ val appliedCodepointTransformation = codepointTransformation
+ ?: SingleLineCodepointTransformation.takeIf { lineLimits == SingleLine }
+
+ val visualText = state.text.toVisualText(appliedCodepointTransformation)
+ layout(
+ text = AnnotatedString(visualText.toString()),
+ textStyle = textStyle,
+ softWrap = !singleLine,
+ density = density,
+ fontFamilyResolver = fontFamilyResolver,
+ constraints = constraints,
+ onTextLayout = onTextLayout
+ )
+ }
+
+ // TODO: min height
+
+ layout(
+ width = result.size.width,
+ height = result.size.height,
+ alignmentLines = mapOf(
+ FirstBaseline to result.firstBaseline.roundToInt(),
+ LastBaseline to result.lastBaseline.roundToInt()
+ )
+ ) {}
+ }
+ })
+ }
+}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/AllCapsFilter.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/AllCapsFilter.kt
new file mode 100644
index 0000000..ce7b0ad
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/AllCapsFilter.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.runtime.Stable
+import androidx.compose.ui.text.input.KeyboardCapitalization
+import androidx.compose.ui.text.intl.Locale
+import androidx.compose.ui.text.toUpperCase
+
+/**
+ * Returns a [TextEditFilter] that forces all text to be uppercase.
+ *
+ * This filter automatically configures the keyboard to capitalize all characters.
+ *
+ * @param locale The [Locale] in which to perform the case conversion.
+ */
+@ExperimentalFoundationApi
+@Stable
+fun TextEditFilter.Companion.allCaps(locale: Locale): TextEditFilter = AllCapsFilter(locale)
+
+// This is a very naive implementation for now, not intended to be production-ready.
+@OptIn(ExperimentalFoundationApi::class)
+private data class AllCapsFilter(private val locale: Locale) : TextEditFilter {
+ override val keyboardOptions = KeyboardOptions(
+ capitalization = KeyboardCapitalization.Characters
+ )
+
+ override fun filter(
+ originalValue: TextFieldCharSequence,
+ valueWithChanges: TextFieldBufferWithSelection
+ ) {
+ val selection = valueWithChanges.selectionInCodepoints
+ valueWithChanges.replace(
+ 0,
+ valueWithChanges.length,
+ valueWithChanges.toString().toUpperCase(locale)
+ )
+ valueWithChanges.selectCodepointsIn(selection)
+ }
+
+ override fun toString(): String = "TextEditFilter.allCaps(locale=$locale)"
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/CodepointTransformation.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/CodepointTransformation.kt
new file mode 100644
index 0000000..df7909b
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/CodepointTransformation.kt
@@ -0,0 +1,119 @@
+/*
+ * 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.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.appendCodePointX
+import androidx.compose.runtime.Stable
+
+/**
+ * Visual transformation interface for input fields.
+ *
+ * This interface is responsible for 1-to-1 mapping of every codepoint in input state to another
+ * codepoint before text is rendered. Visual transformation is useful when the underlying source
+ * of input needs to remain but rendered content should look different, e.g. password obscuring.
+ */
+@ExperimentalFoundationApi
+fun interface CodepointTransformation {
+
+ /**
+ * Transforms a single [codepoint] located at [codepointIndex] to another codepoint.
+ *
+ * A codepoint is an integer that always maps to a single character. Every codepoint in Unicode
+ * is comprised of 16 bits, 2 bytes.
+ */
+ // TODO: add more codepoint explanation or doc referral
+ fun transform(codepointIndex: Int, codepoint: Int): Int
+
+ companion object {
+
+ @Stable
+ val None = CodepointTransformation { _, codepoint -> codepoint }
+ }
+}
+
+/**
+ * Creates a masking [CodepointTransformation] that maps all codepoints to a specific [character].
+ */
+@ExperimentalFoundationApi
+fun CodepointTransformation.Companion.mask(character: Char): CodepointTransformation =
+ MaskCodepointTransformation(character)
+
+@OptIn(ExperimentalFoundationApi::class)
+private class MaskCodepointTransformation(val character: Char) : CodepointTransformation {
+ override fun transform(codepointIndex: Int, codepoint: Int): Int {
+ return character.code
+ }
+
+ override fun toString(): String {
+ return "MaskCodepointTransformation(character=$character)"
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is MaskCodepointTransformation) return false
+
+ if (character != other.character) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ return character.hashCode()
+ }
+}
+
+/**
+ * [CodepointTransformation] that converts all line breaks (\n) into white space(U+0020) and
+ * carriage returns(\r) to zero-width no-break space (U+FEFF). This transformation forces any
+ * content to appear as single line.
+ */
+@OptIn(ExperimentalFoundationApi::class)
+internal object SingleLineCodepointTransformation : CodepointTransformation {
+
+ private const val LINE_FEED = '\n'.code
+ private const val CARRIAGE_RETURN = '\r'.code
+
+ private const val WHITESPACE = ' '.code
+ private const val ZERO_WIDTH_SPACE = '\uFEFF'.code
+
+ override fun transform(codepointIndex: Int, codepoint: Int): Int {
+ if (codepoint == LINE_FEED) return WHITESPACE
+ if (codepoint == CARRIAGE_RETURN) return ZERO_WIDTH_SPACE
+ return codepoint
+ }
+
+ override fun toString(): String {
+ return "SingleLineCodepointTransformation"
+ }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+internal fun CharSequence.toVisualText(
+ codepointTransformation: CodepointTransformation?
+): CharSequence {
+ codepointTransformation ?: return this
+ val text = this
+ return buildString {
+ (0 until Character.codePointCount(text, 0, text.length)).forEach { codepointIndex ->
+ val codepoint = codepointTransformation.transform(
+ codepointIndex, Character.codePointAt(text, codepointIndex)
+ )
+ appendCodePointX(codepoint)
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MaxLengthFilter.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MaxLengthFilter.kt
new file mode 100644
index 0000000..f4b8ab3
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MaxLengthFilter.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.runtime.Stable
+
+/**
+ * Returns [TextEditFilter] that rejects input which causes the total length of the text field to be
+ * more than [maxLength] characters.
+ *
+ * @see maxLengthInCodepoints
+ */
+@ExperimentalFoundationApi
+@Stable
+fun TextEditFilter.Companion.maxLengthInChars(maxLength: Int): TextEditFilter =
+ MaxLengthFilter(maxLength, inCodepoints = false)
+
+/**
+ * Returns a [TextEditFilter] that rejects input which causes the total length of the text field to
+ * be more than [maxLength] codepoints.
+ *
+ * @see maxLengthInChars
+ */
+@ExperimentalFoundationApi
+@Stable
+fun TextEditFilter.Companion.maxLengthInCodepoints(maxLength: Int): TextEditFilter =
+ MaxLengthFilter(maxLength, inCodepoints = true)
+
+// This is a very naive implementation for now, not intended to be production-ready.
+@OptIn(ExperimentalFoundationApi::class)
+private data class MaxLengthFilter(
+ private val maxLength: Int,
+ private val inCodepoints: Boolean
+) : TextEditFilter {
+
+ init {
+ require(maxLength >= 0) { "maxLength must be at least zero, was $maxLength" }
+ }
+
+ override fun filter(
+ originalValue: TextFieldCharSequence,
+ valueWithChanges: TextFieldBufferWithSelection
+ ) {
+ val newLength =
+ if (inCodepoints) valueWithChanges.codepointLength else valueWithChanges.length
+ if (newLength > maxLength) {
+ valueWithChanges.revertAllChanges()
+ }
+ }
+
+ override fun toString(): String {
+ val name = if (inCodepoints) "maxLengthInCodepoints" else "maxLengthInChars"
+ return "TextEditFilter.$name(maxLength=$maxLength)"
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditFilter.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditFilter.kt
new file mode 100644
index 0000000..fd6592c
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditFilter.kt
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.runtime.Stable
+
+/**
+ * A function that is ran after every change made to a [TextFieldState] by user input and can change
+ * or reject that input.
+ *
+ * Filters are ran after hardware and software keyboard events, when text is pasted or dropped into
+ * the field, or when an accessibility service changes the text.
+ *
+ * To chain filters together, call [then].
+ *
+ * Prebuilt filters are provided for common filter operations. See:
+ * - `TextEditFilter`.[maxLengthInChars]`()`
+ * - `TextEditFilter`.[maxLengthInCodepoints]`()`
+ * - `TextEditFilter`.[allCaps]`()`
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2CustomFilterSample
+ */
+@ExperimentalFoundationApi
+@Stable
+fun interface TextEditFilter {
+
+ /**
+ * Optional [KeyboardOptions] that will be used as the default keyboard options for configuring
+ * the IME. The options passed directly to the text field composable will always override this.
+ */
+ val keyboardOptions: KeyboardOptions? get() = null
+
+ /**
+ * The filter operation. For more information see the documentation on [TextEditFilter].
+ *
+ * To reject all changes in [valueWithChanges], call
+ * `valueWithChanges.`[revertAllChanges][TextFieldBufferWithSelection.revertAllChanges].
+ *
+ * @param originalValue The value of the field before the change was performed.
+ * @param valueWithChanges The value of the field after the change. This value can be changed
+ * in-place to alter or reject the changes or set the selection.
+ */
+ fun filter(originalValue: TextFieldCharSequence, valueWithChanges: TextFieldBufferWithSelection)
+
+ companion object
+}
+
+/**
+ * Creates a filter chain that will run [next] after this. Filters are applied sequentially, so any
+ * changes made by this filter will be visible to [next].
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2FilterChainingSample
+ *
+ * @param next The [TextEditFilter] that will be ran after this one.
+ * @param keyboardOptions The [KeyboardOptions] options to use for the chained filter. If not
+ * specified, the chained filter will not specify any [KeyboardOptions], even if one or both of
+ * this or [next] specified some.
+ */
+@ExperimentalFoundationApi
+@Stable
+fun TextEditFilter.then(
+ next: TextEditFilter,
+ keyboardOptions: KeyboardOptions? = null
+): TextEditFilter = FilterChain(this, next, keyboardOptions)
+
+private class FilterChain(
+ private val first: TextEditFilter,
+ private val second: TextEditFilter,
+ override val keyboardOptions: KeyboardOptions?
+) : TextEditFilter {
+
+ override fun filter(
+ originalValue: TextFieldCharSequence,
+ valueWithChanges: TextFieldBufferWithSelection
+ ) {
+ first.filter(originalValue, valueWithChanges)
+ second.filter(originalValue, valueWithChanges)
+ }
+
+ override fun toString(): String = "$first.then($second)"
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as FilterChain
+
+ if (first != other.first) return false
+ if (second != other.second) return false
+ if (keyboardOptions != other.keyboardOptions) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = first.hashCode()
+ result = 31 * result + second.hashCode()
+ result = 32 * result + keyboardOptions.hashCode()
+ return result
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditResult.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditResult.kt
new file mode 100644
index 0000000..93b0021
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditResult.kt
@@ -0,0 +1,381 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.ui.text.TextRange
+
+/**
+ * A value to be returned from [TextFieldState.edit] that specifies where to place the cursor or
+ * selection.
+ *
+ * Predefined results include:
+ * - [TextFieldBuffer.placeCursorAtEnd]
+ * - [TextFieldBuffer.placeCursorBeforeFirstChange]
+ * - [TextFieldBuffer.placeCursorAfterLastChange]
+ * - [TextFieldBuffer.placeCursorBeforeCharAt]
+ * - [TextFieldBuffer.placeCursorAfterCharAt]
+ * - [TextFieldBuffer.placeCursorBeforeCodepointAt]
+ * - [TextFieldBuffer.placeCursorAfterCodepointAt]
+ * - [TextFieldBuffer.selectAll]
+ * - [TextFieldBuffer.selectAllChanges]
+ * - [TextFieldBuffer.selectCharsIn]
+ * - [TextFieldBuffer.selectCodepointsIn]
+ */
+@ExperimentalFoundationApi
+sealed class TextEditResult {
+ /**
+ * Returns the [TextRange] to set as the new selection. If the selection is collapsed, it will
+ * set the cursor instead.
+ *
+ * @return The new range of the selection, in character offsets.
+ */
+ internal abstract fun calculateSelection(
+ oldValue: TextFieldCharSequence,
+ newValue: TextFieldBuffer
+ ): TextRange
+}
+
+/**
+ * Returns a [TextEditResult] that places the cursor before the codepoint at the given index.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If [index] is inside an invalid run, the cursor will be placed at the nearest earlier index.
+ *
+ * To place the cursor at the beginning of the field, pass index 0. To place the cursor at the end
+ * of the field, after the last character, pass index [TextFieldBuffer.codepointLength].
+ *
+ * @param index Codepoint index to place cursor before, should be in range 0 to
+ * [TextFieldBuffer.codepointLength], inclusive.
+ *
+ * @see placeCursorBeforeCharAt
+ * @see placeCursorAfterCodepointAt
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorBeforeCodepointAt(index: Int): TextEditResult =
+ PlaceCursorResult(this, index, after = false, inCodepoints = true)
+
+/**
+ * Returns a [TextEditResult] that places the cursor after the codepoint at the given index.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If [index] is inside an invalid run, the cursor will be placed at the nearest earlier index.
+ *
+ * To place the cursor at the end of the field, after the last character, pass index
+ * [TextFieldBuffer.codepointLength] or call [placeCursorAtEnd].
+ *
+ * @param index Codepoint index to place cursor after, should be in range 0 (inclusive) to
+ * [TextFieldBuffer.codepointLength] (exclusive).
+ *
+ * @see placeCursorBeforeCharAt
+ * @see placeCursorAfterCodepointAt
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorAfterCodepointAt(index: Int): TextEditResult =
+ PlaceCursorResult(this, index, after = true, inCodepoints = true)
+
+/**
+ * Returns a [TextEditResult] that places the cursor before the character at the given index.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If [index] is inside a surrogate pair or other invalid run, the cursor will be placed at the
+ * nearest earlier index.
+ *
+ * To place the cursor at the beginning of the field, pass index 0. To place the cursor at the end
+ * of the field, after the last character, pass index [TextFieldBuffer.length] or call
+ * [placeCursorAtEnd].
+ *
+ * @param index Character index to place cursor before, should be in range 0 to
+ * [TextFieldBuffer.length], inclusive.
+ *
+ * @see placeCursorBeforeCodepointAt
+ * @see placeCursorAfterCharAt
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorBeforeCharAt(index: Int): TextEditResult =
+ PlaceCursorResult(this, index, after = false, inCodepoints = false)
+
+/**
+ * Returns a [TextEditResult] that places the cursor after the character at the given index.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If [index] is inside a surrogate pair or other invalid run, the cursor will be placed at the
+ * nearest earlier index.
+ *
+ * To place the cursor at the end of the field, after the last character, pass index
+ * [TextFieldBuffer.length] or call [placeCursorAtEnd].
+ *
+ * @param index Character index to place cursor after, should be in range 0 (inclusive) to
+ * [TextFieldBuffer.length] (exclusive).
+ *
+ * @see placeCursorAfterCodepointAt
+ * @see placeCursorBeforeCharAt
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorAfterCharAt(index: Int): TextEditResult =
+ PlaceCursorResult(this, index, after = true, inCodepoints = false)
+
+/**
+ * Returns a [TextEditResult] that places the cursor at the end of the text.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * @see placeCursorAfterLastChange
+ * @see TextFieldState.edit
+ */
+@Suppress("UnusedReceiverParameter")
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorAtEnd(): TextEditResult = PlaceCursorAtEndResult
+
+/**
+ * Returns a [TextEditResult] that places the cursor after the last change made to this
+ * [TextFieldBuffer].
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * @see placeCursorAtEnd
+ * @see placeCursorBeforeFirstChange
+ * @see TextFieldState.edit
+ */
+@Suppress("UnusedReceiverParameter")
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorAfterLastChange(): TextEditResult =
+ PlaceCursorAfterLastChangeResult
+
+/**
+ * Returns a [TextEditResult] that places the cursor before the first change made to this
+ * [TextFieldBuffer].
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * @see placeCursorAfterLastChange
+ * @see TextFieldState.edit
+ */
+@Suppress("UnusedReceiverParameter")
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorBeforeFirstChange(): TextEditResult =
+ PlaceCursorBeforeFirstChangeResult
+
+/**
+ * Returns a [TextEditResult] that places the selection around the given [range] in codepoints.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If the start or end of [range] fall inside invalid runs, the values will be adjusted to the
+ * nearest earlier and later codepoints, respectively.
+ *
+ * To place the start of the selection at the beginning of the field, pass index 0. To place the end
+ * of the selection at the end of the field, after the last codepoint, pass index
+ * [TextFieldBuffer.codepointLength]. Passing a zero-length range is the same as calling
+ * [placeCursorBeforeCodepointAt].
+ *
+ * @param range Codepoint range of the selection, should be in range 0 to
+ * [TextFieldBuffer.codepointLength], inclusive.
+ *
+ * @see selectCharsIn
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.selectCodepointsIn(range: TextRange): TextEditResult =
+ SelectRangeResult(this, range, inCodepoints = true)
+
+/**
+ * Returns a [TextEditResult] that places the selection around the given [range] in characters.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If the start or end of [range] fall inside surrogate pairs or other invalid runs, the values will
+ * be adjusted to the nearest earlier and later characters, respectively.
+ *
+ * To place the start of the selection at the beginning of the field, pass index 0. To place the end
+ * of the selection at the end of the field, after the last character, pass index
+ * [TextFieldBuffer.length]. Passing a zero-length range is the same as calling
+ * [placeCursorBeforeCharAt].
+ *
+ * @param range Codepoint range of the selection, should be in range 0 to
+ * [TextFieldBuffer.length], inclusive.
+ *
+ * @see selectCharsIn
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.selectCharsIn(range: TextRange): TextEditResult =
+ SelectRangeResult(this, range, inCodepoints = false)
+
+/**
+ * Returns a [TextEditResult] that places the selection before the first change and after the
+ * last change.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * @see selectAll
+ * @see TextFieldState.edit
+ */
+@Suppress("UnusedReceiverParameter")
+@ExperimentalFoundationApi
+fun TextFieldBuffer.selectAllChanges(): TextEditResult = SelectAllChangesResult
+
+/**
+ * Returns a [TextEditResult] that places the selection around all the text.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * @see selectAllChanges
+ * @see TextFieldState.edit
+ */
+@Suppress("UnusedReceiverParameter")
+@ExperimentalFoundationApi
+fun TextFieldBuffer.selectAll(): TextEditResult = SelectAllResult
+
+private object PlaceCursorAtEndResult : TextEditResult() {
+ override fun calculateSelection(
+ oldValue: TextFieldCharSequence,
+ newValue: TextFieldBuffer
+ ): TextRange = TextRange(newValue.length)
+
+ override fun toString(): String = "placeCursorAtEnd()"
+}
+
+private object PlaceCursorAfterLastChangeResult : TextEditResult() {
+ override fun calculateSelection(
+ oldValue: TextFieldCharSequence,
+ newValue: TextFieldBuffer
+ ): TextRange {
+ return if (newValue.changes.changeCount == 0) {
+ oldValue.selectionInChars
+ } else {
+ TextRange(newValue.changes.getRange(newValue.changes.changeCount).max)
+ }
+ }
+
+ override fun toString(): String = "placeCursorAfterLastChange()"
+}
+
+private object PlaceCursorBeforeFirstChangeResult : TextEditResult() {
+ override fun calculateSelection(
+ oldValue: TextFieldCharSequence,
+ newValue: TextFieldBuffer
+ ): TextRange {
+ return if (newValue.changes.changeCount == 0) {
+ oldValue.selectionInChars
+ } else {
+ TextRange(newValue.changes.getRange(0).min)
+ }
+ }
+
+ override fun toString(): String = "placeCursorBeforeFirstChange()"
+}
+
+private object SelectAllChangesResult : TextEditResult() {
+ override fun calculateSelection(
+ oldValue: TextFieldCharSequence,
+ newValue: TextFieldBuffer
+ ): TextRange {
+ val changes = newValue.changes
+ return if (changes.changeCount == 0) {
+ oldValue.selectionInChars
+ } else {
+ TextRange(
+ changes.getRange(0).min,
+ changes.getRange(changes.changeCount).max
+ )
+ }
+ }
+
+ override fun toString(): String = "selectAllChanges()"
+}
+
+private object SelectAllResult : TextEditResult() {
+ override fun calculateSelection(
+ oldValue: TextFieldCharSequence,
+ newValue: TextFieldBuffer
+ ): TextRange = TextRange(0, newValue.length)
+
+ override fun toString(): String = "selectAll()"
+}
+
+private class PlaceCursorResult(
+ value: TextFieldBuffer,
+ private val rawIndex: Int,
+ private val after: Boolean,
+ private val inCodepoints: Boolean
+) : TextEditResult() {
+
+ init {
+ value.requireValidIndex(rawIndex, inCodepoints)
+ }
+
+ override fun calculateSelection(
+ oldValue: TextFieldCharSequence,
+ newValue: TextFieldBuffer
+ ): TextRange {
+ var index = if (after) rawIndex + 1 else rawIndex
+ index = index.coerceAtMost(if (inCodepoints) newValue.codepointLength else newValue.length)
+ index = if (inCodepoints) newValue.codepointIndexToCharIndex(index) else index
+ return TextRange(index)
+ }
+
+ override fun toString(): String = buildString {
+ append("placeCursor")
+ append(if (after) "After" else "Before")
+ append(if (inCodepoints) "Codepoint" else "Char")
+ append("At(index=$rawIndex)")
+ }
+}
+
+private class SelectRangeResult(
+ value: TextFieldBuffer,
+ private val rawRange: TextRange,
+ private val inCodepoints: Boolean
+) : TextEditResult() {
+
+ init {
+ value.requireValidRange(rawRange, inCodepoints)
+ }
+
+ override fun calculateSelection(
+ oldValue: TextFieldCharSequence,
+ newValue: TextFieldBuffer
+ ): TextRange = if (inCodepoints) newValue.codepointsToChars(rawRange) else rawRange
+
+ override fun toString(): String = buildString {
+ append("select")
+ append(if (inCodepoints) "Codepoints" else "Chars")
+ append("In(range=$rawRange)")
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBuffer.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBuffer.kt
new file mode 100644
index 0000000..267535c
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBuffer.kt
@@ -0,0 +1,306 @@
+/*
+ * 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.input
+
+import androidx.annotation.CallSuper
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList
+import androidx.compose.foundation.text2.input.internal.ChangeTracker
+import androidx.compose.ui.text.TextRange
+
+/**
+ * A text buffer that can be edited, similar to [StringBuilder].
+ *
+ * This class provides methods for changing the text, such as [replace], [append], [insert], and
+ * [delete].
+ *
+ * To get one of these, and for usage samples, see [TextFieldState.edit]. Every change to the buffer
+ * is tracked in a [ChangeList] which you can access via the [changes] property.
+ *
+ * [TextFieldBufferWithSelection] is a special type of buffer that has an associated cursor position
+ * or selection range.
+ */
+@ExperimentalFoundationApi
+open class TextFieldBuffer internal constructor(
+ internal val value: TextFieldCharSequence,
+ initialChanges: ChangeTracker? = null
+) : CharSequence,
+ Appendable {
+
+ private val buffer = StringBuffer(value)
+
+ /**
+ * Lazily-allocated [ChangeTracker], initialized on the first text change.
+ */
+ private var changeTracker: ChangeTracker? =
+ initialChanges?.let { ChangeTracker(initialChanges) }
+
+ /**
+ * The number of characters in the text field. This will be equal to or greater than
+ * [codepointLength].
+ */
+ override val length: Int get() = buffer.length
+
+ /**
+ * The number of codepoints in the text field. This will be equal to or less than [length].
+ */
+ val codepointLength: Int get() = buffer.codePointCount(0, length)
+
+ /**
+ * The [ChangeList] represents the changes made to this value and is inherently mutable. This
+ * means that the returned [ChangeList] always reflects the complete list of changes made to
+ * this value at any given time, even those made after reading this property.
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2ChangeIterationSample
+ * @sample androidx.compose.foundation.samples.BasicTextField2ChangeReverseIterationSample
+ */
+ val changes: ChangeList get() = changeTracker ?: EmptyChangeList
+
+ /**
+ * Replaces the text between [start] (inclusive) and [end] (exclusive) in this value with
+ * [text], and records the change in [changes].
+ *
+ * @param start The character offset of the first character to replace.
+ * @param end The character offset of the first character after the text to replace.
+ * @param text The text to replace the range `[start, end)` with.
+ *
+ * @see append
+ * @see insert
+ * @see delete
+ */
+ fun replace(start: Int, end: Int, text: String) {
+ onTextWillChange(TextRange(start, end), text.length)
+ buffer.replace(start, end, text)
+ }
+
+ // Doc inherited from Appendable.
+ // This append overload should be first so it ends up being the target of links to this method.
+ override fun append(text: CharSequence?): Appendable = apply {
+ if (text != null) {
+ onTextWillChange(TextRange(length), text.length)
+ buffer.append(text)
+ }
+ }
+
+ // Doc inherited from Appendable.
+ override fun append(text: CharSequence?, start: Int, end: Int): Appendable = apply {
+ if (text != null) {
+ onTextWillChange(TextRange(length), end - start)
+ buffer.append(text, start, end)
+ }
+ }
+
+ // Doc inherited from Appendable.
+ override fun append(char: Char): Appendable = apply {
+ onTextWillChange(TextRange(length), 1)
+ buffer.append(char)
+ }
+
+ /**
+ * Called just before the text contents are about to change.
+ *
+ * @param rangeToBeReplaced The range in the current text that's about to be replaced.
+ * @param newLength The length of the replacement.
+ */
+ @CallSuper
+ protected open fun onTextWillChange(rangeToBeReplaced: TextRange, newLength: Int) {
+ (changeTracker ?: ChangeTracker().also { changeTracker = it })
+ .trackChange(rangeToBeReplaced, newLength)
+ }
+
+ override operator fun get(index: Int): Char = buffer[index]
+
+ override fun subSequence(startIndex: Int, endIndex: Int): CharSequence =
+ buffer.subSequence(startIndex, endIndex)
+
+ override fun toString(): String = buffer.toString()
+
+ internal fun clearChangeList() {
+ changeTracker?.clearChanges()
+ }
+
+ internal fun toTextFieldCharSequence(
+ selection: TextRange,
+ composition: TextRange? = null
+ ): TextFieldCharSequence = TextFieldCharSequence(
+ buffer.toString(),
+ selection = selection,
+ composition = composition
+ )
+
+ internal fun requireValidIndex(index: Int, inCodepoints: Boolean) {
+ // The "units" of the range in the error message should match the units passed in.
+ // If the input was in codepoint indices, the output should be in codepoint indices.
+ val validRange = TextRange(0, length)
+ .let { if (inCodepoints) charsToCodepoints(it) else it }
+ require(index in validRange) {
+ val unit = if (inCodepoints) "codepoints" else "chars"
+ "Expected $index to be in $validRange ($unit)"
+ }
+ }
+
+ internal fun requireValidRange(range: TextRange, inCodepoints: Boolean) {
+ // The "units" of the range in the error message should match the units passed in.
+ // If the input was in codepoint indices, the output should be in codepoint indices.
+ val validRange = TextRange(0, length)
+ .let { if (inCodepoints) charsToCodepoints(it) else it }
+ require(range in validRange) {
+ val unit = if (inCodepoints) "codepoints" else "chars"
+ "Expected $range to be in $validRange ($unit)"
+ }
+ }
+
+ internal fun toTextFieldCharSequence(selection: TextRange): TextFieldCharSequence =
+ TextFieldCharSequence(buffer.toString(), selection = selection)
+
+ internal fun codepointsToChars(range: TextRange): TextRange = TextRange(
+ codepointIndexToCharIndex(range.start),
+ codepointIndexToCharIndex(range.end)
+ )
+
+ internal fun charsToCodepoints(range: TextRange): TextRange = TextRange(
+ charIndexToCodepointIndex(range.start),
+ charIndexToCodepointIndex(range.end),
+ )
+
+ // TODO Support actual codepoints.
+ internal fun codepointIndexToCharIndex(index: Int): Int = index
+ private fun charIndexToCodepointIndex(index: Int): Int = index
+
+ /**
+ * The ordered list of non-overlapping and discontinuous changes performed on a
+ * [TextFieldBuffer] during the current [edit][TextFieldState.edit] or
+ * [filter][TextEditFilter.filter] operation. Changes are listed in the order they appear in the
+ * text, not the order in which they were made. Overlapping changes are represented as a single
+ * change.
+ */
+ @ExperimentalFoundationApi
+ interface ChangeList {
+ /**
+ * The number of changes that have been performed.
+ */
+ val changeCount: Int
+
+ /**
+ * Returns the range in the [TextFieldBuffer] that was changed.
+ *
+ * @throws IndexOutOfBoundsException If [changeIndex] is not in [0, [changeCount]).
+ */
+ fun getRange(changeIndex: Int): TextRange
+
+ /**
+ * Returns the range in the original text that was replaced.
+ *
+ * @throws IndexOutOfBoundsException If [changeIndex] is not in [0, [changeCount]).
+ */
+ fun getOriginalRange(changeIndex: Int): TextRange
+ }
+}
+
+/**
+ * Insert [text] at the given [index] in this value. Pass 0 to insert [text] at the beginning of
+ * this buffer, and pass [TextFieldBuffer.length] to insert [text] at the end of this buffer.
+ *
+ * This is equivalent to calling `replace(index, index, text)`.
+ *
+ * @param index The character offset at which to insert [text].
+ * @param text The text to insert.
+ *
+ * @see TextFieldBuffer.replace
+ * @see TextFieldBuffer.append
+ * @see TextFieldBuffer.delete
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.insert(index: Int, text: String) {
+ replace(index, index, text)
+}
+
+/**
+ * Delete the text between [start] (inclusive) and [end] (exclusive). Pass 0 as [start] and
+ * [TextFieldBuffer.length] as [end] to delete everything in this buffer.
+ *
+ * @param start The character offset of the first character to delete.
+ * @param end The character offset of the first character after the deleted range.
+ *
+ * @see TextFieldBuffer.replace
+ * @see TextFieldBuffer.append
+ * @see TextFieldBuffer.insert
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.delete(start: Int, end: Int) {
+ replace(start, end, "")
+}
+
+/**
+ * Iterates over all the changes in this [ChangeList].
+ *
+ * Changes are iterated by index, so any changes made by [block] after the current one will be
+ * visited by [block]. [block] should not make any new changes _before_ the current one or changes
+ * will be visited more than once. If you need to make changes, consider using
+ * [forEachChangeReversed].
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2ChangeIterationSample
+ *
+ * @see forEachChangeReversed
+ */
+@ExperimentalFoundationApi
+inline fun ChangeList.forEachChange(
+ block: (range: TextRange, originalRange: TextRange) -> Unit
+) {
+ var i = 0
+ // Check the size every iteration in case more changes were performed.
+ while (i < changeCount) {
+ block(getRange(i), getOriginalRange(i))
+ i++
+ }
+}
+
+/**
+ * Iterates over all the changes in this [ChangeList] in reverse order.
+ *
+ * Changes are iterated by index, so [block] should not perform any new changes before the current
+ * one or changes may be skipped. [block] may make non-overlapping changes after the current one
+ * safely, such changes will not be visited.
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2ChangeReverseIterationSample
+ *
+ * @see forEachChange
+ */
+@ExperimentalFoundationApi
+inline fun ChangeList.forEachChangeReversed(
+ block: (range: TextRange, originalRange: TextRange) -> Unit
+) {
+ var i = changeCount - 1
+ while (i >= 0) {
+ block(getRange(i), getOriginalRange(i))
+ i--
+ }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+private object EmptyChangeList : ChangeList {
+ override val changeCount: Int
+ get() = 0
+
+ override fun getRange(changeIndex: Int): TextRange {
+ throw IndexOutOfBoundsException()
+ }
+
+ override fun getOriginalRange(changeIndex: Int): TextRange {
+ throw IndexOutOfBoundsException()
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelection.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelection.kt
new file mode 100644
index 0000000..56c698e
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelection.kt
@@ -0,0 +1,299 @@
+/*
+ * 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.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.internal.ChangeTracker
+import androidx.compose.ui.text.TextRange
+
+/**
+ * A [TextFieldBuffer] that also provides both read and write access to the current selection,
+ * used by [TextEditFilter.filter].
+ */
+@ExperimentalFoundationApi
+class TextFieldBufferWithSelection internal constructor(
+ value: TextFieldCharSequence,
+ /** The value reverted to when [revertAllChanges] is called. */
+ private val sourceValue: TextFieldCharSequence = TextFieldCharSequence(),
+ initialChanges: ChangeTracker? = null
+) : TextFieldBuffer(value, initialChanges) {
+
+ /**
+ * True if the selection range has non-zero length. If this is false, then the selection
+ * represents the cursor.
+ *
+ * @see selectionInChars
+ */
+ val hasSelection: Boolean
+ get() = !selectionInChars.collapsed
+
+ /**
+ * The selected range of characters.
+ *
+ * @see selectionInCodepoints
+ */
+ var selectionInChars: TextRange = value.selectionInChars
+ private set
+
+ /**
+ * The selected range of codepoints.
+ *
+ * @see selectionInChars
+ */
+ val selectionInCodepoints: TextRange
+ get() = charsToCodepoints(selectionInChars)
+
+ /**
+ * Places the cursor before the codepoint at the given index.
+ *
+ * If [index] is inside an invalid run, the cursor will be placed at the nearest earlier index.
+ *
+ * To place the cursor at the beginning of the field, pass index 0. To place the cursor at the
+ * end of the field, after the last character, pass index
+ * [TextFieldBuffer.codepointLength] or call [placeCursorAtEnd].
+ *
+ * @param index Codepoint index to place cursor before, should be in range 0 to
+ * [TextFieldBuffer.codepointLength], inclusive.
+ *
+ * @see placeCursorBeforeCharAt
+ * @see placeCursorAfterCodepointAt
+ */
+ fun placeCursorBeforeCodepointAt(index: Int) {
+ requireValidIndex(index, inCodepoints = true)
+ val charIndex = codepointIndexToCharIndex(index)
+ selectionInChars = TextRange(charIndex)
+ }
+
+ /**
+ * Places the cursor before the character at the given index.
+ *
+ * If [index] is inside a surrogate pair or other invalid run, the cursor will be placed at the
+ * nearest earlier index.
+ *
+ * To place the cursor at the beginning of the field, pass index 0. To place the cursor at the
+ * end of the field, after the last character, pass index [TextFieldBuffer.length] or call
+ * [placeCursorAtEnd].
+ *
+ * @param index Character index to place cursor before, should be in range 0 to
+ * [TextFieldBuffer.length], inclusive.
+ *
+ * @see placeCursorBeforeCodepointAt
+ * @see placeCursorAfterCharAt
+ */
+ fun placeCursorBeforeCharAt(index: Int) {
+ requireValidIndex(index, inCodepoints = false)
+ selectionInChars = TextRange(index)
+ }
+
+ /**
+ * Places the cursor after the codepoint at the given index.
+ *
+ * If [index] is inside an invalid run, the cursor will be placed at the nearest later index.
+ *
+ * To place the cursor at the end of the field, after the last character, pass index
+ * [TextFieldBuffer.codepointLength] or call [placeCursorAtEnd].
+ *
+ * @param index Codepoint index to place cursor after, should be in range 0 (inclusive) to
+ * [TextFieldBuffer.codepointLength] (exclusive).
+ *
+ * @see placeCursorAfterCharAt
+ * @see placeCursorBeforeCodepointAt
+ */
+ fun placeCursorAfterCodepointAt(index: Int) {
+ requireValidIndex(index, inCodepoints = true)
+ val charIndex = codepointIndexToCharIndex((index + 1).coerceAtMost(codepointLength))
+ selectionInChars = TextRange(charIndex)
+ }
+
+ /**
+ * Places the cursor after the character at the given index.
+ *
+ * If [index] is inside a surrogate pair or other invalid run, the cursor will be placed at the
+ * nearest later index.
+ *
+ * To place the cursor at the end of the field, after the last character, pass index
+ * [TextFieldBuffer.length] or call [placeCursorAtEnd].
+ *
+ * @param index Character index to place cursor after, should be in range 0 (inclusive) to
+ * [TextFieldBuffer.length] (exclusive).
+ *
+ * @see placeCursorAfterCodepointAt
+ * @see placeCursorBeforeCharAt
+ */
+ fun placeCursorAfterCharAt(index: Int) {
+ requireValidIndex(index, inCodepoints = false)
+ selectionInChars = TextRange((index + 1).coerceAtMost(length))
+ }
+
+ /**
+ * Places the cursor at the end of the text.
+ *
+ * @see placeCursorBeforeFirstChange
+ * @see placeCursorAfterLastChange
+ */
+ fun placeCursorAtEnd() {
+ selectionInChars = TextRange(length)
+ }
+
+ /**
+ * Places the cursor after the last change made to this [TextFieldBufferWithSelection].
+ *
+ * @see placeCursorAtEnd
+ * @see placeCursorBeforeFirstChange
+ */
+ fun placeCursorAfterLastChange() {
+ if (changes.changeCount > 0) {
+ placeCursorBeforeCharAt(changes.getRange(changes.changeCount).max)
+ }
+ }
+
+ /**
+ * Places the cursor before the first change made to this [TextFieldBufferWithSelection].
+ *
+ * @see placeCursorAfterLastChange
+ */
+ fun placeCursorBeforeFirstChange() {
+ if (changes.changeCount > 0) {
+ placeCursorBeforeCharAt(changes.getRange(0).min)
+ }
+ }
+
+ /**
+ * Places the selection around the given [range] in codepoints.
+ *
+ * If the start or end of [range] fall inside invalid runs, the values will be adjusted to the
+ * nearest earlier and later codepoints, respectively.
+ *
+ * To place the start of the selection at the beginning of the field, pass index 0. To place the
+ * end of the selection at the end of the field, after the last codepoint, pass index
+ * [TextFieldBuffer.codepointLength]. Passing a zero-length range is the same as calling
+ * [placeCursorBeforeCodepointAt].
+ *
+ * @param range Codepoint range of the selection, should be in range 0 to
+ * [TextFieldBuffer.codepointLength], inclusive.
+ *
+ * @see selectCharsIn
+ */
+ fun selectCodepointsIn(range: TextRange) {
+ requireValidRange(range, inCodepoints = true)
+ selectionInChars = codepointsToChars(range)
+ }
+
+ /**
+ * Places the selection around the given [range] in characters.
+ *
+ * If the start or end of [range] fall inside surrogate pairs or other invalid runs, the values will
+ * be adjusted to the nearest earlier and later characters, respectively.
+ *
+ * To place the start of the selection at the beginning of the field, pass index 0. To place the end
+ * of the selection at the end of the field, after the last character, pass index
+ * [TextFieldBuffer.length]. Passing a zero-length range is the same as calling
+ * [placeCursorBeforeCharAt].
+ *
+ * @param range Codepoint range of the selection, should be in range 0 to
+ * [TextFieldBuffer.length], inclusive.
+ *
+ * @see selectCodepointsIn
+ */
+ fun selectCharsIn(range: TextRange) {
+ requireValidRange(range, inCodepoints = false)
+ selectionInChars = range
+ }
+
+ /**
+ * Places the selection around all the text.
+ *
+ * @see selectAllChanges
+ */
+ fun selectAll() {
+ selectionInChars = TextRange(0, length)
+ }
+
+ /**
+ * Places the selection before the first change and after the last change.
+ *
+ * @see selectAll
+ */
+ fun selectAllChanges() {
+ if (changes.changeCount > 0) {
+ selectCharsIn(
+ TextRange(
+ changes.getRange(0).min,
+ changes.getRange(changes.changeCount).max
+ )
+ )
+ }
+ }
+
+ /**
+ * Revert all changes made to this value since it was created.
+ *
+ * After calling this method, this object will be in the same state it was when it was initially
+ * created, and [changes] will be empty.
+ */
+ fun revertAllChanges() {
+ replace(0, length, sourceValue.toString())
+ selectionInChars = sourceValue.selectionInChars
+ clearChangeList()
+ }
+
+ override fun onTextWillChange(rangeToBeReplaced: TextRange, newLength: Int) {
+ super.onTextWillChange(rangeToBeReplaced, newLength)
+
+ // Adjust selection.
+ val start = rangeToBeReplaced.min
+ val end = rangeToBeReplaced.max
+ var selStart = selectionInChars.min
+ var selEnd = selectionInChars.max
+
+ if (selEnd < start) {
+ // The entire selection is before the insertion point – we don't have to adjust the
+ // mark at all, so skip the math.
+ return
+ }
+
+ if (selStart <= start && end <= selEnd) {
+ // The insertion is entirely inside the selection, move the end only.
+ val diff = newLength - (end - start)
+ // Preserve "cursorness".
+ if (selStart == selEnd) {
+ selStart += diff
+ }
+ selEnd += diff
+ } else if (selStart > start && selEnd < end) {
+ // Selection is entirely inside replacement, move it to the end.
+ selStart = start + newLength
+ selEnd = start + newLength
+ } else if (selStart >= end) {
+ // The entire selection is after the insertion, so shift everything forward.
+ val diff = newLength - (end - start)
+ selStart += diff
+ selEnd += diff
+ } else if (start < selStart) {
+ // Insertion is around start of selection, truncate start of selection.
+ selStart = start + newLength
+ selEnd += newLength - (end - start)
+ } else {
+ // Insertion is around end of selection, truncate end of selection.
+ selEnd = start
+ }
+ selectionInChars = TextRange(selStart, selEnd)
+ }
+
+ internal fun toTextFieldCharSequence(composition: TextRange? = null): TextFieldCharSequence =
+ toTextFieldCharSequence(selection = selectionInChars, composition = composition)
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequence.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequence.kt
new file mode 100644
index 0000000..e8b4877
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequence.kt
@@ -0,0 +1,125 @@
+/*
+ * 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.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.coerceIn
+
+/**
+ * An immutable snapshot of the contents of a [TextFieldState].
+ *
+ * This class is a [CharSequence] and directly represents the text being edited. It also stores
+ * the current [selectionInChars] of the field, which may either represent the cursor (if the
+ * selection is [collapsed][TextRange.collapsed]) or the selection range.
+ *
+ * This class also may contain the range being composed by the IME, if any, although this is not
+ * exposed.
+ *
+ * @see TextFieldBuffer
+ */
+@ExperimentalFoundationApi
+sealed interface TextFieldCharSequence : CharSequence {
+ /**
+ * The selection range. If the selection is collapsed, it represents cursor
+ * location. When selection range is out of bounds, it is constrained with the text length.
+ */
+ val selectionInChars: TextRange
+
+ /**
+ * Composition range created by IME. If null, there is no composition range.
+ *
+ * Input service composition is an instance of text produced by IME. An example visual for the
+ * composition is that the currently composed word is visually separated from others with
+ * underline, or text background. For description of composition please check
+ * [W3C IME Composition](https://www.w3.org/TR/ime-api/#ime-composition)
+ *
+ * Composition can only be set by the system.
+ */
+ val compositionInChars: TextRange?
+
+ /**
+ * Returns true if the text in this object is equal to the text in [other], disregarding any
+ * other properties of this (such as selection) or [other].
+ */
+ fun contentEquals(other: CharSequence): Boolean
+
+ abstract override fun toString(): String
+ abstract override fun equals(other: Any?): Boolean
+ abstract override fun hashCode(): Int
+}
+
+@ExperimentalFoundationApi
+fun TextFieldCharSequence(
+ text: String = "",
+ selection: TextRange = TextRange.Zero
+): TextFieldCharSequence = TextFieldCharSequenceWrapper(text, selection, composition = null)
+
+@OptIn(ExperimentalFoundationApi::class)
+internal fun TextFieldCharSequence(
+ text: CharSequence,
+ selection: TextRange,
+ composition: TextRange? = null
+): TextFieldCharSequence = TextFieldCharSequenceWrapper(text, selection, composition)
+
+@OptIn(ExperimentalFoundationApi::class)
+private class TextFieldCharSequenceWrapper(
+ private val text: CharSequence,
+ selection: TextRange,
+ composition: TextRange?
+) : TextFieldCharSequence {
+
+ override val length: Int
+ get() = text.length
+
+ override val selectionInChars: TextRange = selection.coerceIn(0, text.length)
+
+ override val compositionInChars: TextRange? = composition?.coerceIn(0, text.length)
+
+ override operator fun get(index: Int): Char = text[index]
+
+ override fun subSequence(startIndex: Int, endIndex: Int): CharSequence =
+ text.subSequence(startIndex, endIndex)
+
+ override fun toString(): String = text.toString()
+
+ override fun contentEquals(other: CharSequence): Boolean = text.contentEquals(other)
+
+ /**
+ * Returns true if [other] is a [TextFieldCharSequence] with the same contents, text, and composition.
+ * To compare just the text, call [contentEquals].
+ */
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as TextFieldCharSequenceWrapper
+
+ if (selectionInChars != other.selectionInChars) return false
+ if (compositionInChars != other.compositionInChars) return false
+ if (!contentEquals(other.text)) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = text.hashCode()
+ result = 31 * result + selectionInChars.hashCode()
+ result = 31 * result + (compositionInChars?.hashCode() ?: 0)
+ return result
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldLineLimits.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldLineLimits.kt
new file mode 100644
index 0000000..e2e151f
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldLineLimits.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.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.Stable
+
+/**
+ * Values that specify the text wrapping, scrolling, and height measurement behavior for
+ * text fields.
+ *
+ * @see SingleLine
+ * @see MultiLine
+ */
+@ExperimentalFoundationApi
+@Stable
+sealed interface TextFieldLineLimits {
+
+ /**
+ * The text field is always a single line tall, ignores newlines in the text, and scrolls
+ * horizontally when the text overflows.
+ */
+ object SingleLine : TextFieldLineLimits
+
+ /**
+ * The text field will be at least [minHeightInLines] tall, if the text overflows it will wrap,
+ * and if the text ends up being more than one line the field will grow until it is
+ * [maxHeightInLines] tall and then start scrolling vertically.
+ *
+ * It is required that 1 ≤ [minHeightInLines] ≤ [maxHeightInLines].
+ */
+ @Immutable
+ class MultiLine(
+ val minHeightInLines: Int = 1,
+ val maxHeightInLines: Int = Int.MAX_VALUE
+ ) : TextFieldLineLimits {
+ init {
+ require(minHeightInLines in 1..maxHeightInLines) {
+ "Expected 1 ≤ minHeightInLines ≤ maxHeightInLines, were " +
+ "$minHeightInLines, $maxHeightInLines"
+ }
+ }
+
+ override fun toString(): String =
+ "MultiLine(minHeightInLines=$minHeightInLines, maxHeightInLines=$maxHeightInLines)"
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+ other as MultiLine
+ if (minHeightInLines != other.minHeightInLines) return false
+ if (maxHeightInLines != other.maxHeightInLines) return false
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = minHeightInLines
+ result = 31 * result + maxHeightInLines
+ return result
+ }
+ }
+
+ companion object {
+ val Default: TextFieldLineLimits = MultiLine()
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldState.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldState.kt
new file mode 100644
index 0000000..f88738b
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldState.kt
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.internal.EditProcessor
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.saveable.SaverScope
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.snapshotFlow
+import androidx.compose.ui.text.TextRange
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collectLatest
+
+/**
+ * The editable text state of a text field, including both the [text] itself and position of the
+ * cursor or selection.
+ *
+ * To change the text field contents programmatically, call [edit], [setTextAndSelectAll],
+ * [setTextAndPlaceCursorAtEnd], or [clearText]. To observe the value of the field over time, call
+ * [forEachTextValue] or [textAsFlow].
+ *
+ * When instantiating this class from a composable, use [rememberTextFieldState] to automatically
+ * save and restore the field state. For more advanced use cases, pass [TextFieldState.Saver] to
+ * [rememberSaveable].
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2StateCompleteSample
+ */
+@ExperimentalFoundationApi
+@Stable
+class TextFieldState(
+ initialText: String = "",
+ initialSelectionInChars: TextRange = TextRange.Zero
+) {
+ internal var editProcessor =
+ EditProcessor(TextFieldCharSequence(initialText, initialSelectionInChars))
+
+ /**
+ * The current text and selection. This value will automatically update when the user enters
+ * text or otherwise changes the text field contents. To change it programmatically, call
+ * [edit].
+ *
+ * This is backed by snapshot state, so reading this property in a restartable function (e.g.
+ * a composable function) will cause the function to restart when the text field's value
+ * changes.
+ *
+ * To observe changes to this property outside a restartable function, see [forEachTextValue]
+ * and [textAsFlow].
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2TextDerivedStateSample
+ *
+ * @see edit
+ * @see forEachTextValue
+ * @see textAsFlow
+ */
+ val text: TextFieldCharSequence
+ get() = editProcessor.value
+
+ /**
+ * Runs [block] with a mutable version of the current state. The block can make changes to the
+ * text, and must specify the new location of the cursor or selection by returning a
+ * [TextEditResult] such as [placeCursorAtEnd] or [selectAll] (see the documentation on
+ * [TextEditResult] for the full list of prebuilt results).
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2StateEditSample
+ *
+ * @see setTextAndPlaceCursorAtEnd
+ * @see setTextAndSelectAll
+ */
+ inline fun edit(block: TextFieldBuffer.() -> TextEditResult) {
+ val mutableValue = startEdit(text)
+ val result = mutableValue.block()
+ commitEdit(mutableValue, result)
+ }
+
+ override fun toString(): String =
+ "TextFieldState(selectionInChars=${text.selectionInChars}, text=\"$text\")"
+
+ @Suppress("ShowingMemberInHiddenClass")
+ @PublishedApi
+ internal fun startEdit(value: TextFieldCharSequence): TextFieldBuffer =
+ TextFieldBuffer(value)
+
+ @Suppress("ShowingMemberInHiddenClass")
+ @PublishedApi
+ internal fun commitEdit(newValue: TextFieldBuffer, result: TextEditResult) {
+ val newSelection = result.calculateSelection(text, newValue)
+ val finalValue = newValue.toTextFieldCharSequence(newSelection)
+ editProcessor.reset(finalValue)
+ }
+
+ /**
+ * Saves and restores a [TextFieldState] for [rememberSaveable].
+ *
+ * @see rememberTextFieldState
+ */
+ // Preserve nullability since this is public API.
+ @Suppress("RedundantNullableReturnType")
+ object Saver : androidx.compose.runtime.saveable.Saver<TextFieldState, Any> {
+ override fun SaverScope.save(value: TextFieldState): Any? = listOf(
+ value.text.toString(),
+ value.text.selectionInChars.start,
+ value.text.selectionInChars.end
+ )
+
+ override fun restore(value: Any): TextFieldState? {
+ val (text, selectionStart, selectionEnd) = value as List<*>
+ return TextFieldState(
+ initialText = text as String,
+ initialSelectionInChars = TextRange(
+ start = selectionStart as Int,
+ end = selectionEnd as Int
+ )
+ )
+ }
+ }
+}
+
+/**
+ * Returns a [Flow] of the values of [TextFieldState.text] as seen from the global snapshot.
+ * The initial value is emitted immediately when the flow is collected.
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2TextValuesSample
+ */
+@ExperimentalFoundationApi
+fun TextFieldState.textAsFlow(): Flow<TextFieldCharSequence> = snapshotFlow { text }
+
+/**
+ * Create and remember a [TextFieldState]. The state is remembered using [rememberSaveable] and so
+ * will be saved and restored with the composition.
+ *
+ * If you need to store a [TextFieldState] in another object, use the [TextFieldState.Saver] object
+ * to manually save and restore the state.
+ */
+@ExperimentalFoundationApi
+@Composable
+fun rememberTextFieldState(): TextFieldState =
+ rememberSaveable(saver = TextFieldState.Saver) {
+ TextFieldState()
+ }
+
+/**
+ * Sets the text in this [TextFieldState] to [text], replacing any text that was previously there,
+ * and places the cursor at the end of the new text.
+ *
+ * To perform more complicated edits on the text, call [TextFieldState.edit]. This function is
+ * equivalent to calling:
+ * ```
+ * edit {
+ * replace(0, length, text)
+ * placeCursorAtEnd()
+ * }
+ * ```
+ *
+ * @see setTextAndSelectAll
+ * @see clearText
+ * @see TextFieldBuffer.placeCursorAtEnd
+ */
+@ExperimentalFoundationApi
+fun TextFieldState.setTextAndPlaceCursorAtEnd(text: String) {
+ edit {
+ replace(0, length, text)
+ placeCursorAtEnd()
+ }
+}
+
+/**
+ * Sets the text in this [TextFieldState] to [text], replacing any text that was previously there,
+ * and selects all the text.
+ *
+ * To perform more complicated edits on the text, call [TextFieldState.edit]. This function is
+ * equivalent to calling:
+ * ```
+ * edit {
+ * replace(0, length, text)
+ * selectAll()
+ * }
+ * ```
+ *
+ * @see setTextAndPlaceCursorAtEnd
+ * @see clearText
+ * @see TextFieldBuffer.selectAll
+ */
+@ExperimentalFoundationApi
+fun TextFieldState.setTextAndSelectAll(text: String) {
+ edit {
+ replace(0, length, text)
+ selectAll()
+ }
+}
+
+/**
+ * Deletes all the text in the state.
+ *
+ * To perform more complicated edits on the text, call [TextFieldState.edit]. This function is
+ * equivalent to calling:
+ * ```
+ * edit {
+ * delete(0, length)
+ * placeCursorAtEnd()
+ * }
+ * ```
+ *
+ * @see setTextAndPlaceCursorAtEnd
+ * @see setTextAndSelectAll
+ */
+@ExperimentalFoundationApi
+fun TextFieldState.clearText() {
+ edit {
+ delete(0, length)
+ placeCursorAtEnd()
+ }
+}
+
+/**
+ * Invokes [block] with the value of [TextFieldState.text], and every time the value is changed.
+ *
+ * The caller will be suspended until its coroutine is cancelled. If the text is changed while
+ * [block] is suspended, [block] will be cancelled and re-executed with the new value immediately.
+ * [block] will never be executed concurrently with itself.
+ *
+ * To get access to a [Flow] of [TextFieldState.text] over time, use [textAsFlow].
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2ForEachTextValueSample
+ *
+ * @see textAsFlow
+ */
+@ExperimentalFoundationApi
+suspend fun TextFieldState.forEachTextValue(
+ block: suspend (TextFieldCharSequence) -> Unit
+): Nothing {
+ textAsFlow().collectLatest(block)
+ error("textAsFlow expected not to complete without exception")
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+internal fun TextFieldState.deselect() {
+ if (!text.selectionInChars.collapsed) {
+ edit {
+ selectCharsIn(TextRange.Zero)
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextObfuscationMode.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextObfuscationMode.kt
new file mode 100644
index 0000000..670a51db
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextObfuscationMode.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.input
+
+import android.provider.Settings
+import androidx.compose.foundation.ExperimentalFoundationApi
+
+/**
+ * Defines how the text will be obscured in secure text fields.
+ *
+ * Text obscuring refers to replacing the original text content with a mask via various methods.
+ * It is most common in password fields.
+ *
+ * The default behavior for typing input on Desktop has always been to keep it completely hidden.
+ * However, on mobile devices, the default behavior is to briefly reveal the last typed character
+ * for a short period or until another character is typed. This helps the user to follow the text
+ * input while also protecting their privacy by not revealing too much information to others.
+ */
+@ExperimentalFoundationApi
+@JvmInline
+value class TextObfuscationMode internal constructor(val value: Int) {
+ companion object {
+ /**
+ * Do not obscure any content, making all the content visible.
+ *
+ * It can be useful when you want to briefly reveal the content by clicking a reveal button.
+ */
+ val Visible = TextObfuscationMode(0)
+
+ /**
+ * Default behavior on mobile devices. Reveals the last typed character for a short amount
+ * of time.
+ *
+ * Note; this feature also depends on a system setting called
+ * [Settings.System.TEXT_SHOW_PASSWORD]. If the system setting is disabled, this option
+ * behaves exactly as [Hidden].
+ */
+ val RevealLastTyped = TextObfuscationMode(1)
+
+ /**
+ * Default behavior on desktop platforms. All characters are hidden.
+ */
+ val Hidden = TextObfuscationMode(2)
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapter.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapter.kt
new file mode 100644
index 0000000..47f6759
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapter.kt
@@ -0,0 +1,490 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.text2.input.internal
+
+import android.os.Looper
+import android.text.InputType
+import android.util.Log
+import android.view.Choreographer
+import android.view.KeyEvent
+import android.view.View
+import android.view.inputmethod.EditorInfo
+import android.view.inputmethod.InputConnection
+import androidx.annotation.VisibleForTesting
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.runtime.collection.mutableVectorOf
+import androidx.compose.ui.text.input.ImeAction
+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.PlatformTextInput
+import androidx.compose.ui.text.input.PlatformTextInputAdapter
+import androidx.core.view.inputmethod.EditorInfoCompat
+import java.util.concurrent.Executor
+import org.jetbrains.annotations.TestOnly
+
+/**
+ * Enable to print logs during debugging, see [logDebug].
+ */
+@VisibleForTesting
+internal const val TIA_DEBUG = false
+private const val TAG = "AndroidTextInputAdapter"
+
+internal class AndroidTextInputAdapter constructor(
+ view: View,
+ private val platformTextInput: PlatformTextInput
+) : PlatformTextInputAdapter {
+
+ private var currentTextInputSession: EditableTextInputSession? = null
+
+ private val inputMethodManager = ComposeInputMethodManager(view)
+
+ private val textInputCommandExecutor = TextInputCommandExecutor(view, inputMethodManager)
+
+ private val resetListener = EditProcessor.ResetListener { old, new ->
+ val needUpdateSelection = (old.selectionInChars != new.selectionInChars) ||
+ old.compositionInChars != new.compositionInChars
+ if (needUpdateSelection) {
+ inputMethodManager.updateSelection(
+ selectionStart = new.selectionInChars.min,
+ selectionEnd = new.selectionInChars.max,
+ compositionStart = new.compositionInChars?.min ?: -1,
+ compositionEnd = new.compositionInChars?.max ?: -1
+ )
+ }
+
+ if (!old.contentEquals(new)) {
+ inputMethodManager.restartInput()
+ }
+ }
+
+ override fun createInputConnection(outAttrs: EditorInfo): InputConnection {
+ logDebug { "createInputConnection" }
+ val value = currentTextInputSession?.value ?: TextFieldCharSequence()
+ val imeOptions = currentTextInputSession?.imeOptions ?: ImeOptions.Default
+
+ logDebug { "createInputConnection.value = $value" }
+
+ outAttrs.update(value, imeOptions)
+
+ val inputConnection = StatelessInputConnection(
+ activeSessionProvider = { currentTextInputSession }
+ )
+ testInputConnectionCreatedListener?.invoke(outAttrs, inputConnection)
+ return inputConnection
+ }
+
+ /**
+ * Clear the resources before being disposed. Any active session should be stopped from
+ * receiving any more input.
+ */
+ override fun onDisposed() {
+ currentTextInputSession?.dispose()
+ }
+
+ /**
+ * Start a new input session and close the active session if there is one. This session will
+ * be responsible for maintaining an agreement between text editor and lower level platform
+ * APIs to agree on where to direct incoming requests. If there are multiple text editors on a
+ * screen, only the active(focused) one should receive inputs from the platform input
+ * connection.
+ *
+ * Each session is tied with a [TextFieldState] from the start. The current editing state of
+ * the text editor is read and written via platform calls as long as the session is active.
+ * [ImeOptions] are used to initialize an [InputConnection] when [createInputConnection] is
+ * called. Any change in [ImeOptions] should start a new session. Regularly starting a new input
+ * session also instructs the platform to request a new [InputConnection] but that's not
+ * guaranteed. [AndroidTextInputAdapter] behaves as a bridge to establish a stable communication
+ * channel between active [TextInputSession] in this class and the [InputConnection] used by
+ * the platform.
+ *
+ * @param state Text editing state
+ * @param imeOptions How to configure the IME when creating new [InputConnection]s
+ * @param initialFilter The initial [TextEditFilter]. The filter can be changed after the
+ * session is started by calling [TextInputSession.setFilter].
+ * @param onImeActionPerformed A callback to pass received editor action from IME.
+ * @return A handle to manage active session between Adapter and platform APIs.
+ */
+ fun startInputSession(
+ state: TextFieldState,
+ imeOptions: ImeOptions,
+ initialFilter: TextEditFilter?,
+ onImeActionPerformed: (ImeAction) -> Unit
+ ): TextInputSession {
+ if (!isMainThread()) {
+ throw IllegalStateException("Input sessions can only be started from the main thread.")
+ }
+ logDebug { "startInputSession.state = $state" }
+ platformTextInput.requestInputFocus()
+ textInputCommandExecutor.send(TextInputCommand.StartInput)
+
+ val nextSession = createEditableTextInputSession(
+ state = state,
+ imeOptions = imeOptions,
+ initialFilter = initialFilter,
+ onImeActionPerformed = onImeActionPerformed
+ )
+ currentTextInputSession = nextSession
+ return nextSession
+ }
+
+ private fun createEditableTextInputSession(
+ state: TextFieldState,
+ imeOptions: ImeOptions,
+ initialFilter: TextEditFilter?,
+ onImeActionPerformed: (ImeAction) -> Unit
+ ) = object : EditableTextInputSession {
+
+ // Immediately start listening to reset events.
+ init {
+ state.editProcessor.addResetListener(resetListener)
+ }
+
+ // region TextInputSession
+ override val isOpen: Boolean
+ get() = currentTextInputSession == this
+
+ override fun showSoftwareKeyboard() {
+ if (isOpen) {
+ textInputCommandExecutor.send(TextInputCommand.ShowKeyboard)
+ }
+ }
+
+ override fun hideSoftwareKeyboard() {
+ if (isOpen) {
+ textInputCommandExecutor.send(TextInputCommand.HideKeyboard)
+ }
+ }
+
+ override fun dispose() {
+ state.editProcessor.removeResetListener(resetListener)
+ stopInputSession(this)
+ }
+ // endregion
+
+ // region EditableTextInputSession
+ override val value: TextFieldCharSequence
+ get() = state.text
+
+ private var filter: TextEditFilter? = initialFilter
+
+ override fun setFilter(filter: TextEditFilter?) {
+ this.filter = filter
+ }
+
+ override fun requestEdits(editCommands: List<EditCommand>) {
+ state.editProcessor.update(editCommands, filter)
+ }
+
+ override fun sendKeyEvent(keyEvent: KeyEvent) {
+ inputMethodManager.sendKeyEvent(keyEvent)
+ }
+
+ override val imeOptions: ImeOptions = imeOptions
+
+ override fun onImeAction(imeAction: ImeAction) = onImeActionPerformed(imeAction)
+ // endregion
+ }
+
+ /**
+ * Stop the given [session] if it's active and clear resources.
+ */
+ private fun stopInputSession(session: TextInputSession) {
+ if (!isMainThread()) {
+ throw IllegalStateException("Input sessions can only be stopped from the main thread.")
+ }
+ if (currentTextInputSession == session) {
+ currentTextInputSession = null
+ platformTextInput.releaseInputFocus()
+ textInputCommandExecutor.send(TextInputCommand.StopInput)
+ }
+ }
+
+ companion object {
+ private var testInputConnectionCreatedListener: ((EditorInfo, InputConnection) -> Unit)? =
+ null
+
+ /**
+ * Set a function to be called when an [AndroidTextInputAdapter] returns from
+ * [createInputConnection]. This method should only be used to assert on the [EditorInfo]
+ * and grab the [InputConnection] to inject commands.
+ */
+ @TestOnly
+ @VisibleForTesting
+ fun setInputConnectionCreatedListenerForTests(
+ listener: ((EditorInfo, InputConnection) -> Unit)?
+ ) {
+ testInputConnectionCreatedListener = listener
+ }
+ }
+}
+
+/**
+ * Commands that can be sent into [TextInputCommandExecutor].
+ */
+internal enum class TextInputCommand {
+ StartInput,
+ StopInput,
+ ShowKeyboard,
+ HideKeyboard;
+}
+
+/**
+ * TODO: kdoc
+ */
+internal class TextInputCommandExecutor(
+ private val view: View,
+ private val inputMethodManager: ComposeInputMethodManager,
+ private val inputCommandProcessorExecutor: Executor = Choreographer.getInstance().asExecutor(),
+) {
+ /**
+ * A channel that is used to debounce rapid operations such as showing/hiding the keyboard and
+ * starting/stopping input, so we can make the minimal number of calls on the
+ * [inputMethodManager]. The [TextInputCommand]s sent to this channel are processed by
+ * [processQueue].
+ */
+ private val textInputCommandQueue = mutableVectorOf<TextInputCommand>()
+ private var frameCallback: Runnable? = null
+
+ fun send(textInputCommand: TextInputCommand) {
+ textInputCommandQueue += textInputCommand
+ if (frameCallback == null) {
+ frameCallback = Runnable {
+ frameCallback = null
+ processQueue()
+ }.also(inputCommandProcessorExecutor::execute)
+ }
+ }
+
+ private fun processQueue() {
+ logDebug { "processQueue has started" }
+ // When focus changes to a non-Compose view, the system will take care of managing the
+ // keyboard (via ImeFocusController) so we don't need to do anything. This can happen
+ // when a Compose text field is focused, then the user taps on an EditText view.
+ // And any commands that come in while we're not focused should also just be ignored,
+ // since no unfocused view should be messing with the keyboard.
+ // TODO(b/215761849) When focus moves to a different ComposeView than this one, this
+ // logic doesn't work and the keyboard is not hidden.
+ if (!view.isFocused) {
+ logDebug { "processing queue returning early because the view is not focused" }
+ // All queued commands should be ignored.
+ textInputCommandQueue.clear()
+ return
+ }
+
+ // Multiple commands may have been queued up in the channel while this function was
+ // waiting to be resumed. We don't execute the commands as they come in because making a
+ // bunch of calls to change the actual IME quickly can result in flickers. Instead, we
+ // manually coalesce the commands to figure out the minimum number of IME operations we
+ // need to get to the desired final state.
+ // The queued commands effectively operate on a simple state machine consisting of two
+ // flags:
+ // 1. Whether to start a new input connection (true), tear down the input connection
+ // (false), or leave the current connection as-is (null).
+ var startInput: Boolean? = null
+ // 2. Whether to show the keyboard (true), hide the keyboard (false), or leave the
+ // keyboard visibility as-is (null).
+ var showKeyboard: Boolean? = null
+
+ // And a function that performs the appropriate state transition given a command.
+ fun TextInputCommand.applyToState() {
+ when (this) {
+ TextInputCommand.StartInput -> {
+ // Any commands before restarting the input are meaningless since they would
+ // apply to the connection we're going to tear down and recreate.
+ // Starting a new connection implicitly stops the previous connection.
+ startInput = true
+ // It doesn't make sense to start a new connection without the keyboard
+ // showing.
+ showKeyboard = true
+ }
+
+ TextInputCommand.StopInput -> {
+ startInput = false
+ // It also doesn't make sense to keep the keyboard visible if it's not
+ // connected to anything. Note that this is different than the Android
+ // default behavior for Views, which is to keep the keyboard showing even
+ // after the view that the IME was shown for loses focus.
+ // See this doc for some notes and discussion on whether we should auto-hide
+ // or match Android:
+ // https://docs.google.com/document/d/1o-y3NkfFPCBhfDekdVEEl41tqtjjqs8jOss6txNgqaw/edit?resourcekey=0-o728aLn51uXXnA4Pkpe88Q#heading=h.ieacosb5rizm
+ showKeyboard = false
+ }
+
+ TextInputCommand.ShowKeyboard,
+ TextInputCommand.HideKeyboard -> {
+ // Any keyboard visibility commands sent after input is stopped but before
+ // input is started should be ignored.
+ // Otherwise, the last visibility command sent either before the last stop
+ // command, or after the last start command, is the one that should take
+ // effect.
+ if (startInput != false) {
+ showKeyboard = this == TextInputCommand.ShowKeyboard
+ }
+ }
+ }
+ }
+
+ // Feed all the queued commands into the state machine.
+ textInputCommandQueue.forEach { command ->
+ command.applyToState()
+ logDebug { "command: $command applied to state" }
+ }
+
+ logDebug { "commands are applied. startInput = $startInput, showKeyboard = $showKeyboard" }
+
+ // Now that we've calculated what operations we need to perform on the actual input
+ // manager, perform them.
+ // If the keyboard visibility was changed after starting a new connection, we need to
+ // perform that operation change after starting it.
+ // If the keyboard visibility was changed before closing the connection, we need to
+ // perform that operation before closing the connection so it doesn't no-op.
+ if (startInput == true) {
+ restartInputImmediately()
+ }
+ showKeyboard?.also(::setKeyboardVisibleImmediately)
+ if (startInput == false) {
+ restartInputImmediately()
+ }
+ }
+
+ /** Immediately restart the IME connection, bypassing the [textInputCommandQueue]. */
+ private fun restartInputImmediately() {
+ logDebug { "restartInputImmediately" }
+ inputMethodManager.restartInput()
+ }
+
+ /** Immediately show or hide the keyboard, bypassing the [textInputCommandQueue]. */
+ private fun setKeyboardVisibleImmediately(visible: Boolean) {
+ logDebug { "setKeyboardVisibleImmediately(visible: $visible)" }
+ if (visible) {
+ inputMethodManager.showSoftInput()
+ } else {
+ inputMethodManager.hideSoftInput()
+ }
+ }
+}
+
+private fun Choreographer.asExecutor(): Executor = Executor { runnable ->
+ postFrameCallback { runnable.run() }
+}
+
+/**
+ * Fills necessary info of EditorInfo.
+ */
+internal fun EditorInfo.update(textFieldValue: TextFieldCharSequence, imeOptions: ImeOptions) {
+ this.imeOptions = when (imeOptions.imeAction) {
+ ImeAction.Default -> {
+ if (imeOptions.singleLine) {
+ // this is the last resort to enable single line
+ // Android IME still shows return key even if multi line is not send
+ // TextView.java#onCreateInputConnection
+ EditorInfo.IME_ACTION_DONE
+ } else {
+ EditorInfo.IME_ACTION_UNSPECIFIED
+ }
+ }
+ ImeAction.None -> EditorInfo.IME_ACTION_NONE
+ ImeAction.Go -> EditorInfo.IME_ACTION_GO
+ ImeAction.Next -> EditorInfo.IME_ACTION_NEXT
+ ImeAction.Previous -> EditorInfo.IME_ACTION_PREVIOUS
+ ImeAction.Search -> EditorInfo.IME_ACTION_SEARCH
+ ImeAction.Send -> EditorInfo.IME_ACTION_SEND
+ ImeAction.Done -> EditorInfo.IME_ACTION_DONE
+ else -> error("invalid ImeAction")
+ }
+
+ this.inputType = when (imeOptions.keyboardType) {
+ KeyboardType.Text -> InputType.TYPE_CLASS_TEXT
+ KeyboardType.Ascii -> {
+ this.imeOptions = this.imeOptions or EditorInfo.IME_FLAG_FORCE_ASCII
+ InputType.TYPE_CLASS_TEXT
+ }
+ KeyboardType.Number ->
+ InputType.TYPE_CLASS_NUMBER
+ KeyboardType.Phone ->
+ InputType.TYPE_CLASS_PHONE
+ KeyboardType.Uri ->
+ InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_URI
+ KeyboardType.Email ->
+ InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+ KeyboardType.Password ->
+ InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
+ KeyboardType.NumberPassword ->
+ InputType.TYPE_CLASS_NUMBER or EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD
+ KeyboardType.Decimal ->
+ InputType.TYPE_CLASS_NUMBER or EditorInfo.TYPE_NUMBER_FLAG_DECIMAL
+ else -> error("Invalid Keyboard Type")
+ }
+
+ if (!imeOptions.singleLine) {
+ if (hasFlag(this.inputType, InputType.TYPE_CLASS_TEXT)) {
+ // TextView.java#setInputTypeSingleLine
+ this.inputType = this.inputType or InputType.TYPE_TEXT_FLAG_MULTI_LINE
+
+ if (imeOptions.imeAction == ImeAction.Default) {
+ this.imeOptions = this.imeOptions or EditorInfo.IME_FLAG_NO_ENTER_ACTION
+ }
+ }
+ }
+
+ if (hasFlag(this.inputType, InputType.TYPE_CLASS_TEXT)) {
+ when (imeOptions.capitalization) {
+ KeyboardCapitalization.Characters -> {
+ this.inputType = this.inputType or InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
+ }
+
+ KeyboardCapitalization.Words -> {
+ this.inputType = this.inputType or InputType.TYPE_TEXT_FLAG_CAP_WORDS
+ }
+
+ KeyboardCapitalization.Sentences -> {
+ this.inputType = this.inputType or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
+ }
+
+ else -> {
+ /* do nothing */
+ }
+ }
+
+ if (imeOptions.autoCorrect) {
+ this.inputType = this.inputType or InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
+ }
+ }
+
+ this.initialSelStart = textFieldValue.selectionInChars.start
+ this.initialSelEnd = textFieldValue.selectionInChars.end
+
+ EditorInfoCompat.setInitialSurroundingText(this, textFieldValue)
+
+ this.imeOptions = this.imeOptions or EditorInfo.IME_FLAG_NO_FULLSCREEN
+}
+
+private fun hasFlag(bits: Int, flag: Int): Boolean = (bits and flag) == flag
+
+private fun logDebug(tag: String = TAG, content: () -> String) {
+ if (TIA_DEBUG) {
+ Log.d(tag, content())
+ }
+}
+
+private fun isMainThread() = Looper.myLooper() === Looper.getMainLooper()
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputPlugin.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputPlugin.kt
new file mode 100644
index 0000000..341bb9b6a
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputPlugin.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.
+ */
+
+package androidx.compose.foundation.text2.input.internal
+
+import android.view.View
+import androidx.compose.ui.text.input.PlatformTextInput
+import androidx.compose.ui.text.input.PlatformTextInputPlugin
+
+internal object AndroidTextInputPlugin : PlatformTextInputPlugin<AndroidTextInputAdapter> {
+
+ override fun createAdapter(
+ platformTextInput: PlatformTextInput,
+ view: View
+ ): AndroidTextInputAdapter {
+ return AndroidTextInputAdapter(view, platformTextInput)
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ApplyEditCommand.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ApplyEditCommand.kt
new file mode 100644
index 0000000..f169040
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ApplyEditCommand.kt
@@ -0,0 +1,255 @@
+/*
+ * 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.input.internal
+
+import java.text.BreakIterator
+
+/**
+ * Applies a given [EditCommand] on this [EditingBuffer].
+ *
+ * Usually calls a dedicated extension function for a given subclass of [EditCommand].
+ *
+ * @throws IllegalArgumentException if EditCommand is not recognized.
+ */
+internal fun EditingBuffer.update(editCommand: EditCommand) {
+ when (editCommand) {
+ is BackspaceCommand -> applyBackspaceCommand()
+ is CommitTextCommand -> applyCommitTextCommand(editCommand)
+ is DeleteAllCommand -> replace(0, length, "")
+ is DeleteSurroundingTextCommand -> applyDeleteSurroundingTextCommand(editCommand)
+ is DeleteSurroundingTextInCodePointsCommand ->
+ applyDeleteSurroundingTextInCodePointsCommand(editCommand)
+ is FinishComposingTextCommand -> commitComposition()
+ is MoveCursorCommand -> applyMoveCursorCommand(editCommand)
+ is SetComposingRegionCommand -> applySetComposingRegionCommand(editCommand)
+ is SetComposingTextCommand -> applySetComposingTextCommand(editCommand)
+ is SetSelectionCommand -> applySetSelectionCommand(editCommand)
+ }
+}
+
+private fun EditingBuffer.applySetSelectionCommand(setSelectionCommand: SetSelectionCommand) {
+ // Sanitize the input: reverse if reversed, clamped into valid range.
+ val clampedStart = setSelectionCommand.start.coerceIn(0, length)
+ val clampedEnd = setSelectionCommand.end.coerceIn(0, length)
+ if (clampedStart < clampedEnd) {
+ setSelection(clampedStart, clampedEnd)
+ } else {
+ setSelection(clampedEnd, clampedStart)
+ }
+}
+
+private fun EditingBuffer.applySetComposingTextCommand(
+ setComposingTextCommand: SetComposingTextCommand
+) {
+ val text = setComposingTextCommand.text
+ val newCursorPosition = setComposingTextCommand.newCursorPosition
+
+ if (hasComposition()) {
+ // API doc says, if there is ongoing composing text, replace it with new text.
+ val compositionStart = compositionStart
+ replace(compositionStart, compositionEnd, text)
+ if (text.isNotEmpty()) {
+ setComposition(compositionStart, compositionStart + text.length)
+ }
+ } else {
+ // If there is no composing text, insert composing text into cursor position with
+ // removing selected text if any.
+ val selectionStart = selectionStart
+ replace(selectionStart, selectionEnd, text)
+ if (text.isNotEmpty()) {
+ setComposition(selectionStart, selectionStart + text.length)
+ }
+ }
+
+ // After replace function is called, the editing buffer places the cursor at the end of the
+ // modified range.
+ val newCursor = cursor
+
+ // See above API description for the meaning of newCursorPosition.
+ val newCursorInBuffer = if (newCursorPosition > 0) {
+ newCursor + newCursorPosition - 1
+ } else {
+ newCursor + newCursorPosition - text.length
+ }
+
+ cursor = newCursorInBuffer.coerceIn(0, length)
+}
+
+private fun EditingBuffer.applySetComposingRegionCommand(
+ setComposingRegionCommand: SetComposingRegionCommand
+) {
+ // The API description says, different from SetComposingText, SetComposingRegion must
+ // preserve the ongoing composition text and set new composition.
+ if (hasComposition()) {
+ commitComposition()
+ }
+
+ // Sanitize the input: reverse if reversed, clamped into valid range, ignore empty range.
+ val clampedStart = setComposingRegionCommand.start.coerceIn(0, length)
+ val clampedEnd = setComposingRegionCommand.end.coerceIn(0, length)
+ if (clampedStart == clampedEnd) {
+ // do nothing. empty composition range is not allowed.
+ } else if (clampedStart < clampedEnd) {
+ setComposition(clampedStart, clampedEnd)
+ } else {
+ setComposition(clampedEnd, clampedStart)
+ }
+}
+
+private fun EditingBuffer.applyMoveCursorCommand(moveCursorCommand: MoveCursorCommand) {
+ if (cursor == -1) {
+ cursor = selectionStart
+ }
+
+ var newCursor = selectionStart
+ val bufferText = toString()
+ if (moveCursorCommand.amount > 0) {
+ for (i in 0 until moveCursorCommand.amount) {
+ val next = bufferText.findFollowingBreak(newCursor)
+ if (next == -1) break
+ newCursor = next
+ }
+ } else {
+ for (i in 0 until -moveCursorCommand.amount) {
+ val prev = bufferText.findPrecedingBreak(newCursor)
+ if (prev == -1) break
+ newCursor = prev
+ }
+ }
+
+ cursor = newCursor
+}
+
+private fun EditingBuffer.applyDeleteSurroundingTextInCodePointsCommand(
+ deleteSurroundingTextInCodePointsCommand: DeleteSurroundingTextInCodePointsCommand
+) {
+ // Convert code point length into character length. Then call the common logic of the
+ // DeleteSurroundingTextEditOp
+ var beforeLenInChars = 0
+ for (i in 0 until deleteSurroundingTextInCodePointsCommand.lengthBeforeCursor) {
+ beforeLenInChars++
+ if (selectionStart > beforeLenInChars) {
+ val lead = this[selectionStart - beforeLenInChars - 1]
+ val trail = this[selectionStart - beforeLenInChars]
+
+ if (isSurrogatePair(lead, trail)) {
+ beforeLenInChars++
+ }
+ }
+ if (beforeLenInChars == selectionStart) break
+ }
+
+ var afterLenInChars = 0
+ for (i in 0 until deleteSurroundingTextInCodePointsCommand.lengthAfterCursor) {
+ afterLenInChars++
+ if (selectionEnd + afterLenInChars < length) {
+ val lead = this[selectionEnd + afterLenInChars - 1]
+ val trail = this[selectionEnd + afterLenInChars]
+
+ if (isSurrogatePair(lead, trail)) {
+ afterLenInChars++
+ }
+ }
+ if (selectionEnd + afterLenInChars == length) break
+ }
+
+ delete(selectionEnd, selectionEnd + afterLenInChars)
+ delete(selectionStart - beforeLenInChars, selectionStart)
+}
+
+private fun EditingBuffer.applyDeleteSurroundingTextCommand(
+ deleteSurroundingTextCommand: DeleteSurroundingTextCommand
+) {
+ // calculate the end with safe addition since lengthAfterCursor can be set to e.g. Int.MAX
+ // by the input
+ val end = selectionEnd.addExactOrElse(deleteSurroundingTextCommand.lengthAfterCursor) { length }
+ delete(selectionEnd, minOf(end, length))
+
+ // calculate the start with safe subtraction since lengthBeforeCursor can be set to e.g.
+ // Int.MAX by the input
+ val start = selectionStart.subtractExactOrElse(
+ deleteSurroundingTextCommand.lengthBeforeCursor
+ ) { 0 }
+ delete(maxOf(0, start), selectionStart)
+}
+
+private fun EditingBuffer.applyBackspaceCommand() {
+ if (hasComposition()) {
+ delete(compositionStart, compositionEnd)
+ return
+ }
+
+ if (cursor == -1) {
+ val delStart = selectionStart
+ val delEnd = selectionEnd
+ cursor = selectionStart
+ delete(delStart, delEnd)
+ return
+ }
+
+ if (cursor == 0) {
+ return
+ }
+
+ val prevCursorPos = toString().findPrecedingBreak(cursor)
+ delete(prevCursorPos, cursor)
+}
+
+private fun EditingBuffer.applyCommitTextCommand(commitTextCommand: CommitTextCommand) {
+ // API description says replace ongoing composition text if there. Then, if there is no
+ // composition text, insert text into cursor position or replace selection.
+ if (hasComposition()) {
+ replace(compositionStart, compositionEnd, commitTextCommand.text)
+ } else {
+ // In this editing buffer, insert into cursor or replace selection are equivalent.
+ replace(selectionStart, selectionEnd, commitTextCommand.text)
+ }
+
+ // After replace function is called, the editing buffer places the cursor at the end of the
+ // modified range.
+ val newCursor = cursor
+
+ // See above API description for the meaning of newCursorPosition.
+ val newCursorInBuffer = if (commitTextCommand.newCursorPosition > 0) {
+ newCursor + commitTextCommand.newCursorPosition - 1
+ } else {
+ newCursor + commitTextCommand.newCursorPosition - commitTextCommand.text.length
+ }
+
+ cursor = newCursorInBuffer.coerceIn(0, length)
+}
+
+/**
+ * Helper function that returns true when [high] is a Unicode high-surrogate code unit and [low]
+ * is a Unicode low-surrogate code unit.
+ */
+private fun isSurrogatePair(high: Char, low: Char): Boolean =
+ high.isHighSurrogate() && low.isLowSurrogate()
+
+// TODO(halilibo): Remove when migrating back to foundation
+private fun String.findPrecedingBreak(index: Int): Int {
+ val it = BreakIterator.getCharacterInstance()
+ it.setText(this)
+ return it.preceding(index)
+}
+
+// TODO(halilibo): Remove when migrating back to foundation
+private fun String.findFollowingBreak(index: Int): Int {
+ val it = BreakIterator.getCharacterInstance()
+ it.setText(this)
+ return it.following(index)
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTracker.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTracker.kt
new file mode 100644
index 0000000..1649497
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTracker.kt
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.text2.input.internal
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList
+import androidx.compose.runtime.collection.mutableVectorOf
+import androidx.compose.ui.text.TextRange
+
+/**
+ * Keeps track of changes made to a text buffer via [trackChange], and reports changes as a
+ * [ChangeList].
+ *
+ * @param initialChanges If non-null, used to initialize this tracker by copying changes.
+ */
+internal class ChangeTracker(initialChanges: ChangeTracker? = null) : ChangeList {
+
+ private var _changes = mutableVectorOf<Change>()
+ private var _changesTemp = mutableVectorOf<Change>()
+
+ init {
+ initialChanges?._changes?.forEach {
+ _changes += Change(it.preStart, it.preEnd, it.originalStart, it.originalEnd)
+ }
+ }
+
+ override val changeCount: Int
+ get() = _changes.size
+
+ /**
+ * This function deals with three "coordinate spaces":
+ * - `original`: The text before any changes were made.
+ * - `pre`: The text before this change is applied, but with all previous changes applied.
+ * - `post`: The text after this change is applied, including all the previous changes.
+ *
+ * When this function is called, the existing changes map ranges in `original` to ranges in
+ * `pre`. The new change is a mapping from `pre` to `post`. This function must determine the
+ * corresponding range in `original` for this change, and convert all other changes' `pre`
+ * ranges to `post`. It must also ensure that any adjacent or overlapping ranges are merged to
+ * ensure the [ChangeList] invariant that all changes are non-overlapping.
+ *
+ * The algorithm works as follows:
+ * 1. Find all the changes that are adjacent to or overlap with this one. This search is
+ * performed in the `pre` space since that's the space the new change shares with the
+ * existing changes.
+ * 2. Merge all the changes from (1) into a single range in the `original` and `pre` spaces.
+ * 3. Merge the new change with the change from (2), updating the end of the range to account
+ * for the new text.
+ * 3. Offset all remaining changes are to account for the new text.
+ */
+ fun trackChange(preRange: TextRange, postLength: Int) {
+ if (preRange.collapsed && postLength == 0) {
+ // Ignore noop changes.
+ return
+ }
+
+ var i = 0
+ var recordedNewChange = false
+ val postDelta = postLength - preRange.length
+
+ var mergedOverlappingChange: Change? = null
+ while (i < _changes.size) {
+ val change = _changes[i]
+
+ // Merge adjacent and overlapping changes as we go.
+ if (
+ change.preStart in preRange.min..preRange.max ||
+ change.preEnd in preRange.min..preRange.max
+ ) {
+ if (mergedOverlappingChange == null) {
+ mergedOverlappingChange = change
+ } else {
+ mergedOverlappingChange.preEnd = change.preEnd
+ mergedOverlappingChange.originalEnd = change.originalEnd
+ }
+ // Don't append overlapping changes to the temp list until we're finished merging.
+ i++
+ continue
+ }
+
+ if (change.preStart > preRange.max && !recordedNewChange) {
+ // First non-overlapping change after the new one – record the change before
+ // proceeding.
+ appendNewChange(mergedOverlappingChange, preRange, postDelta)
+ recordedNewChange = true
+ }
+
+ if (recordedNewChange) {
+ change.preStart += postDelta
+ change.preEnd += postDelta
+ }
+ _changesTemp += change
+ i++
+ }
+
+ if (!recordedNewChange) {
+ // The new change is after or overlapping all previous changes so it hasn't been
+ // appended yet.
+ appendNewChange(mergedOverlappingChange, preRange, postDelta)
+ }
+
+ // Swap the lists.
+ val oldChanges = _changes
+ _changes = _changesTemp
+ _changesTemp = oldChanges
+ _changesTemp.clear()
+ }
+
+ fun clearChanges() {
+ _changes.clear()
+ }
+
+ override fun getRange(changeIndex: Int): TextRange =
+ _changes[changeIndex].let { TextRange(it.preStart, it.preEnd) }
+
+ override fun getOriginalRange(changeIndex: Int): TextRange =
+ _changes[changeIndex].let { TextRange(it.originalStart, it.originalEnd) }
+
+ override fun toString(): String = buildString {
+ append("ChangeList(changes=[")
+ _changes.forEachIndexed { i, change ->
+ append(
+ "(${change.originalStart},${change.originalEnd})->" +
+ "(${change.preStart},${change.preEnd})"
+ )
+ if (i < changeCount - 1) append(", ")
+ }
+ append("])")
+ }
+
+ private fun appendNewChange(
+ mergedOverlappingChange: Change?,
+ preRange: TextRange,
+ postDelta: Int
+ ) {
+ var originalDelta = if (_changesTemp.isEmpty()) 0 else {
+ _changesTemp.last().let { it.preEnd - it.originalEnd }
+ }
+ val newChange: Change
+ if (mergedOverlappingChange == null) {
+ // There were no overlapping changes, so allocate a new one.
+ val originalStart = preRange.min - originalDelta
+ val originalEnd = originalStart + preRange.length
+ newChange = Change(
+ preStart = preRange.min,
+ preEnd = preRange.max + postDelta,
+ originalStart = originalStart,
+ originalEnd = originalEnd
+ )
+ } else {
+ newChange = mergedOverlappingChange
+ // Convert the merged overlapping changes to the `post` space.
+ // Merge the new changed with the merged overlapping changes.
+ if (newChange.preStart > preRange.min) {
+ // The new change starts before the merged overlapping set.
+ newChange.preStart = preRange.min
+ newChange.originalStart = preRange.min
+ }
+ if (preRange.max > newChange.preEnd) {
+ // The new change ends after the merged overlapping set.
+ originalDelta = newChange.preEnd - newChange.originalEnd
+ newChange.preEnd = preRange.max
+ newChange.originalEnd = preRange.max - originalDelta
+ }
+ newChange.preEnd += postDelta
+ }
+ _changesTemp += newChange
+ }
+
+ private data class Change(
+ var preStart: Int,
+ var preEnd: Int,
+ var originalStart: Int,
+ var originalEnd: Int
+ )
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ComposeInputMethodManager.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ComposeInputMethodManager.kt
new file mode 100644
index 0000000..caccd1a
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ComposeInputMethodManager.kt
@@ -0,0 +1,171 @@
+/*
+ * 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.input.internal
+
+import android.content.Context
+import android.os.Build
+import android.view.KeyEvent
+import android.view.View
+import android.view.inputmethod.BaseInputConnection
+import android.view.inputmethod.ExtractedText
+import android.view.inputmethod.InputMethodManager
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import androidx.core.view.SoftwareKeyboardControllerCompat
+import org.jetbrains.annotations.TestOnly
+
+/**
+ * Compatibility interface for [InputMethodManager] to use in Compose text input systems.
+ *
+ * This interface is responsible for handling the calls made to platform InputMethodManager in
+ * Android. There are different ways to show and hide software keyboard depending on API level.
+ *
+ * This interface also allows us to fake out the IMM for testing. For that reason, it should match
+ * the relevant platform [InputMethodManager] APIs as closely as possible.
+ */
+internal interface ComposeInputMethodManager {
+ fun restartInput()
+
+ fun showSoftInput()
+
+ fun hideSoftInput()
+
+ fun updateExtractedText(
+ token: Int,
+ extractedText: ExtractedText
+ )
+
+ fun updateSelection(
+ selectionStart: Int,
+ selectionEnd: Int,
+ compositionStart: Int,
+ compositionEnd: Int
+ )
+
+ /**
+ * Sends a [KeyEvent] originated from an InputMethod to the Window. This is a necessary
+ * delegation when the InputConnection itself does not handle the received event.
+ */
+ fun sendKeyEvent(event: KeyEvent)
+}
+
+/**
+ * Creates a new instance of [ComposeInputMethodManager].
+ *
+ * The value returned by this function can be changed for tests by calling
+ * [overrideComposeInputMethodManagerFactoryForTests].
+ */
+internal fun ComposeInputMethodManager(view: View): ComposeInputMethodManager =
+ ComposeInputMethodManagerFactory(view)
+
+/** This lets us swap out the implementation in our own tests. */
+private var ComposeInputMethodManagerFactory: (View) -> ComposeInputMethodManager = { view ->
+ when {
+ Build.VERSION.SDK_INT >= 24 -> ComposeInputMethodManagerImplApi24(view)
+ else -> ComposeInputMethodManagerImplApi21(view)
+ }
+}
+
+/**
+ * Sets the factory used by [ComposeInputMethodManager] to create instances and returns the previous
+ * factory.
+ *
+ * Any test that calls this should call it again to restore the factory after the test finishes, to
+ * avoid breaking unrelated tests.
+ */
+@TestOnly
+@VisibleForTesting
+internal fun overrideComposeInputMethodManagerFactoryForTests(
+ factory: (View) -> ComposeInputMethodManager
+): (View) -> ComposeInputMethodManager {
+ val oldFactory = ComposeInputMethodManagerFactory
+ ComposeInputMethodManagerFactory = factory
+ return oldFactory
+}
+
+private abstract class ComposeInputMethodManagerImpl(protected val view: View) :
+ ComposeInputMethodManager {
+
+ private var imm: InputMethodManager? = null
+
+ private val softwareKeyboardControllerCompat =
+ SoftwareKeyboardControllerCompat(view)
+
+ override fun restartInput() {
+ requireImm().restartInput(view)
+ }
+
+ override fun showSoftInput() {
+ softwareKeyboardControllerCompat.show()
+ }
+
+ override fun hideSoftInput() {
+ softwareKeyboardControllerCompat.hide()
+ }
+
+ override fun updateExtractedText(
+ token: Int,
+ extractedText: ExtractedText
+ ) {
+ requireImm().updateExtractedText(view, token, extractedText)
+ }
+
+ override fun updateSelection(
+ selectionStart: Int,
+ selectionEnd: Int,
+ compositionStart: Int,
+ compositionEnd: Int
+ ) {
+ requireImm().updateSelection(
+ view,
+ selectionStart,
+ selectionEnd,
+ compositionStart,
+ compositionEnd
+ )
+ }
+
+ protected fun requireImm(): InputMethodManager = imm ?: createImm().also { imm = it }
+
+ private fun createImm() =
+ view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+}
+
+private open class ComposeInputMethodManagerImplApi21(view: View) :
+ ComposeInputMethodManagerImpl(view) {
+
+ /**
+ * Prior to API24, the safest way to delegate IME originated KeyEvents to the window was
+ * through BaseInputConnection.
+ */
+ private var baseInputConnection: BaseInputConnection? = null
+
+ override fun sendKeyEvent(event: KeyEvent) {
+ val baseInputConnection = baseInputConnection
+ ?: BaseInputConnection(view, false).also { baseInputConnection = it }
+ baseInputConnection.sendKeyEvent(event)
+ }
+}
+
+@RequiresApi(24)
+private open class ComposeInputMethodManagerImplApi24(view: View) :
+ ComposeInputMethodManagerImplApi21(view) {
+
+ override fun sendKeyEvent(event: KeyEvent) {
+ requireImm().dispatchKeyEventFromInputMethod(view, event)
+ }
+}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditCommand.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditCommand.kt
new file mode 100644
index 0000000..fae3413
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditCommand.kt
@@ -0,0 +1,241 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.AnnotatedString
+
+/**
+ * [EditCommand] is a command representation for the platform IME API function calls. The commands
+ * from the IME as function calls are translated into command pattern. For example, as a result of
+ * commit text function call by IME [CommitTextCommand] is created.
+ */
+// TODO(halilibo): Consider value class or some other alternatives like passing the buffer into
+// InputConnection, eliminating the need for EditCommand.
+internal sealed interface EditCommand
+
+/**
+ * Commit final [text] to the text box and set the new cursor position.
+ *
+ * See [`commitText`](https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#commitText(java.lang.CharSequence,%20int)).
+ *
+ * @param annotatedString The text to commit.
+ * @param newCursorPosition The cursor position after inserted text.
+ */
+internal data class CommitTextCommand(
+ val annotatedString: AnnotatedString,
+ val newCursorPosition: Int
+) : EditCommand {
+
+ constructor(
+ /**
+ * The text to commit. We ignore any styles in the original API.
+ */
+ text: String,
+ /**
+ * The cursor position after setting composing text.
+ */
+ newCursorPosition: Int
+ ) : this(AnnotatedString(text), newCursorPosition)
+
+ val text: String get() = annotatedString.text
+
+ override fun toString(): String {
+ return "CommitTextCommand(text='$text', newCursorPosition=$newCursorPosition)"
+ }
+}
+
+/**
+ * Mark a certain region of text as composing text.
+ *
+ * See [`setComposingRegion`](https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingRegion(int,%2520int)).
+ *
+ * @param start The inclusive start offset of the composing region.
+ * @param end The exclusive end offset of the composing region
+ */
+internal data class SetComposingRegionCommand(
+ val start: Int,
+ val end: Int
+) : EditCommand {
+
+ override fun toString(): String {
+ return "SetComposingRegionCommand(start=$start, end=$end)"
+ }
+}
+
+/**
+ * Replace the currently composing text with the given text, and set the new cursor position. Any
+ * composing text set previously will be removed automatically.
+ *
+ * See [`setComposingText`](https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingText(java.lang.CharSequence,%2520int)).
+ *
+ * @param annotatedString The composing text.
+ * @param newCursorPosition The cursor position after setting composing text.
+ */
+internal data class SetComposingTextCommand(
+ val annotatedString: AnnotatedString,
+ val newCursorPosition: Int
+) : EditCommand {
+
+ constructor(
+ /**
+ * The composing text.
+ */
+ text: String,
+ /**
+ * The cursor position after setting composing text.
+ */
+ newCursorPosition: Int
+ ) : this(AnnotatedString(text), newCursorPosition)
+
+ val text: String get() = annotatedString.text
+
+ override fun toString(): String {
+ return "SetComposingTextCommand(text='$text', newCursorPosition=$newCursorPosition)"
+ }
+}
+
+/**
+ * Delete [lengthBeforeCursor] characters of text before the current cursor position, and delete
+ * [lengthAfterCursor] characters of text after the current cursor position, excluding the selection.
+ *
+ * Before and after refer to the order of the characters in the string, not to their visual
+ * representation.
+ *
+ * See [`deleteSurroundingText`](https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#deleteSurroundingText(int,%2520int)).
+ *
+ * @param lengthBeforeCursor The number of characters in UTF-16 before the cursor to be deleted.
+ * Must be non-negative.
+ * @param lengthAfterCursor The number of characters in UTF-16 after the cursor to be deleted.
+ * Must be non-negative.
+ */
+internal data class DeleteSurroundingTextCommand(
+ val lengthBeforeCursor: Int,
+ val lengthAfterCursor: Int
+) : EditCommand {
+ init {
+ require(lengthBeforeCursor >= 0 && lengthAfterCursor >= 0) {
+ "Expected lengthBeforeCursor and lengthAfterCursor to be non-negative, were " +
+ "$lengthBeforeCursor and $lengthAfterCursor respectively."
+ }
+ }
+
+ override fun toString(): String {
+ return "DeleteSurroundingTextCommand(lengthBeforeCursor=$lengthBeforeCursor, " +
+ "lengthAfterCursor=$lengthAfterCursor)"
+ }
+}
+
+/**
+ * A variant of [DeleteSurroundingTextCommand]. The difference is that
+ * * The lengths are supplied in code points, not in chars.
+ * * This command does nothing if there are one or more invalid surrogate pairs
+ * in the requested range.
+ *
+ * See [`deleteSurroundingTextInCodePoints`](https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#deleteSurroundingTextInCodePoints(int,%2520int)).
+ *
+ * @param lengthBeforeCursor The number of characters in Unicode code points before the cursor to be
+ * deleted. Must be non-negative.
+ * @param lengthAfterCursor The number of characters in Unicode code points after the cursor to be
+ * deleted. Must be non-negative.
+ */
+internal data class DeleteSurroundingTextInCodePointsCommand(
+ val lengthBeforeCursor: Int,
+ val lengthAfterCursor: Int
+) : EditCommand {
+ init {
+ require(lengthBeforeCursor >= 0 && lengthAfterCursor >= 0) {
+ "Expected lengthBeforeCursor and lengthAfterCursor to be non-negative, were " +
+ "$lengthBeforeCursor and $lengthAfterCursor respectively."
+ }
+ }
+
+ override fun toString(): String {
+ return "DeleteSurroundingTextInCodePointsCommand(lengthBeforeCursor=$lengthBeforeCursor, " +
+ "lengthAfterCursor=$lengthAfterCursor)"
+ }
+}
+
+/**
+ * Sets the selection on the text. When [start] and [end] have the same value, it sets the cursor
+ * position.
+ *
+ * See [`setSelection`](https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setSelection(int,%2520int)).
+ *
+ * @param start The inclusive start offset of the selection region.
+ * @param end The exclusive end offset of the selection region.
+ */
+internal data class SetSelectionCommand(
+ val start: Int,
+ val end: Int
+) : EditCommand {
+
+ override fun toString(): String {
+ return "SetSelectionCommand(start=$start, end=$end)"
+ }
+}
+
+/**
+ * Finishes the composing text that is currently active. This simply leaves the text as-is,
+ * removing any special composing styling or other state that was around it. The cursor position
+ * remains unchanged.
+ *
+ * See [`finishComposingText`](https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#finishComposingText()).
+ */
+internal object FinishComposingTextCommand : EditCommand {
+
+ override fun toString(): String {
+ return "FinishComposingTextCommand()"
+ }
+}
+
+/**
+ * Represents a backspace operation at the cursor position.
+ *
+ * If there is composition, delete the text in the composition range.
+ * If there is no composition but there is selection, delete whole selected range.
+ * If there is no composition and selection, perform backspace key event at the cursor position.
+ */
+internal object BackspaceCommand : EditCommand {
+
+ override fun toString(): String {
+ return "BackspaceCommand()"
+ }
+}
+
+/**
+ * Moves the cursor with [amount] characters.
+ *
+ * If there is selection, cancel the selection first and move the cursor to the selection start
+ * position. Then perform the cursor movement.
+ *
+ * @param amount The amount of cursor movement. If you want to move backward, pass negative value.
+ */
+internal data class MoveCursorCommand(val amount: Int) : EditCommand {
+ override fun toString(): String {
+ return "MoveCursorCommand(amount=$amount)"
+ }
+}
+
+/**
+ * Deletes all the text in the buffer.
+ */
+internal object DeleteAllCommand : EditCommand {
+
+ override fun toString(): String {
+ return "DeleteAllCommand()"
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessor.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessor.kt
new file mode 100644
index 0000000..a089951
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessor.kt
@@ -0,0 +1,248 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldBufferWithSelection
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.runtime.State
+import androidx.compose.runtime.collection.mutableVectorOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.input.TextInputService
+import androidx.compose.ui.util.fastForEach
+
+/**
+ * Helper class to apply [EditCommand]s on an internal buffer. Used by TextField Composable
+ * to combine TextFieldValue lifecycle with the editing operations.
+ *
+ * When a [TextFieldValue] is suggested by the developer, [reset] should be called.
+ * When [TextInputService] provides [EditCommand]s, they should be applied to the internal
+ * buffer using [apply].
+ */
+@OptIn(ExperimentalFoundationApi::class)
+internal class EditProcessor(
+ initialValue: TextFieldCharSequence = TextFieldCharSequence("", TextRange.Zero),
+) {
+
+ private val valueMutableState = mutableStateOf(initialValue)
+
+ /**
+ * The current state of the internal editing buffer as a [TextFieldCharSequence] backed by
+ * snapshot state, so its readers can get updates in composition context.
+ */
+ var value: TextFieldCharSequence by valueMutableState
+ private set
+
+ val valueState: State<TextFieldCharSequence> get() = valueMutableState
+
+ // The editing buffer used for applying editor commands from IME.
+ internal var mBuffer: EditingBuffer = EditingBuffer(
+ text = initialValue.toString(),
+ selection = initialValue.selectionInChars
+ )
+ private set
+
+ private val resetListeners = mutableVectorOf<ResetListener>()
+
+ /**
+ * Must be called whenever TextFieldValue needs to change directly, not using EditCommands.
+ *
+ * This method updates the internal editing buffer with the given TextFieldValue.
+ * This method may tell the IME about the selection offset changes or extracted text changes.
+ *
+ * Retro(halilibo); this function seems straightforward but it actually does something very
+ * specific for the previous state hoisting design of TextField. In each recomposition, this
+ * function was supposed to be called from BasicTextField with the new value. However, this new
+ * value wouldn't be new to the internal buffer since the changes coming from IME were already
+ * applied in the previous composition and sent through onValueChange to the hoisted state.
+ *
+ * Therefore, this function has to care for two scenarios. 1) Developer doesn't interfere with
+ * the value and the editing buffer doesn't have to change because previous composition value
+ * is sent back. 2) Developer interferes and the new value is different than the current buffer
+ * state. The difference could be text, selection, or composition.
+ *
+ * In short, `reset` function used to compare newly arrived value in this composition with the
+ * internal buffer for any differences. This won't be necessary anymore since the internal state
+ * is going to be the only source of truth for the new BasicTextField. However, `reset` would
+ * gain a new responsibility in the cases where developer filters the input or adds a template.
+ * This would again introduce a need for sync between internal buffer and the state value.
+ */
+ fun reset(newValue: TextFieldCharSequence) {
+ val bufferState = TextFieldCharSequence(
+ mBuffer.toString(),
+ mBuffer.selection,
+ mBuffer.composition
+ )
+
+ var textChanged = false
+ var selectionChanged = false
+ val compositionChanged = newValue.compositionInChars != mBuffer.composition
+
+ if (!bufferState.contentEquals(newValue)) {
+ // reset the buffer in its entirety
+ mBuffer = EditingBuffer(
+ text = newValue.toString(),
+ selection = newValue.selectionInChars
+ )
+ textChanged = true
+ } else if (bufferState.selectionInChars != newValue.selectionInChars) {
+ mBuffer.setSelection(newValue.selectionInChars.min, newValue.selectionInChars.max)
+ selectionChanged = true
+ }
+
+ val composition = newValue.compositionInChars
+ if (composition == null || composition.collapsed) {
+ mBuffer.commitComposition()
+ } else {
+ mBuffer.setComposition(composition.min, composition.max)
+ }
+
+ // TODO(halilibo): This could be unnecessary when we figure out how to correctly
+ // communicate composing region changes back to IME.
+ if (textChanged || (!selectionChanged && compositionChanged)) {
+ mBuffer.commitComposition()
+ }
+
+ val finalValue = TextFieldCharSequence(
+ if (textChanged) newValue else bufferState,
+ mBuffer.selection,
+ mBuffer.composition
+ )
+
+ resetListeners.forEach { it.onReset(bufferState, finalValue) }
+
+ value = finalValue
+ }
+
+ /**
+ * Applies a set of [editCommands] to the internal text editing buffer.
+ *
+ * After applying the changes, returns the final state of the editing buffer as a
+ * [TextFieldValue]
+ *
+ * @param editCommands [EditCommand]s to be applied to the editing buffer.
+ *
+ * @return the [TextFieldValue] representation of the final buffer state.
+ */
+ fun update(editCommands: List<EditCommand>, filter: TextEditFilter?) {
+ var lastCommand: EditCommand? = null
+ mBuffer.changeTracker.clearChanges()
+ try {
+ editCommands.fastForEach {
+ lastCommand = it
+ mBuffer.update(it)
+ }
+ } catch (e: Exception) {
+ throw RuntimeException(generateBatchErrorMessage(editCommands, lastCommand), e)
+ }
+
+ val proposedValue = TextFieldCharSequence(
+ text = mBuffer.toString(),
+ selection = mBuffer.selection,
+ composition = mBuffer.composition
+ )
+
+ @Suppress("NAME_SHADOWING")
+ val filter = filter
+ if (filter == null) {
+ value = proposedValue
+ } else {
+ val oldValue = value
+ val mutableValue = TextFieldBufferWithSelection(
+ value = proposedValue,
+ sourceValue = oldValue,
+ initialChanges = mBuffer.changeTracker
+ )
+ filter.filter(originalValue = oldValue, valueWithChanges = mutableValue)
+ // If neither the text nor the selection changed, we want to preserve the composition.
+ // Otherwise, the IME will reset it anyway.
+ val newValue = mutableValue.toTextFieldCharSequence(proposedValue.compositionInChars)
+ if (newValue == proposedValue) {
+ value = newValue
+ } else {
+ reset(newValue)
+ }
+ }
+ }
+
+ private fun generateBatchErrorMessage(
+ editCommands: List<EditCommand>,
+ failedCommand: EditCommand?,
+ ): String = buildString {
+ appendLine(
+ "Error while applying EditCommand batch to buffer (" +
+ "length=${mBuffer.length}, " +
+ "composition=${mBuffer.composition}, " +
+ "selection=${mBuffer.selection}):"
+ )
+ @Suppress("ListIterator")
+ editCommands.joinTo(this, separator = "\n") {
+ val prefix = if (failedCommand === it) " > " else " "
+ prefix + it.toStringForLog()
+ }
+ }
+
+ internal fun addResetListener(resetListener: ResetListener) {
+ resetListeners.add(resetListener)
+ }
+
+ internal fun removeResetListener(resetListener: ResetListener) {
+ resetListeners.remove(resetListener)
+ }
+
+ /**
+ * A listener that can be attached to an EditProcessor to listen for reset events. State in
+ * EditProcessor can change through filters or direct access. Unlike IME events (EditCommands),
+ * these direct changes should be immediately passed onto IME to keep editor state and IME in
+ * sync. Moreover, some changes can even require an input session restart to reset the state
+ * in IME.
+ */
+ internal fun interface ResetListener {
+
+ fun onReset(oldValue: TextFieldCharSequence, newValue: TextFieldCharSequence)
+ }
+}
+
+/**
+ * Generate a description of the command that is suitable for logging – this should not include
+ * any user-entered text, which may be sensitive.
+ */
+internal fun EditCommand.toStringForLog(): String = when (this) {
+ is CommitTextCommand ->
+ "CommitTextCommand(text.length=${text.length}, newCursorPosition=$newCursorPosition)"
+
+ is SetComposingTextCommand ->
+ "SetComposingTextCommand(text.length=${text.length}, " +
+ "newCursorPosition=$newCursorPosition)"
+
+ is SetComposingRegionCommand -> toString()
+ is DeleteSurroundingTextCommand -> toString()
+ is DeleteSurroundingTextInCodePointsCommand -> toString()
+ is SetSelectionCommand -> toString()
+ is FinishComposingTextCommand -> toString()
+ is BackspaceCommand -> toString()
+ is MoveCursorCommand -> toString()
+ is DeleteAllCommand -> toString()
+}
+
+private val EmptyAnnotatedString = buildAnnotatedString { }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditingBuffer.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditingBuffer.kt
new file mode 100644
index 0000000..feeacb4
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditingBuffer.kt
@@ -0,0 +1,403 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.TextRange
+
+/**
+ * The editing buffer
+ *
+ * This class manages the all editing relate states, editing buffers, selection, styles, etc.
+ */
+internal class EditingBuffer(
+ /**
+ * The initial text of this editing buffer
+ */
+ text: AnnotatedString,
+ /**
+ * The initial selection range of this buffer.
+ * If you provide collapsed selection, it is treated as the cursor position. The cursor and
+ * selection cannot exists at the same time.
+ * The selection must points the valid index of the initialText, otherwise
+ * IndexOutOfBoundsException will be thrown.
+ */
+ selection: TextRange
+) {
+ internal companion object {
+ const val NOWHERE = -1
+ }
+
+ private val gapBuffer = PartialGapBuffer(text.text)
+
+ val changeTracker = ChangeTracker()
+
+ /**
+ * The inclusive selection start offset
+ */
+ var selectionStart = selection.min
+ private set(value) {
+ require(value >= 0) { "Cannot set selectionStart to a negative value: $value" }
+ field = value
+ }
+
+ /**
+ * The exclusive selection end offset
+ */
+ var selectionEnd = selection.max
+ private set(value) {
+ require(value >= 0) { "Cannot set selectionEnd to a negative value: $value" }
+ field = value
+ }
+
+ /**
+ * The inclusive composition start offset
+ *
+ * If there is no composing text, returns -1
+ */
+ var compositionStart = NOWHERE
+ private set
+
+ /**
+ * The exclusive composition end offset
+ *
+ * If there is no composing text, returns -1
+ */
+ var compositionEnd = NOWHERE
+ private set
+
+ /**
+ * Helper function that returns true if the editing buffer has composition text
+ */
+ fun hasComposition(): Boolean = compositionStart != NOWHERE
+
+ /**
+ * Returns the composition information as TextRange. Returns null if no
+ * composition is set.
+ */
+ val composition: TextRange?
+ get() = if (hasComposition()) {
+ TextRange(compositionStart, compositionEnd)
+ } else null
+
+ /**
+ * Returns the selection information as TextRange
+ */
+ val selection: TextRange
+ get() = TextRange(selectionStart, selectionEnd)
+
+ /**
+ * Helper accessor for cursor offset
+ */
+ /*VisibleForTesting*/
+ var cursor: Int
+ /**
+ * Return the cursor offset.
+ *
+ * Since selection and cursor cannot exist at the same time, return -1 if there is a
+ * selection.
+ */
+ get() = if (selectionStart == selectionEnd) selectionEnd else -1
+ /**
+ * Set the cursor offset.
+ *
+ * Since selection and cursor cannot exist at the same time, cancel selection if there is.
+ */
+ set(cursor) = setSelection(cursor, cursor)
+
+ /**
+ * [] operator for the character at the index.
+ */
+ operator fun get(index: Int): Char = gapBuffer[index]
+
+ /**
+ * Returns the length of the buffer.
+ */
+ val length: Int get() = gapBuffer.length
+
+ constructor(
+ text: String,
+ selection: TextRange
+ ) : this(AnnotatedString(text), selection)
+
+ init {
+ val start = selection.min
+ val end = selection.max
+ if (start < 0 || start > text.length) {
+ throw IndexOutOfBoundsException(
+ "start ($start) offset is outside of text region ${text.length}"
+ )
+ }
+
+ if (end < 0 || end > text.length) {
+ throw IndexOutOfBoundsException(
+ "end ($end) offset is outside of text region ${text.length}"
+ )
+ }
+
+ if (start > end) {
+ throw IllegalArgumentException("Do not set reversed range: $start > $end")
+ }
+ }
+
+ fun replace(start: Int, end: Int, text: AnnotatedString) {
+ replace(start, end, text.text)
+ }
+
+ /**
+ * Replace the text and move the cursor to the end of inserted text.
+ *
+ * This function cancels selection if there.
+ *
+ * @throws IndexOutOfBoundsException if start or end offset is outside of current buffer
+ * @throws IllegalArgumentException if start is larger than end. (reversed range)
+ */
+ fun replace(start: Int, end: Int, text: String) {
+ changeTracker.trackChange(TextRange(start, end), text.length)
+
+ if (start < 0 || start > gapBuffer.length) {
+ throw IndexOutOfBoundsException(
+ "start ($start) offset is outside of text region ${gapBuffer.length}"
+ )
+ }
+
+ if (end < 0 || end > gapBuffer.length) {
+ throw IndexOutOfBoundsException(
+ "end ($end) offset is outside of text region ${gapBuffer.length}"
+ )
+ }
+
+ if (start > end) {
+ throw IllegalArgumentException("Do not set reversed range: $start > $end")
+ }
+
+ gapBuffer.replace(start, end, text)
+
+ // On Android, all text modification APIs also provides explicit cursor location. On the
+ // hand, desktop application usually doesn't. So, here tentatively move the cursor to the
+ // end offset of the editing area for desktop like application. In case of Android,
+ // implementation will call setSelection immediately after replace function to update this
+ // tentative cursor location.
+ selectionStart = start + text.length
+ selectionEnd = start + text.length
+
+ // Similarly, if text modification happens, cancel ongoing composition. If caller want to
+ // change the composition text, it is caller responsibility to call setComposition again
+ // to set composition range after replace function.
+ compositionStart = NOWHERE
+ compositionEnd = NOWHERE
+ }
+
+ /**
+ * Remove the given range of text.
+ *
+ * Different from replace method, this doesn't move cursor location to the end of modified text.
+ * Instead, preserve the selection with adjusting the deleted text.
+ */
+ fun delete(start: Int, end: Int) {
+ changeTracker.trackChange(TextRange(start, end), 0)
+ val deleteRange = TextRange(start, end)
+
+ gapBuffer.replace(start, end, "")
+
+ val newSelection = updateRangeAfterDelete(
+ TextRange(selectionStart, selectionEnd),
+ deleteRange
+ )
+ selectionStart = newSelection.min
+ selectionEnd = newSelection.max
+
+ if (hasComposition()) {
+ val compositionRange = TextRange(compositionStart, compositionEnd)
+ val newComposition = updateRangeAfterDelete(compositionRange, deleteRange)
+ if (newComposition.collapsed) {
+ commitComposition()
+ } else {
+ compositionStart = newComposition.min
+ compositionEnd = newComposition.max
+ }
+ }
+ }
+
+ /**
+ * Mark the specified area of the text as selected text.
+ *
+ * You can set cursor by specifying the same value to `start` and `end`.
+ * The reversed range is not allowed.
+ * @param start the inclusive start offset of the selection
+ * @param end the exclusive end offset of the selection
+ *
+ * @throws IndexOutOfBoundsException if start or end offset is outside of current buffer.
+ * @throws IllegalArgumentException if start is larger than end. (reversed range)
+ */
+ fun setSelection(start: Int, end: Int) {
+ if (start < 0 || start > gapBuffer.length) {
+ throw IndexOutOfBoundsException(
+ "start ($start) offset is outside of text region ${gapBuffer.length}"
+ )
+ }
+ if (end < 0 || end > gapBuffer.length) {
+ throw IndexOutOfBoundsException(
+ "end ($end) offset is outside of text region ${gapBuffer.length}"
+ )
+ }
+ if (start > end) {
+ throw IllegalArgumentException("Do not set reversed range: $start > $end")
+ }
+
+ selectionStart = start
+ selectionEnd = end
+ }
+
+ /**
+ * Mark the specified area of the text as composition text.
+ *
+ * The empty range or reversed range is not allowed.
+ * Use clearComposition in case of clearing composition.
+ *
+ * @param start the inclusive start offset of the composition
+ * @param end the exclusive end offset of the composition
+ *
+ * @throws IndexOutOfBoundsException if start or end offset is ouside of current buffer
+ * @throws IllegalArgumentException if start is larger than or equal to end. (reversed or
+ * collapsed range)
+ */
+ fun setComposition(start: Int, end: Int) {
+ if (start < 0 || start > gapBuffer.length) {
+ throw IndexOutOfBoundsException(
+ "start ($start) offset is outside of text region ${gapBuffer.length}"
+ )
+ }
+ if (end < 0 || end > gapBuffer.length) {
+ throw IndexOutOfBoundsException(
+ "end ($end) offset is outside of text region ${gapBuffer.length}"
+ )
+ }
+ if (start >= end) {
+ throw IllegalArgumentException("Do not set reversed or empty range: $start > $end")
+ }
+
+ compositionStart = start
+ compositionEnd = end
+ }
+
+ /**
+ * Removes the ongoing composition text and reset the composition range.
+ */
+ fun cancelComposition() {
+ replace(compositionStart, compositionEnd, "")
+ compositionStart = NOWHERE
+ compositionEnd = NOWHERE
+ }
+
+ /**
+ * Commits the ongoing composition text and reset the composition range.
+ */
+ fun commitComposition() {
+ compositionStart = NOWHERE
+ compositionEnd = NOWHERE
+ }
+
+ override fun toString(): String = gapBuffer.toString()
+
+ fun toAnnotatedString(): AnnotatedString = AnnotatedString(toString())
+}
+
+/**
+ * Returns the updated TextRange for [target] after the [deleted] TextRange is deleted as a Pair.
+ *
+ * If the [deleted] Range covers the whole target, Pair(-1,-1) is returned.
+ */
+/*@VisibleForTesting*/
+internal fun updateRangeAfterDelete(target: TextRange, deleted: TextRange): TextRange {
+ var targetMin = target.min
+ var targetMax = target.max
+
+ // Following figure shows the deletion range and composition range.
+ // |---| represents deleted range.
+ // |===| represents target range.
+ if (deleted.intersects(target)) {
+ if (deleted.contains(target)) {
+ // Input:
+ // Buffer : ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ // Deleted : |-------------|
+ // Target : |======|
+ //
+ // Result:
+ // Buffer : ABCDETUVWXYZ
+ // Target :
+ targetMin = deleted.min
+ targetMax = targetMin
+ } else if (target.contains(deleted)) {
+ // Input:
+ // Buffer : ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ // Deleted : |------|
+ // Target : |==========|
+ //
+ // Result:
+ // Buffer : ABCDEFGHIQRSTUVWXYZ
+ // Target : |===|
+ targetMax -= deleted.length
+ } else if (deleted.contains(targetMin)) {
+ // Input:
+ // Buffer : ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ // Deleted : |---------|
+ // Target : |========|
+ //
+ // Result:
+ // Buffer : ABCDEFPQRSTUVWXYZ
+ // Target : |=====|
+ targetMin = deleted.min
+ targetMax -= deleted.length
+ } else { // deleteRange contains myMax
+ // Input:
+ // Buffer : ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ // Deleted : |---------|
+ // Target : |=======|
+ //
+ // Result:
+ // Buffer : ABCDEFGHSTUVWXYZ
+ // Target : |====|
+ targetMax = deleted.min
+ }
+ } else {
+ if (targetMax <= deleted.min) {
+ // Input:
+ // Buffer : ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ // Deleted : |-------|
+ // Target : |=======|
+ //
+ // Result:
+ // Buffer : ABCDEFGHIJKLTUVWXYZ
+ // Target : |=======|
+ // do nothing
+ } else {
+ // Input:
+ // Buffer : ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ // Deleted : |-------|
+ // Target : |=======|
+ //
+ // Result:
+ // Buffer : AJKLMNOPQRSTUVWXYZ
+ // Target : |=======|
+ targetMin -= deleted.length
+ targetMax -= deleted.length
+ }
+ }
+
+ return TextRange(targetMin, targetMax)
+}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/GapBuffer.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/GapBuffer.kt
new file mode 100644
index 0000000..9527b3f
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/GapBuffer.kt
@@ -0,0 +1,338 @@
+/*
+ * 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.input.internal
+
+/**
+ * Like [toCharArray] but copies the entire source string.
+ * Workaround for compiler error when giving [toCharArray] above default parameters.
+ */
+private fun String.toCharArray(
+ destination: CharArray,
+ destinationOffset: Int
+) = toCharArray(destination, destinationOffset, startIndex = 0, endIndex = this.length)
+
+/**
+ * Copies characters from this [String] into [destination].
+ *
+ * Platform-specific implementations should use native functions for performing this operation if
+ * they exist, since they will likely be more efficient than copying each character individually.
+ *
+ * @param destination The [CharArray] to copy into.
+ * @param destinationOffset The index in [destination] to start copying to.
+ * @param startIndex The index in `this` of the first character to copy from (inclusive).
+ * @param endIndex The index in `this` of the last character to copy from (exclusive).
+ */
+// TODO(halilibo): Revert back to expect/actual when moving to foundation
+internal fun String.toCharArray(
+ destination: CharArray,
+ destinationOffset: Int,
+ startIndex: Int,
+ endIndex: Int
+) {
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
+ (this as java.lang.String).getChars(startIndex, endIndex, destination, destinationOffset)
+}
+
+/**
+ * The gap buffer implementation
+ *
+ * @param initBuffer An initial buffer. This class takes ownership of this object, so do not modify
+ * array after passing to this constructor
+ * @param initGapStart An initial inclusive gap start offset of the buffer
+ * @param initGapEnd An initial exclusive gap end offset of the buffer
+ */
+private class GapBuffer(initBuffer: CharArray, initGapStart: Int, initGapEnd: Int) {
+
+ /**
+ * The current capacity of the buffer
+ */
+ private var capacity = initBuffer.size
+
+ /**
+ * The buffer
+ */
+ private var buffer = initBuffer
+
+ /**
+ * The inclusive start offset of the gap
+ */
+ private var gapStart = initGapStart
+
+ /**
+ * The exclusive end offset of the gap
+ */
+ private var gapEnd = initGapEnd
+
+ /**
+ * The length of the gap.
+ */
+ private fun gapLength(): Int = gapEnd - gapStart
+
+ /**
+ * [] operator for the character at the index.
+ */
+ operator fun get(index: Int): Char {
+ if (index < gapStart) {
+ return buffer[index]
+ } else {
+ return buffer[index - gapStart + gapEnd]
+ }
+ }
+
+ /**
+ * Check if the gap has a requested size, and allocate new buffer if there is enough space.
+ */
+ private fun makeSureAvailableSpace(requestSize: Int) {
+ if (requestSize <= gapLength()) {
+ return
+ }
+
+ // Allocating necessary memory space by doubling the array size.
+ val necessarySpace = requestSize - gapLength()
+ var newCapacity = capacity * 2
+ while ((newCapacity - capacity) < necessarySpace) {
+ newCapacity *= 2
+ }
+
+ val newBuffer = CharArray(newCapacity)
+ buffer.copyInto(newBuffer, 0, 0, gapStart)
+ val tailLength = capacity - gapEnd
+ val newEnd = newCapacity - tailLength
+ buffer.copyInto(newBuffer, newEnd, gapEnd, gapEnd + tailLength)
+
+ buffer = newBuffer
+ capacity = newCapacity
+ gapEnd = newEnd
+ }
+
+ /**
+ * Delete the given range of the text.
+ */
+ private fun delete(start: Int, end: Int) {
+ if (start < gapStart && end <= gapStart) {
+ // The remove happens in the head buffer. Copy the tail part of the head buffer to the
+ // tail buffer.
+ //
+ // Example:
+ // Input:
+ // buffer: ABCDEFGHIJKLMNOPQ*************RSTUVWXYZ
+ // del region: |-----|
+ //
+ // First, move the remaining part of the head buffer to the tail buffer.
+ // buffer: ABCDEFGHIJKLMNOPQ*****KLKMNOPQRSTUVWXYZ
+ // move data: ^^^^^^^ => ^^^^^^^^
+ //
+ // Then, delete the given range. (just updating gap positions)
+ // buffer: ABCD******************KLKMNOPQRSTUVWXYZ
+ // del region: |-----|
+ //
+ // Output: ABCD******************KLKMNOPQRSTUVWXYZ
+ val copyLen = gapStart - end
+ buffer.copyInto(buffer, gapEnd - copyLen, end, gapStart)
+ gapStart = start
+ gapEnd -= copyLen
+ } else if (start < gapStart && end >= gapStart) {
+ // The remove happens with accrossing the gap region. Just update the gap position
+ //
+ // Example:
+ // Input:
+ // buffer: ABCDEFGHIJKLMNOPQ************RSTUVWXYZ
+ // del region: |-------------------|
+ //
+ // Output: ABCDEFGHIJKL********************UVWXYZ
+ gapEnd = end + gapLength()
+ gapStart = start
+ } else { // start > gapStart && end > gapStart
+ // The remove happens in the tail buffer. Copy the head part of the tail buffer to the
+ // head buffer.
+ //
+ // Example:
+ // Input:
+ // buffer: ABCDEFGHIJKL************MNOPQRSTUVWXYZ
+ // del region: |-----|
+ //
+ // First, move the remaining part in the tail buffer to the head buffer.
+ // buffer: ABCDEFGHIJKLMNO*********MNOPQRSTUVWXYZ
+ // move dat: ^^^ <= ^^^
+ //
+ // Then, delete the given range. (just updating gap positions)
+ // buffer: ABCDEFGHIJKLMNO******************VWXYZ
+ // del region: |-----|
+ //
+ // Output: ABCDEFGHIJKLMNO******************VWXYZ
+ val startInBuffer = start + gapLength()
+ val endInBuffer = end + gapLength()
+ val copyLen = startInBuffer - gapEnd
+ buffer.copyInto(buffer, gapStart, gapEnd, startInBuffer)
+ gapStart += copyLen
+ gapEnd = endInBuffer
+ }
+ }
+
+ /**
+ * Replace the certain region of text with given text
+ *
+ * @param start an inclusive start offset for replacement.
+ * @param end an exclusive end offset for replacement
+ * @param text a text to replace
+ */
+ fun replace(start: Int, end: Int, text: String) {
+ makeSureAvailableSpace(text.length - (end - start))
+
+ delete(start, end)
+
+ text.toCharArray(buffer, gapStart)
+ gapStart += text.length
+ }
+
+ /**
+ * Write the current text into outBuf.
+ * @param builder The output string builder
+ */
+ fun append(builder: StringBuilder) {
+ builder.append(buffer, 0, gapStart)
+ builder.append(buffer, gapEnd, capacity - gapEnd)
+ }
+
+ /**
+ * The lengh of this gap buffer.
+ *
+ * This doesn't include internal hidden gap length.
+ */
+ fun length() = capacity - gapLength()
+
+ override fun toString(): String = StringBuilder().apply { append(this) }.toString()
+}
+
+/**
+ * An editing buffer that uses Gap Buffer only around the cursor location.
+ *
+ * Different from the original gap buffer, this gap buffer doesn't convert all given text into
+ * mutable buffer. Instead, this gap buffer converts cursor around text into mutable gap buffer
+ * for saving construction time and memory space. If text modification outside of the gap buffer
+ * is requested, this class flush the buffer and create new String, then start new gap buffer.
+ *
+ * @param text The initial text
+ * @suppress
+ */
+internal class PartialGapBuffer(var text: String) {
+ internal companion object {
+ const val BUF_SIZE = 255
+ const val SURROUNDING_SIZE = 64
+ const val NOWHERE = -1
+ }
+
+ private var buffer: GapBuffer? = null
+ private var bufStart = NOWHERE
+ private var bufEnd = NOWHERE
+
+ /**
+ * The text length
+ */
+ val length: Int
+ get() {
+ val buffer = buffer ?: return text.length
+ return text.length - (bufEnd - bufStart) + buffer.length()
+ }
+
+ /**
+ * Replace the certain region of text with given text
+ *
+ * @param start an inclusive start offset for replacement.
+ * @param end an exclusive end offset for replacement
+ * @param text a text to replace
+ */
+ fun replace(start: Int, end: Int, text: String) {
+ require(start <= end) {
+ "start index must be less than or equal to end index: $start > $end"
+ }
+ require(start >= 0) {
+ "start must be non-negative, but was $start"
+ }
+
+ val buffer = buffer
+ if (buffer == null) { // First time to create gap buffer
+ val charArray = CharArray(maxOf(BUF_SIZE, text.length + 2 * SURROUNDING_SIZE))
+
+ // Convert surrounding text into buffer.
+ val leftCopyCount = minOf(start, SURROUNDING_SIZE)
+ val rightCopyCount = minOf(this.text.length - end, SURROUNDING_SIZE)
+
+ // Copy left surrounding
+ this.text.toCharArray(charArray, 0, start - leftCopyCount, start)
+
+ // Copy right surrounding
+ this.text.toCharArray(
+ charArray,
+ charArray.size - rightCopyCount,
+ end,
+ end + rightCopyCount
+ )
+
+ // Copy given text into buffer
+ text.toCharArray(charArray, leftCopyCount)
+
+ this.buffer = GapBuffer(
+ charArray,
+ initGapStart = leftCopyCount + text.length,
+ initGapEnd = charArray.size - rightCopyCount
+ )
+ bufStart = start - leftCopyCount
+ bufEnd = end + rightCopyCount
+ return
+ }
+
+ // Convert user space offset into buffer space offset
+ val bufferStart = start - bufStart
+ val bufferEnd = end - bufStart
+ if (bufferStart < 0 || bufferEnd > buffer.length()) {
+ // Text modification outside of gap buffer has requested. Flush the buffer and try it
+ // again.
+ this.text = toString()
+ this.buffer = null
+ bufStart = NOWHERE
+ bufEnd = NOWHERE
+ return replace(start, end, text)
+ }
+
+ buffer.replace(bufferStart, bufferEnd, text)
+ }
+
+ /**
+ * [] operator for the character at the index.
+ */
+ operator fun get(index: Int): Char {
+ val buffer = buffer ?: return text[index]
+ if (index < bufStart) {
+ return text[index]
+ }
+ val gapBufLength = buffer.length()
+ if (index < gapBufLength + bufStart) {
+ return buffer[index - bufStart]
+ }
+ return text[index - (gapBufLength - bufEnd + bufStart)]
+ }
+
+ override fun toString(): String {
+ val b = buffer ?: return text
+ val sb = StringBuilder()
+ sb.append(text, 0, bufStart)
+ b.append(sb)
+ sb.append(text, bufEnd, text.length)
+ return sb.toString()
+ }
+}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/MathUtils.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/MathUtils.kt
new file mode 100644
index 0000000..ee35949
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/MathUtils.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.input.internal
+
+/**
+ * Adds [this] and [right], and if an overflow occurs returns result of [defaultValue].
+ */
+internal inline fun Int.addExactOrElse(right: Int, defaultValue: () -> Int): Int {
+ val result = this + right
+ // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+ return if (this xor result and (right xor result) < 0) defaultValue() else result
+}
+
+/**
+ * Subtracts [right] from [this], and if an overflow occurs returns result of [defaultValue].
+ */
+internal fun Int.subtractExactOrElse(right: Int, defaultValue: () -> Int): Int {
+ val result = this - right
+ // HD 2-12 Overflow iff the arguments have different signs and
+ // the sign of the result is different from the sign of x
+ return if (this xor right and (this xor result) < 0) defaultValue() else result
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnection.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnection.kt
new file mode 100644
index 0000000..c2e492c
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnection.kt
@@ -0,0 +1,414 @@
+/*
+ * 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.input.internal
+
+import android.os.Bundle
+import android.os.Handler
+import android.text.TextUtils
+import android.util.Log
+import android.view.KeyEvent
+import android.view.inputmethod.CompletionInfo
+import android.view.inputmethod.CorrectionInfo
+import android.view.inputmethod.EditorInfo
+import android.view.inputmethod.ExtractedText
+import android.view.inputmethod.ExtractedTextRequest
+import android.view.inputmethod.InputConnection
+import android.view.inputmethod.InputContentInfo
+import androidx.annotation.VisibleForTesting
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.TextFieldValue
+import kotlin.math.max
+import kotlin.math.min
+
+@VisibleForTesting
+internal const val SIC_DEBUG = false
+private const val TAG = "StatelessIC"
+private const val DEBUG_CLASS = "StatelessInputConnection"
+
+private val EmptyTextFieldValue = TextFieldValue()
+
+/**
+ * An input connection that delegates its reads and writes to the active text input session in
+ * [AndroidTextInputAdapter]. InputConnections are requested and used by framework to create bridge
+ * from IME to an active editor.
+ */
+@OptIn(ExperimentalFoundationApi::class)
+internal class StatelessInputConnection(
+ private val activeSessionProvider: () -> EditableTextInputSession?
+) : InputConnection {
+ /**
+ * The depth of the batch session. 0 means no session.
+ *
+ * Sometimes InputConnection does not call begin/endBatchEdit functions before calling other
+ * edit functions like commitText or setComposingText. StatelessInputConnection starts and
+ * finishes a new artificial batch for every EditCommand to make sure that there is always
+ * an ongoing batch. EditCommands are only applied when batchDepth reaches 0.
+ */
+ private var batchDepth: Int = 0
+
+ /**
+ * The input state from the currently active [TextInputSession] in
+ * [AndroidTextInputAdapter]. Returns null if there is no active session.
+ */
+ private val valueOrNull: TextFieldCharSequence?
+ get() = activeSessionProvider()?.value
+
+ /**
+ * The input state from the currently active [TextInputSession] in
+ * [AndroidTextInputAdapter]. Returns empty TextFieldValue if there is no active session.
+ */
+ private val value: TextFieldCharSequence
+ get() = valueOrNull ?: TextFieldCharSequence()
+
+ /**
+ * Recording of editing operations for batch editing
+ */
+ private val editCommands = mutableListOf<EditCommand>()
+
+ /**
+ * If this InputConnection itself is active. This value becomes false only if [closeConnection]
+ * gets called.
+ */
+ private var isICActive: Boolean = true
+
+ /**
+ * Returns whether this input connection is still active and also executes the given lambda if
+ * it is active.
+ */
+ private inline fun ensureActive(block: () -> Unit): Boolean {
+ val combinedActive = isICActive && activeSessionProvider() != null
+ return combinedActive.also {
+ if (it) {
+ block()
+ }
+ }
+ }
+
+ /**
+ * Add edit op to internal list with wrapping batch edit. It's not guaranteed by IME that
+ * batch editing will be used for every operation. Instead, [StatelessInputConnection] creates
+ * its own mini batches for every edit op. These batches are only applied when batch depth
+ * reaches 0, meaning that artificial batches won't be applied until the real batches are
+ * completed.
+ */
+ private fun addEditCommandWithBatch(editCommand: EditCommand) {
+ beginBatchEditInternal()
+ try {
+ editCommands.add(editCommand)
+ } finally {
+ endBatchEditInternal()
+ }
+ }
+
+ // region Methods for batch editing and session control
+ override fun beginBatchEdit(): Boolean = ensureActive {
+ logDebug("beginBatchEdit()")
+ return beginBatchEditInternal()
+ }
+
+ private fun beginBatchEditInternal(): Boolean {
+ batchDepth++
+ return true
+ }
+
+ override fun endBatchEdit(): Boolean {
+ logDebug("endBatchEdit()")
+ return endBatchEditInternal()
+ }
+
+ private fun endBatchEditInternal(): Boolean {
+ batchDepth--
+ if (batchDepth == 0 && editCommands.isNotEmpty()) {
+ // apply the changes to active input session.
+ activeSessionProvider()?.requestEdits(editCommands.toMutableList())
+ editCommands.clear()
+ }
+ return batchDepth > 0
+ }
+
+ override fun closeConnection() {
+ logDebug("closeConnection()")
+ editCommands.clear()
+ batchDepth = 0
+ isICActive = false
+ }
+
+ //endregion
+
+ // region Callbacks for text editing
+
+ override fun commitText(text: CharSequence?, newCursorPosition: Int): Boolean = ensureActive {
+ logDebug("commitText(\"$text\", $newCursorPosition)")
+ addEditCommandWithBatch(CommitTextCommand(text.toString(), newCursorPosition))
+ }
+
+ override fun setComposingRegion(start: Int, end: Int): Boolean = ensureActive {
+ logDebug("setComposingRegion($start, $end)")
+ addEditCommandWithBatch(SetComposingRegionCommand(start, end))
+ }
+
+ override fun setComposingText(text: CharSequence?, newCursorPosition: Int): Boolean =
+ ensureActive {
+ logDebug("setComposingText(\"$text\", $newCursorPosition)")
+ addEditCommandWithBatch(SetComposingTextCommand(text.toString(), newCursorPosition))
+ }
+
+ override fun deleteSurroundingTextInCodePoints(beforeLength: Int, afterLength: Int): Boolean =
+ ensureActive {
+ logDebug("deleteSurroundingTextInCodePoints($beforeLength, $afterLength)")
+ addEditCommandWithBatch(
+ DeleteSurroundingTextInCodePointsCommand(beforeLength, afterLength)
+ )
+ return true
+ }
+
+ override fun deleteSurroundingText(beforeLength: Int, afterLength: Int): Boolean =
+ ensureActive {
+ logDebug("deleteSurroundingText($beforeLength, $afterLength)")
+ addEditCommandWithBatch(DeleteSurroundingTextCommand(beforeLength, afterLength))
+ return true
+ }
+
+ override fun setSelection(start: Int, end: Int): Boolean = ensureActive {
+ logDebug("setSelection($start, $end)")
+ addEditCommandWithBatch(SetSelectionCommand(start, end))
+ return true
+ }
+
+ override fun finishComposingText(): Boolean = ensureActive {
+ logDebug("finishComposingText()")
+ addEditCommandWithBatch(FinishComposingTextCommand)
+ return true
+ }
+
+ override fun sendKeyEvent(event: KeyEvent): Boolean = ensureActive {
+ logDebug("sendKeyEvent($event)")
+ activeSessionProvider()?.sendKeyEvent(event)
+ return true
+ }
+
+ // endregion
+
+ // region Callbacks for retrieving editing buffer info by IME
+
+ override fun getTextBeforeCursor(maxChars: Int, flags: Int): CharSequence {
+ // TODO(b/135556699) should return styled text
+ val result = value.getTextBeforeSelection(maxChars).toString()
+ logDebug("getTextBeforeCursor($maxChars, $flags): $result")
+ return result
+ }
+
+ override fun getTextAfterCursor(maxChars: Int, flags: Int): CharSequence {
+ // TODO(b/135556699) should return styled text
+ val result = value.getTextAfterSelection(maxChars).toString()
+ logDebug("getTextAfterCursor($maxChars, $flags): $result")
+ return result
+ }
+
+ override fun getSelectedText(flags: Int): CharSequence? {
+ // https://source.chromium.org/chromium/chromium/src/+/master:content/public/android/java/src/org/chromium/content/browser/input/TextInputState.java;l=56;drc=0e20d1eb38227949805a4c0e9d5cdeddc8d23637
+ val result: CharSequence? = if (value.selectionInChars.collapsed) {
+ null
+ } else {
+ // TODO(b/135556699) should return styled text
+ value.getSelectedText().toString()
+ }
+ logDebug("getSelectedText($flags): $result")
+ return result
+ }
+
+ override fun requestCursorUpdates(cursorUpdateMode: Int): Boolean = ensureActive {
+ logDebug("requestCursorUpdates($cursorUpdateMode)")
+ return false
+ }
+
+ override fun getExtractedText(request: ExtractedTextRequest?, flags: Int): ExtractedText {
+ logDebug("getExtractedText($request, $flags)")
+// extractedTextMonitorMode = (flags and InputConnection.GET_EXTRACTED_TEXT_MONITOR) != 0
+// if (extractedTextMonitorMode) {
+// currentExtractedTextRequestToken = request?.token ?: 0
+// }
+ // TODO(halilibo): Implement extracted text monitor
+ // TODO(b/135556699) should return styled text
+ return value.toExtractedText()
+ }
+
+ override fun getCursorCapsMode(reqModes: Int): Int {
+ logDebug("getCursorCapsMode($reqModes)")
+ return TextUtils.getCapsMode(value, value.selectionInChars.min, reqModes)
+ }
+
+ // endregion
+
+ // region Editor action and Key events.
+
+ override fun performContextMenuAction(id: Int): Boolean = ensureActive {
+ logDebug("performContextMenuAction($id)")
+ when (id) {
+ android.R.id.selectAll -> {
+ addEditCommandWithBatch(SetSelectionCommand(0, value.length))
+ }
+ // TODO(siyamed): Need proper connection to cut/copy/paste
+ android.R.id.cut -> sendSynthesizedKeyEvent(KeyEvent.KEYCODE_CUT)
+ android.R.id.copy -> sendSynthesizedKeyEvent(KeyEvent.KEYCODE_COPY)
+ android.R.id.paste -> sendSynthesizedKeyEvent(KeyEvent.KEYCODE_PASTE)
+ android.R.id.startSelectingText -> {} // not supported
+ android.R.id.stopSelectingText -> {} // not supported
+ android.R.id.copyUrl -> {} // not supported
+ android.R.id.switchInputMethod -> {} // not supported
+ else -> {
+ // not supported
+ }
+ }
+ return false
+ }
+
+ private fun sendSynthesizedKeyEvent(code: Int) {
+ sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, code))
+ sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP, code))
+ }
+
+ override fun performEditorAction(editorAction: Int): Boolean = ensureActive {
+ logDebug("performEditorAction($editorAction)")
+
+ val imeAction = when (editorAction) {
+ EditorInfo.IME_ACTION_UNSPECIFIED -> ImeAction.Default
+ EditorInfo.IME_ACTION_DONE -> ImeAction.Done
+ EditorInfo.IME_ACTION_SEND -> ImeAction.Send
+ EditorInfo.IME_ACTION_SEARCH -> ImeAction.Search
+ EditorInfo.IME_ACTION_PREVIOUS -> ImeAction.Previous
+ EditorInfo.IME_ACTION_NEXT -> ImeAction.Next
+ EditorInfo.IME_ACTION_GO -> ImeAction.Go
+ else -> {
+ logDebug("IME sent an unrecognized editor action: $editorAction")
+ ImeAction.Default
+ }
+ }
+
+ activeSessionProvider()?.onImeAction(imeAction)
+ return true
+ }
+
+ // endregion
+
+ // region Unsupported callbacks
+
+ override fun commitCompletion(text: CompletionInfo?): Boolean {
+ logDebug("commitCompletion(${text?.text})")
+ // We don't support this callback.
+ // The API documents says this should return if the input connection is no longer valid, but
+ // The Chromium implementation already returning false, so assuming it is safe to return
+ // false if not supported.
+ // see https://cs.chromium.org/chromium/src/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java
+ return false
+ }
+
+ override fun commitCorrection(correctionInfo: CorrectionInfo?): Boolean {
+ // logDebug("commitCorrection($correctionInfo),autoCorrect:$autoCorrect")
+ // Should add an event here so that we can implement the autocorrect highlight
+ // Bug: 170647219
+ // TODO(halilibo): Implement autoCorrect from ImeOptions
+ return true
+ }
+
+ override fun getHandler(): Handler? {
+ logDebug("getHandler()")
+ return null // Returns null means using default Handler
+ }
+
+ override fun clearMetaKeyStates(states: Int): Boolean {
+ logDebug("clearMetaKeyStates($states)")
+ // We don't support this callback.
+ // The API documents says this should return if the input connection is no longer valid, but
+ // The Chromium implementation already returning false, so assuming it is safe to return
+ // false if not supported.
+ // see https://cs.chromium.org/chromium/src/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java
+ return false
+ }
+
+ override fun reportFullscreenMode(enabled: Boolean): Boolean {
+ logDebug("reportFullscreenMode($enabled)")
+ return false // This value is ignored according to the API docs.
+ }
+
+ override fun performPrivateCommand(action: String?, data: Bundle?): Boolean = ensureActive {
+ logDebug("performPrivateCommand($action, $data)")
+ return true // API doc says we should return true even if we didn't understand the command.
+ }
+
+ override fun commitContent(
+ inputContentInfo: InputContentInfo,
+ flags: Int,
+ opts: Bundle?
+ ): Boolean = ensureActive {
+ logDebug("commitContent($inputContentInfo, $flags, $opts)")
+ // TODO(halilibo): Support commit content in BasicTextField2
+ return false
+ }
+
+ // endregion
+
+ /**
+ * Returns the text before the selection.
+ *
+ * @param maxChars maximum number of characters (inclusive) before the minimum value in
+ * [TextFieldCharSequence.selectionInChars].
+ *
+ * @see TextRange.min
+ */
+ fun TextFieldCharSequence.getTextBeforeSelection(maxChars: Int): CharSequence =
+ subSequence(max(0, selectionInChars.min - maxChars), selectionInChars.min)
+
+ /**
+ * Returns the text after the selection.
+ *
+ * @param maxChars maximum number of characters (exclusive) after the maximum value in
+ * [TextFieldCharSequence.selectionInChars].
+ *
+ * @see TextRange.max
+ */
+ fun TextFieldCharSequence.getTextAfterSelection(maxChars: Int): CharSequence =
+ subSequence(selectionInChars.max, min(selectionInChars.max + maxChars, length))
+
+ /**
+ * Returns the currently selected text.
+ */
+ fun TextFieldCharSequence.getSelectedText(): CharSequence =
+ subSequence(selectionInChars.min, selectionInChars.max)
+
+ private fun logDebug(message: String) {
+ if (SIC_DEBUG) {
+ Log.d(TAG, "$DEBUG_CLASS.$message, $isICActive, ${activeSessionProvider() != null}")
+ }
+ }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+private fun TextFieldCharSequence.toExtractedText(): ExtractedText {
+ val res = ExtractedText()
+ res.text = this
+ res.startOffset = 0
+ res.partialEndOffset = length
+ res.partialStartOffset = -1 // -1 means full text
+ res.selectionStart = selectionInChars.min
+ res.selectionEnd = selectionInChars.max
+ res.flags = if ('\n' in this) 0 else ExtractedText.FLAG_SINGLE_LINE
+ return res
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldCoreModifier.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldCoreModifier.kt
new file mode 100644
index 0000000..15ab3ed
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldCoreModifier.kt
@@ -0,0 +1,497 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.keyframes
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.ScrollState
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.scrollBy
+import androidx.compose.foundation.text.selection.LocalTextSelectionColors
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.runtime.snapshotFlow
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.MotionDurationScale
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.drawscope.ContentDrawScope
+import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
+import androidx.compose.ui.graphics.isUnspecified
+import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
+import androidx.compose.ui.node.DrawModifierNode
+import androidx.compose.ui.node.GlobalPositionAwareModifierNode
+import androidx.compose.ui.node.LayoutModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.currentValueOf
+import androidx.compose.ui.platform.InspectorInfo
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextPainter
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import kotlin.math.min
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+/**
+ * Modifier element for the core functionality of [BasicTextField2] that is passed as inner
+ * TextField to the decoration box. This is only half the actual modifiers for the field, the other
+ * half are only attached to the decorated text field.
+ *
+ * This modifier mostly handles layout and draw.
+ */
+@OptIn(ExperimentalFoundationApi::class)
+internal data class TextFieldCoreModifier(
+ private val isFocused: Boolean,
+ private val textLayoutState: TextLayoutState,
+ private val textFieldState: TextFieldState,
+ private val cursorBrush: Brush,
+ private val writeable: Boolean,
+ private val scrollState: ScrollState,
+ private val orientation: Orientation,
+) : ModifierNodeElement<TextFieldCoreModifierNode>() {
+
+ override fun create(): TextFieldCoreModifierNode = TextFieldCoreModifierNode(
+ isFocused = isFocused,
+ textLayoutState = textLayoutState,
+ textFieldState = textFieldState,
+ cursorBrush = cursorBrush,
+ writable = writeable,
+ scrollState = scrollState,
+ orientation = orientation,
+ )
+
+ override fun update(node: TextFieldCoreModifierNode) {
+ node.updateNode(
+ isFocused = isFocused,
+ textLayoutState = textLayoutState,
+ textFieldState = textFieldState,
+ cursorBrush = cursorBrush,
+ writeable = writeable,
+ scrollState = scrollState,
+ orientation = orientation,
+ )
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
+ // no inspector info
+ }
+}
+
+/** Modifier node for [TextFieldCoreModifier]. */
+@OptIn(ExperimentalFoundationApi::class)
+internal class TextFieldCoreModifierNode(
+ private var isFocused: Boolean,
+ private var textLayoutState: TextLayoutState,
+ private var textFieldState: TextFieldState,
+ private var cursorBrush: Brush,
+ private var writable: Boolean,
+ private var scrollState: ScrollState,
+ private var orientation: Orientation,
+) : Modifier.Node(),
+ LayoutModifierNode,
+ DrawModifierNode,
+ GlobalPositionAwareModifierNode,
+ CompositionLocalConsumerModifierNode {
+
+ /**
+ * Animatable object for cursor's alpha value. It becomes 1f for half a second and 0f for
+ * another half a second when TextField is focused and editable. Initial value should be 0f
+ * so that when cursor needs to be drawn for the first time, change to 1f invalidates draw.
+ */
+ private val cursorAlpha = Animatable(0f)
+
+ /**
+ * Whether to show cursor at all when TextField has focus. This depends on enabled, read only,
+ * and brush at a given time.
+ */
+ private val showCursor: Boolean
+ get() = writable && isFocused && cursorBrush.isSpecified
+
+ /**
+ * Observes the [textFieldState] for any changes to content or selection. If a change happens,
+ * cursor blink animation gets reset.
+ */
+ private var changeObserverJob: Job? = null
+
+ // TODO: kdoc
+ private var previousSelection: TextRange = TextRange.Zero
+ private var previousCursorRect: Rect = Rect.Zero
+
+ /**
+ * Updates all the related properties and invalidates internal state based on the changes.
+ */
+ fun updateNode(
+ isFocused: Boolean,
+ textLayoutState: TextLayoutState,
+ textFieldState: TextFieldState,
+ cursorBrush: Brush,
+ writeable: Boolean,
+ scrollState: ScrollState,
+ orientation: Orientation,
+ ) {
+ val wasFocused = this.isFocused
+ val previousTextFieldState = this.textFieldState
+
+ this.isFocused = isFocused
+ this.textLayoutState = textLayoutState
+ this.textFieldState = textFieldState
+ this.cursorBrush = cursorBrush
+ this.writable = writeable
+ this.scrollState = scrollState
+ this.orientation = orientation
+
+ if (!showCursor) {
+ changeObserverJob?.cancel()
+ changeObserverJob = null
+ coroutineScope.launch { cursorAlpha.snapTo(0f) }
+ } else if (!wasFocused || previousTextFieldState != textFieldState) {
+ // this node is writeable, focused and gained that focus just now.
+ // start the state value observation
+ changeObserverJob = coroutineScope.launch {
+ // Animate the cursor even when animations are disabled by the system.
+ withContext(FixedMotionDurationScale) {
+ snapshotFlow { textFieldState.text }
+ .collectLatest {
+ // ensure that the value is always 1f _this_ frame by calling snapTo
+ cursorAlpha.snapTo(1f)
+ // then start the cursor blinking on animation clock (500ms on to start)
+ cursorAlpha.animateTo(0f, cursorAnimationSpec)
+ }
+ }
+ }
+ }
+ }
+
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints
+ ) = if (orientation == Orientation.Vertical) {
+ measureVerticalScroll(measurable, constraints)
+ } else {
+ measureHorizontalScroll(measurable, constraints)
+ }
+
+ override fun ContentDrawScope.draw() {
+ drawContent()
+ val value = textFieldState.text
+ val textLayoutResult = textLayoutState.layoutResult ?: return
+
+ if (value.selectionInChars.collapsed) {
+ drawText(textLayoutResult)
+ drawCursor(value.selectionInChars, textLayoutResult)
+ } else {
+ drawSelection(value.selectionInChars, textLayoutResult)
+ drawText(textLayoutResult)
+ }
+ }
+
+ override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
+ textLayoutState.proxy?.innerTextFieldCoordinates = coordinates
+ }
+
+ private fun MeasureScope.measureVerticalScroll(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ val currSelection = textFieldState.text.selectionInChars
+ val offsetToFollow = when {
+ currSelection.start != previousSelection.start -> currSelection.start
+ currSelection.end != previousSelection.end -> currSelection.end
+ else -> currSelection.min
+ }
+ previousSelection = currSelection
+
+ // remove any height constraints for TextField since it'll be able to scroll vertically.
+ val childConstraints = constraints.copy(maxHeight = Constraints.Infinity)
+ val placeable = measurable.measure(childConstraints)
+ // final height is the minimum of calculated or constrained maximum height.
+ val height = min(placeable.height, constraints.maxHeight)
+
+ return layout(placeable.width, height) {
+ // we may need to update the scroll state to bring the cursor back into view after
+ // layout is completed
+ updateScrollState(
+ cursorRect = getCursorRectInScroller(
+ cursorOffset = offsetToFollow,
+ textLayoutResult = textLayoutState.layoutResult,
+ rtl = layoutDirection == LayoutDirection.Rtl,
+ textFieldWidth = placeable.width
+ ),
+ containerSize = height,
+ textFieldSize = placeable.height
+ )
+
+ placeable.placeRelative(0, -scrollState.value)
+ }
+ }
+
+ private fun MeasureScope.measureHorizontalScroll(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ val value = textFieldState.text
+ val offsetToFollow = when {
+ value.selectionInChars.start != previousSelection.start -> value.selectionInChars.start
+ value.selectionInChars.end != previousSelection.end -> value.selectionInChars.end
+ else -> value.selectionInChars.min
+ }
+ previousSelection = value.selectionInChars
+
+ // If the maxIntrinsicWidth of the children is already smaller than the constraint, pass
+ // the original constraints so that the children has more information to determine its
+ // size.
+ val maxIntrinsicWidth = measurable.maxIntrinsicWidth(constraints.maxHeight)
+
+ // remove any width constraints for TextField since it'll be able to scroll horizontally.
+ val childConstraints = if (maxIntrinsicWidth < constraints.maxWidth) {
+ constraints
+ } else {
+ constraints.copy(maxWidth = Constraints.Infinity)
+ }
+ val placeable = measurable.measure(childConstraints)
+ val width = min(placeable.width, constraints.maxWidth)
+
+ return layout(width, placeable.height) {
+ // we may need to update the scroll state to bring the cursor back into view before
+ // layout is updated.
+ updateScrollState(
+ cursorRect = getCursorRectInScroller(
+ cursorOffset = offsetToFollow,
+ textLayoutResult = textLayoutState.layoutResult,
+ rtl = layoutDirection == LayoutDirection.Rtl,
+ textFieldWidth = placeable.width
+ ),
+ containerSize = width,
+ textFieldSize = placeable.width
+ )
+
+ placeable.placeRelative(-scrollState.value, 0)
+ }
+ }
+
+ /**
+ * Updates the scroll state to make sure cursor is visible after text content, selection, or
+ * layout changes. Only scroll changes won't trigger this.
+ *
+ * @param cursorRect Rectangle area to bring into view
+ * @param containerSize Either height or width of scrollable host, depending on scroll
+ * orientation
+ * @param textFieldSize Either height or width of scrollable text field content, depending on
+ * scroll orientation
+ */
+ private fun updateScrollState(
+ cursorRect: Rect,
+ containerSize: Int,
+ textFieldSize: Int,
+ ) {
+ // update the maximum scroll value
+ val difference = textFieldSize - containerSize
+ scrollState.maxValue = difference
+
+ // if cursor is not showing, we don't have to update the state for cursor
+ if (!showCursor) return
+
+ // Check if cursor has actually changed its location
+ if (cursorRect.left != previousCursorRect.left ||
+ cursorRect.top != previousCursorRect.top) {
+ val vertical = orientation == Orientation.Vertical
+ val cursorStart = if (vertical) cursorRect.top else cursorRect.left
+ val cursorEnd = if (vertical) cursorRect.bottom else cursorRect.right
+
+ val startVisibleBound = scrollState.value
+ val endVisibleBound = startVisibleBound + containerSize
+ val offsetDifference = when {
+ // make bottom/end of the cursor visible
+ //
+ // text box
+ // +----------------------+
+ // | |
+ // | |
+ // | cursor |
+ // | | |
+ // +-------------|--------+
+ // |
+ //
+ cursorEnd > endVisibleBound -> cursorEnd - endVisibleBound
+
+ // in rare cases when there's not enough space to fit the whole cursor, prioritise
+ // the bottom/end of the cursor
+ //
+ // cursor
+ // text box |
+ // +-------------|--------+
+ // | | |
+ // +-------------|--------+
+ // |
+ //
+ cursorStart < startVisibleBound && cursorEnd - cursorStart > containerSize ->
+ cursorEnd - endVisibleBound
+
+ // make top/start of the cursor visible if there's enough space to fit the whole
+ // cursor
+ //
+ // cursor
+ // text box |
+ // +--------------|-------+
+ // | | |
+ // | |
+ // | |
+ // | |
+ // +----------------------+
+ //
+ cursorStart < startVisibleBound && cursorEnd - cursorStart <= containerSize ->
+ cursorStart - startVisibleBound
+
+ // otherwise keep current offset
+ else -> 0f
+ }
+ previousCursorRect = cursorRect
+ coroutineScope.launch {
+ // this call will respect the earlier set maxValue
+ // no need to coerce again.
+ scrollState.scrollBy(offsetDifference)
+ }
+ }
+ }
+
+ /**
+ * Draws the selection highlight.
+ */
+ private fun DrawScope.drawSelection(
+ selection: TextRange,
+ textLayoutResult: TextLayoutResult
+ ) {
+ val start = selection.min
+ val end = selection.max
+ if (start != end) {
+ val selectionBackgroundColor = currentValueOf(LocalTextSelectionColors)
+ .backgroundColor
+ val selectionPath = textLayoutResult.getPathForRange(start, end)
+ drawPath(selectionPath, color = selectionBackgroundColor)
+ }
+ }
+
+ /**
+ * Draws the text content.
+ */
+ private fun DrawScope.drawText(textLayoutResult: TextLayoutResult) {
+ drawIntoCanvas { canvas ->
+ TextPainter.paint(canvas, textLayoutResult)
+ }
+ }
+
+ /**
+ * Draws the cursor indicator. Do not confuse it with cursor handle which is a popup that
+ * carries the cursor movement gestures.
+ */
+ private fun DrawScope.drawCursor(
+ selection: TextRange,
+ textLayoutResult: TextLayoutResult
+ ) {
+ // Only draw cursor if it can be shown and its alpha is higher than 0f
+ // Alpha is checked before showCursor purposefully to make sure that we read
+ // cursorAlpha.value in draw phase. So, when the alpha value changes, draw phase
+ // invalidates.
+ if (cursorAlpha.value <= 0f || !showCursor) return
+
+ val cursorAlphaValue = cursorAlpha.value.coerceIn(0f, 1f)
+ if (cursorAlphaValue == 0f) return
+
+ val cursorRect = textLayoutResult.getCursorRect(selection.start)
+ val cursorWidth = DefaultCursorThickness.toPx()
+ val cursorX = (cursorRect.left + cursorWidth / 2)
+ .coerceAtMost(size.width - cursorWidth / 2)
+
+ drawLine(
+ cursorBrush,
+ Offset(cursorX, cursorRect.top),
+ Offset(cursorX, cursorRect.bottom),
+ alpha = cursorAlphaValue,
+ strokeWidth = cursorWidth
+ )
+ }
+}
+
+private val cursorAnimationSpec: AnimationSpec<Float> = infiniteRepeatable(
+ animation = keyframes {
+ durationMillis = 1000
+ 1f at 0
+ 1f at 499
+ 0f at 500
+ 0f at 999
+ }
+)
+
+private val DefaultCursorThickness = 2.dp
+
+/**
+ * If brush has a specified color. It's possible that [SolidColor] contains [Color.Unspecified].
+ */
+private val Brush.isSpecified: Boolean
+ get() = !(this is SolidColor && this.value.isUnspecified)
+
+private object FixedMotionDurationScale : MotionDurationScale {
+ override val scaleFactor: Float
+ get() = 1f
+}
+
+/**
+ * Finds the rectangle area that corresponds to the visible cursor.
+ *
+ * @param cursorOffset Index of where cursor is at
+ * @param textLayoutResult Current text layout to look for cursor rect.
+ * @param rtl True if layout direction is RightToLeft
+ * @param textFieldWidth Total width of TextField composable
+ */
+private fun Density.getCursorRectInScroller(
+ cursorOffset: Int,
+ textLayoutResult: TextLayoutResult?,
+ rtl: Boolean,
+ textFieldWidth: Int
+): Rect {
+ val cursorRect = textLayoutResult?.getCursorRect(cursorOffset) ?: Rect.Zero
+ val thickness = DefaultCursorThickness.roundToPx()
+
+ val cursorLeft = if (rtl) {
+ textFieldWidth - cursorRect.left - thickness
+ } else {
+ cursorRect.left
+ }
+
+ val cursorRight = if (rtl) {
+ textFieldWidth - cursorRect.left
+ } else {
+ cursorRect.left + thickness
+ }
+ return cursorRect.copy(left = cursorLeft, right = cursorRight)
+}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldDecoratorModifier.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldDecoratorModifier.kt
new file mode 100644
index 0000000..9d45e4f
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldDecoratorModifier.kt
@@ -0,0 +1,419 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.gestures.detectTapAndPress
+import androidx.compose.foundation.text.KeyboardActionScope
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.foundation.text2.BasicTextField2
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.deselect
+import androidx.compose.ui.focus.FocusDirection
+import androidx.compose.ui.focus.FocusEventModifierNode
+import androidx.compose.ui.focus.FocusManager
+import androidx.compose.ui.focus.FocusRequesterModifierNode
+import androidx.compose.ui.focus.FocusState
+import androidx.compose.ui.focus.requestFocus
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.input.key.KeyInputModifierNode
+import androidx.compose.ui.input.pointer.PointerEvent
+import androidx.compose.ui.input.pointer.PointerEventPass
+import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
+import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
+import androidx.compose.ui.node.DelegatingNode
+import androidx.compose.ui.node.GlobalPositionAwareModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.PointerInputModifierNode
+import androidx.compose.ui.node.SemanticsModifierNode
+import androidx.compose.ui.node.currentValueOf
+import androidx.compose.ui.platform.InspectorInfo
+import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.semantics.SemanticsPropertyReceiver
+import androidx.compose.ui.semantics.disabled
+import androidx.compose.ui.semantics.editableText
+import androidx.compose.ui.semantics.getTextLayoutResult
+import androidx.compose.ui.semantics.insertTextAtCursor
+import androidx.compose.ui.semantics.onClick
+import androidx.compose.ui.semantics.onImeAction
+import androidx.compose.ui.semantics.setSelection
+import androidx.compose.ui.semantics.setText
+import androidx.compose.ui.semantics.textSelectionRange
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardCapitalization
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.unit.IntSize
+
+/**
+ * Modifier element for most of the functionality of [BasicTextField2] that is attached to the
+ * decoration box. This is only half the actual modifiers for the field, the other half are only
+ * attached to the internal text field.
+ *
+ * This modifier handles input events (both key and pointer), semantics, and focus.
+ */
+@OptIn(ExperimentalFoundationApi::class)
+internal data class TextFieldDecoratorModifier(
+ private val textFieldState: TextFieldState,
+ private val textLayoutState: TextLayoutState,
+ private val textInputAdapter: AndroidTextInputAdapter?,
+ private val filter: TextEditFilter?,
+ private val enabled: Boolean,
+ private val readOnly: Boolean,
+ private val keyboardOptions: KeyboardOptions,
+ private val keyboardActions: KeyboardActions,
+ private val singleLine: Boolean,
+) : ModifierNodeElement<TextFieldDecoratorModifierNode>() {
+ override fun create(): TextFieldDecoratorModifierNode = TextFieldDecoratorModifierNode(
+ textFieldState = textFieldState,
+ textLayoutState = textLayoutState,
+ textInputAdapter = textInputAdapter,
+ filter = filter,
+ enabled = enabled,
+ readOnly = readOnly,
+ keyboardOptions = keyboardOptions,
+ keyboardActions = keyboardActions,
+ singleLine = singleLine,
+ )
+
+ override fun update(node: TextFieldDecoratorModifierNode) {
+ node.updateNode(
+ textFieldState = textFieldState,
+ textLayoutState = textLayoutState,
+ textInputAdapter = textInputAdapter,
+ filter = filter,
+ enabled = enabled,
+ readOnly = readOnly,
+ keyboardOptions = keyboardOptions,
+ keyboardActions = keyboardActions,
+ singleLine = singleLine,
+ )
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
+ // Show nothing in the inspector.
+ }
+}
+
+/** Modifier node for [TextFieldDecoratorModifier]. */
+@OptIn(ExperimentalFoundationApi::class)
+internal class TextFieldDecoratorModifierNode(
+ var textFieldState: TextFieldState,
+ var textLayoutState: TextLayoutState,
+ var textInputAdapter: AndroidTextInputAdapter?,
+ var filter: TextEditFilter?,
+ var enabled: Boolean,
+ var readOnly: Boolean,
+ keyboardOptions: KeyboardOptions,
+ var keyboardActions: KeyboardActions,
+ var singleLine: Boolean,
+) : DelegatingNode(),
+ SemanticsModifierNode,
+ FocusRequesterModifierNode,
+ FocusEventModifierNode,
+ GlobalPositionAwareModifierNode,
+ PointerInputModifierNode,
+ KeyInputModifierNode,
+ CompositionLocalConsumerModifierNode {
+
+ private val pointerInputNode = delegate(SuspendingPointerInputModifierNode {
+ detectTapAndPress(onTap = {
+ if (!isFocused) {
+ requestFocus()
+ } else if (enabled && !readOnly) {
+ textInputSession?.showSoftwareKeyboard()
+ }
+ })
+ })
+
+ var keyboardOptions: KeyboardOptions = keyboardOptions.withDefaultsFrom(filter?.keyboardOptions)
+ private set
+
+ private var isFocused: Boolean = false
+ private var textInputSession: TextInputSession? = null
+
+ /**
+ * Manages key events. These events often are sourced by a hardware keyboard but it's also
+ * possible that IME or some other platform system simulates a KeyEvent.
+ */
+ private val textFieldKeyEventHandler = TextFieldKeyEventHandler().also {
+ it.setFilter(filter)
+ }
+
+ private val keyboardActionScope = object : KeyboardActionScope {
+ private val focusManager: FocusManager
+ get() = currentValueOf(LocalFocusManager)
+
+ override fun defaultKeyboardAction(imeAction: ImeAction) {
+ when (imeAction) {
+ ImeAction.Next -> {
+ focusManager.moveFocus(FocusDirection.Next)
+ }
+ ImeAction.Previous -> {
+ focusManager.moveFocus(FocusDirection.Previous)
+ }
+ ImeAction.Done -> {
+ textInputSession?.hideSoftwareKeyboard()
+ }
+ ImeAction.Go, ImeAction.Search, ImeAction.Send,
+ ImeAction.Default, ImeAction.None -> Unit
+ }
+ }
+ }
+
+ private val onImeActionPerformed: (ImeAction) -> Unit = { imeAction ->
+ val keyboardAction = when (imeAction) {
+ ImeAction.Done -> keyboardActions.onDone
+ ImeAction.Go -> keyboardActions.onGo
+ ImeAction.Next -> keyboardActions.onNext
+ ImeAction.Previous -> keyboardActions.onPrevious
+ ImeAction.Search -> keyboardActions.onSearch
+ ImeAction.Send -> keyboardActions.onSend
+ ImeAction.Default, ImeAction.None -> null
+ else -> error("invalid ImeAction")
+ }
+ keyboardAction?.invoke(keyboardActionScope)
+ ?: keyboardActionScope.defaultKeyboardAction(imeAction)
+ }
+
+ /**
+ * Updates all the related properties and invalidates internal state based on the changes.
+ */
+ fun updateNode(
+ textFieldState: TextFieldState,
+ textLayoutState: TextLayoutState,
+ textInputAdapter: AndroidTextInputAdapter?,
+ filter: TextEditFilter?,
+ enabled: Boolean,
+ readOnly: Boolean,
+ keyboardOptions: KeyboardOptions,
+ keyboardActions: KeyboardActions,
+ singleLine: Boolean,
+ ) {
+ // Find the diff: current previous and new values before updating current.
+ val previousWriteable = this.enabled && !this.readOnly
+ val writeable = enabled && !readOnly
+ val previousTextFieldState = this.textFieldState
+ val previousKeyboardOptions = this.keyboardOptions
+
+ // Apply the diff.
+ this.textFieldState = textFieldState
+ this.textLayoutState = textLayoutState
+ this.textInputAdapter = textInputAdapter
+ this.filter = filter
+ this.enabled = enabled
+ this.readOnly = readOnly
+ this.keyboardOptions = keyboardOptions.withDefaultsFrom(filter?.keyboardOptions)
+ this.keyboardActions = keyboardActions
+ this.singleLine = singleLine
+
+ // React to diff.
+ // If made writable while focused, or we got a completely new state instance,
+ // start a new input session.
+ if (writeable != previousWriteable ||
+ textFieldState != previousTextFieldState ||
+ keyboardOptions != previousKeyboardOptions
+ ) {
+ if (writeable && isFocused) {
+ // The old session will be implicitly disposed.
+ textInputSession = textInputAdapter?.startInputSession(
+ textFieldState,
+ this.keyboardOptions.toImeOptions(singleLine),
+ filter,
+ onImeActionPerformed
+ )
+ } else if (!writeable) {
+ // We were made read-only or disabled, hide the keyboard.
+ disposeInputSession()
+ }
+ }
+ textInputSession?.setFilter(filter)
+ textFieldKeyEventHandler.setFilter(filter)
+ }
+
+ override val shouldMergeDescendantSemantics: Boolean
+ get() = true
+
+ // This function is called inside a snapshot observer.
+ override fun SemanticsPropertyReceiver.applySemantics() {
+ val text = textFieldState.text
+ val selection = text.selectionInChars
+
+ getTextLayoutResult {
+ textLayoutState.layoutResult?.let { result -> it.add(result) } ?: false
+ }
+ editableText = AnnotatedString(text.toString())
+ textSelectionRange = selection
+ if (!enabled) disabled()
+
+ setText { newText ->
+ textFieldState.editProcessor.update(
+ listOf(
+ DeleteAllCommand,
+ CommitTextCommand(newText, 1)
+ ),
+ filter
+ )
+ true
+ }
+ setSelection { start, end, _ ->
+ // BasicTextField2 doesn't have VisualTransformation for the time being and
+ // probably won't have something that uses offsetMapping design. We can safely
+ // skip relativeToOriginalText flag. Assume it's always true.
+
+ if (!enabled) {
+ false
+ } else if (start == selection.start && end == selection.end) {
+ false
+ } else if (start.coerceAtMost(end) >= 0 &&
+ start.coerceAtLeast(end) <= text.length
+ ) {
+ // reset is required to make sure IME gets the update.
+ textFieldState.editProcessor.reset(
+ TextFieldCharSequence(
+ text = textFieldState.text,
+ selection = TextRange(start, end)
+ )
+ )
+ true
+ } else {
+ false
+ }
+ }
+ insertTextAtCursor { newText ->
+ textFieldState.editProcessor.update(
+ listOf(
+ // Finish composing text first because when the field is focused the IME
+ // might set composition.
+ FinishComposingTextCommand,
+ CommitTextCommand(newText, 1)
+ ),
+ filter
+ )
+ true
+ }
+ onImeAction(keyboardOptions.imeAction) {
+ onImeActionPerformed(keyboardOptions.imeAction)
+ true
+ }
+ onClick {
+ // according to the documentation, we still need to provide proper semantics actions
+ // even if the state is 'disabled'
+ if (!isFocused) {
+ requestFocus()
+ }
+ true
+ }
+ }
+
+ override fun onFocusEvent(focusState: FocusState) {
+ if (isFocused == focusState.isFocused) {
+ return
+ }
+ isFocused = focusState.isFocused
+
+ if (focusState.isFocused) {
+ textInputSession = textInputAdapter?.startInputSession(
+ textFieldState,
+ keyboardOptions.toImeOptions(singleLine),
+ filter,
+ onImeActionPerformed
+ )
+ // TODO(halilibo): bringIntoView
+ } else {
+ textFieldState.deselect()
+ }
+ }
+
+ override fun onDetach() {
+ if (isFocused) {
+ disposeInputSession()
+ }
+ }
+
+ override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
+ textLayoutState.proxy?.decorationBoxCoordinates = coordinates
+ }
+
+ override fun onPointerEvent(
+ pointerEvent: PointerEvent,
+ pass: PointerEventPass,
+ bounds: IntSize
+ ) {
+ pointerInputNode.onPointerEvent(pointerEvent, pass, bounds)
+ }
+
+ override fun onCancelPointerInput() {
+ pointerInputNode.onCancelPointerInput()
+ }
+
+ override fun onPreKeyEvent(event: KeyEvent): Boolean {
+ // TextField does not handle pre key events.
+ return false
+ }
+
+ override fun onKeyEvent(event: KeyEvent): Boolean {
+ return textFieldKeyEventHandler.onKeyEvent(
+ event = event,
+ state = textFieldState,
+ textLayoutState = textLayoutState,
+ editable = enabled && !readOnly,
+ singleLine = singleLine,
+ onSubmit = { onImeActionPerformed(keyboardOptions.imeAction) }
+ )
+ }
+
+ private fun disposeInputSession() {
+ textInputSession?.dispose()
+ textInputSession = null
+ }
+}
+
+/**
+ * Returns a [KeyboardOptions] that is merged with [defaults], with this object's values taking
+ * precedence.
+ */
+// TODO KeyboardOptions can't actually be merged correctly in all cases, because its properties
+// don't all have proper "unspecified" values. I think we can fix that in a backwards-compatible
+// way, but it will require adding new API outside of the text2 package so we should hold off on
+// making them until after the study.
+internal fun KeyboardOptions.withDefaultsFrom(defaults: KeyboardOptions?): KeyboardOptions {
+ if (defaults == null) return this
+ return KeyboardOptions(
+ capitalization = if (this.capitalization != KeyboardCapitalization.None) {
+ this.capitalization
+ } else {
+ defaults.capitalization
+ },
+ autoCorrect = this.autoCorrect && defaults.autoCorrect,
+ keyboardType = if (this.keyboardType != KeyboardType.Text) {
+ this.keyboardType
+ } else {
+ defaults.keyboardType
+ },
+ imeAction = if (this.imeAction != ImeAction.Default) {
+ this.imeAction
+ } else {
+ defaults.imeAction
+ }
+ )
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldKeyEventHandler.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldKeyEventHandler.kt
new file mode 100644
index 0000000..eacb620
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldKeyEventHandler.kt
@@ -0,0 +1,244 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.DeadKeyCombiner
+import androidx.compose.foundation.text.KeyCommand
+import androidx.compose.foundation.text.appendCodePointX
+import androidx.compose.foundation.text.isTypedEvent
+import androidx.compose.foundation.text.platformDefaultKeyMapping
+import androidx.compose.foundation.text.showCharacterPalette
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.internal.TextFieldPreparedSelection.Companion.NoCharacterFound
+import androidx.compose.foundation.text2.input.selectCharsIn
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.input.key.KeyEventType
+import androidx.compose.ui.input.key.type
+
+/**
+ * Handles KeyEvents coming to a BasicTextField. This is mostly to support hardware keyboard but
+ * any KeyEvent can also be sent by the IME or other platform systems.
+ */
+@OptIn(ExperimentalFoundationApi::class)
+internal class TextFieldKeyEventHandler {
+ private val preparedSelectionState = TextFieldPreparedSelectionState()
+ private val deadKeyCombiner = DeadKeyCombiner()
+ private val keyMapping = platformDefaultKeyMapping
+ private var filter: TextEditFilter? = null
+
+ fun setFilter(filter: TextEditFilter?) {
+ this.filter = filter
+ }
+
+ fun onKeyEvent(
+ event: KeyEvent,
+ state: TextFieldState,
+ textLayoutState: TextLayoutState,
+ editable: Boolean,
+ singleLine: Boolean,
+ onSubmit: () -> Unit
+ ): Boolean {
+ if (event.type != KeyEventType.KeyDown) {
+ return false
+ }
+ val editCommand = event.toTypedEditCommand()
+ if (editCommand != null) {
+ return if (editable) {
+ editCommand.applyOnto(state)
+ preparedSelectionState.resetCachedX()
+ true
+ } else {
+ false
+ }
+ }
+ val command = keyMapping.map(event)
+ if (command == null || (command.editsText && !editable)) {
+ return false
+ }
+ var consumed = true
+ preparedSelectionContext(state, textLayoutState) {
+ when (command) {
+ // TODO(halilibo): implement after selection is supported.
+ KeyCommand.COPY, // -> selectionManager.copy(false)
+ // TODO(siyamed): cut & paste will cause a reset input
+ KeyCommand.PASTE, // -> selectionManager.paste()
+ KeyCommand.CUT -> moveCursorRight() // selectionManager.cut()
+ KeyCommand.LEFT_CHAR -> collapseLeftOr { moveCursorLeft() }
+ KeyCommand.RIGHT_CHAR -> collapseRightOr { moveCursorRight() }
+ KeyCommand.LEFT_WORD -> moveCursorLeftByWord()
+ KeyCommand.RIGHT_WORD -> moveCursorRightByWord()
+ KeyCommand.PREV_PARAGRAPH -> moveCursorPrevByParagraph()
+ KeyCommand.NEXT_PARAGRAPH -> moveCursorNextByParagraph()
+ KeyCommand.UP -> moveCursorUpByLine()
+ KeyCommand.DOWN -> moveCursorDownByLine()
+ KeyCommand.PAGE_UP -> moveCursorUpByPage()
+ KeyCommand.PAGE_DOWN -> moveCursorDownByPage()
+ KeyCommand.LINE_START -> moveCursorToLineStart()
+ KeyCommand.LINE_END -> moveCursorToLineEnd()
+ KeyCommand.LINE_LEFT -> moveCursorToLineLeftSide()
+ KeyCommand.LINE_RIGHT -> moveCursorToLineRightSide()
+ KeyCommand.HOME -> moveCursorToHome()
+ KeyCommand.END -> moveCursorToEnd()
+ KeyCommand.DELETE_PREV_CHAR ->
+ deleteIfSelectedOr {
+ DeleteSurroundingTextCommand(
+ selection.end - getPrecedingCharacterIndex(),
+ 0
+ )
+ }?.applyOnto(state)
+
+ KeyCommand.DELETE_NEXT_CHAR -> {
+ // Note that some software keyboards, such as Samsungs, go through this code
+ // path instead of making calls on the InputConnection directly.
+ deleteIfSelectedOr {
+ val nextCharacterIndex = getNextCharacterIndex()
+ // If there's no next character, it means the cursor is at the end of the
+ // text, and this should be a no-op. See b/199919707.
+ if (nextCharacterIndex != NoCharacterFound) {
+ DeleteSurroundingTextCommand(0, nextCharacterIndex - selection.end)
+ } else {
+ null
+ }
+ }?.applyOnto(state)
+ }
+
+ KeyCommand.DELETE_PREV_WORD ->
+ deleteIfSelectedOr {
+ getPreviousWordOffset()?.let {
+ DeleteSurroundingTextCommand(selection.end - it, 0)
+ }
+ }?.applyOnto(state)
+
+ KeyCommand.DELETE_NEXT_WORD ->
+ deleteIfSelectedOr {
+ getNextWordOffset()?.let {
+ DeleteSurroundingTextCommand(0, it - selection.end)
+ }
+ }?.applyOnto(state)
+
+ KeyCommand.DELETE_FROM_LINE_START ->
+ deleteIfSelectedOr {
+ getLineStartByOffset()?.let {
+ DeleteSurroundingTextCommand(selection.end - it, 0)
+ }
+ }?.applyOnto(state)
+
+ KeyCommand.DELETE_TO_LINE_END ->
+ deleteIfSelectedOr {
+ getLineEndByOffset()?.let {
+ DeleteSurroundingTextCommand(0, it - selection.end)
+ }
+ }?.applyOnto(state)
+
+ KeyCommand.NEW_LINE ->
+ if (!singleLine) {
+ CommitTextCommand("\n", 1).applyOnto(state)
+ } else {
+ onSubmit()
+ }
+
+ KeyCommand.TAB ->
+ if (!singleLine) {
+ CommitTextCommand("\t", 1).applyOnto(state)
+ } else {
+ consumed = false // let propagate to focus system
+ }
+
+ KeyCommand.SELECT_ALL -> selectAll()
+ KeyCommand.SELECT_LEFT_CHAR -> moveCursorLeft().selectMovement()
+ KeyCommand.SELECT_RIGHT_CHAR -> moveCursorRight().selectMovement()
+ KeyCommand.SELECT_LEFT_WORD -> moveCursorLeftByWord().selectMovement()
+ KeyCommand.SELECT_RIGHT_WORD -> moveCursorRightByWord().selectMovement()
+ KeyCommand.SELECT_PREV_PARAGRAPH -> moveCursorPrevByParagraph().selectMovement()
+ KeyCommand.SELECT_NEXT_PARAGRAPH -> moveCursorNextByParagraph().selectMovement()
+ KeyCommand.SELECT_LINE_START -> moveCursorToLineStart().selectMovement()
+ KeyCommand.SELECT_LINE_END -> moveCursorToLineEnd().selectMovement()
+ KeyCommand.SELECT_LINE_LEFT -> moveCursorToLineLeftSide().selectMovement()
+ KeyCommand.SELECT_LINE_RIGHT -> moveCursorToLineRightSide().selectMovement()
+ KeyCommand.SELECT_UP -> moveCursorUpByLine().selectMovement()
+ KeyCommand.SELECT_DOWN -> moveCursorDownByLine().selectMovement()
+ KeyCommand.SELECT_PAGE_UP -> moveCursorUpByPage().selectMovement()
+ KeyCommand.SELECT_PAGE_DOWN -> moveCursorDownByPage().selectMovement()
+ KeyCommand.SELECT_HOME -> moveCursorToHome().selectMovement()
+ KeyCommand.SELECT_END -> moveCursorToEnd().selectMovement()
+ KeyCommand.DESELECT -> deselect()
+ KeyCommand.UNDO -> {
+ // undoManager?.makeSnapshot(value)
+ // undoManager?.undo()?.let { this@TextFieldKeyInput.onValueChange(it) }
+ }
+
+ KeyCommand.REDO -> {
+ // undoManager?.redo()?.let { this@TextFieldKeyInput.onValueChange(it) }
+ }
+
+ KeyCommand.CHARACTER_PALETTE -> {
+ showCharacterPalette()
+ }
+ }
+ }
+ // undoManager?.forceNextSnapshot()
+ return consumed
+ }
+
+ private fun KeyEvent.toTypedEditCommand(): CommitTextCommand? {
+ if (!isTypedEvent) {
+ return null
+ }
+
+ val codePoint = deadKeyCombiner.consume(this) ?: return null
+ val text = StringBuilder(2).appendCodePointX(codePoint).toString()
+ return CommitTextCommand(text, 1)
+ }
+
+ private inline fun preparedSelectionContext(
+ state: TextFieldState,
+ textLayoutState: TextLayoutState,
+ block: TextFieldPreparedSelection.() -> Unit
+ ) {
+ val preparedSelection = TextFieldPreparedSelection(
+ state = state,
+ textLayoutState = textLayoutState,
+ textPreparedSelectionState = preparedSelectionState
+ )
+ preparedSelection.block()
+ if (preparedSelection.selection != preparedSelection.initialValue.selectionInChars) {
+ // update the editProcessor with the latest selection state.
+ // this has to be a reset because EditCommands do not inform IME.
+ state.edit {
+ selectCharsIn(preparedSelection.selection)
+ }
+ }
+ }
+
+ /**
+ * Helper function to apply a list of EditCommands in the scope of [TextFieldPreparedSelection]
+ */
+ private fun List<EditCommand>.applyOnto(state: TextFieldState) {
+ state.editProcessor.update(
+ this.toMutableList().apply {
+ add(0, FinishComposingTextCommand)
+ },
+ filter
+ )
+ }
+
+ private fun EditCommand.applyOnto(state: TextFieldState) {
+ state.editProcessor.update(listOf(FinishComposingTextCommand, this), filter)
+ }
+}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextInputSession.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextInputSession.kt
new file mode 100644
index 0000000..a916c38
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextInputSession.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.text2.input.internal
+
+import android.view.KeyEvent
+import android.view.inputmethod.InputConnection
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.ImeOptions
+import androidx.compose.ui.text.input.TextFieldValue
+
+/**
+ * Represents a disposable text input session that starts when an editable BasicTextField2 gains
+ * focus. [TextInputSession] is the main interface for BasicTextField2 to interact with
+ * IME. A session is destroyed when text input is no longer active.
+ */
+internal interface TextInputSession {
+
+ /**
+ * Whether this session is still active.
+ *
+ * This value can only go through two phases. It starts as true and becomes false when session
+ * is destroyed. It can never become true again so a destroyed session should always be cleared
+ * from memory.
+ */
+ val isOpen: Boolean
+
+ /**
+ * Sets an optional [TextEditFilter] to be used when processing input.
+ */
+ fun setFilter(filter: TextEditFilter?)
+
+ /**
+ * Request this session to show the software keyboard.
+ */
+ fun showSoftwareKeyboard()
+
+ /**
+ * Request this session to hide the software keyboard.
+ */
+ fun hideSoftwareKeyboard()
+
+ /**
+ * Destroy this session and clear resources.
+ */
+ fun dispose()
+}
+
+/**
+ * Extended [TextInputSession] that handles [EditCommand]s and keeps track of current
+ * [TextFieldValue]. This interface meant to be completely internal to [AndroidTextInputAdapter].
+ * Please use [TextInputSession] to manage focus and other details from the editor.
+ */
+internal interface EditableTextInputSession : TextInputSession {
+
+ /**
+ * The current [TextFieldValue] in this input session. This value is typically supplied by a
+ * backing [TextFieldState] that is used to initialize the session.
+ */
+ val value: TextFieldCharSequence
+
+ /**
+ * Callback to execute for InputConnection to communicate the changes requested by the IME.
+ */
+ fun requestEdits(editCommands: List<EditCommand>)
+
+ /**
+ * Delegates IME requested KeyEvents.
+ */
+ fun sendKeyEvent(keyEvent: KeyEvent)
+
+ /**
+ * IME configuration to use when creating new [InputConnection]s while this session is active.
+ */
+ val imeOptions: ImeOptions
+
+ /**
+ * Callback to run when IME sends an action via [InputConnection.performEditorAction]
+ */
+ fun onImeAction(imeAction: ImeAction)
+}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextLayoutState.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextLayoutState.kt
new file mode 100644
index 0000000..ff503ef
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextLayoutState.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.foundation.text.InternalFoundationTextApi
+import androidx.compose.foundation.text.TextDelegate
+import androidx.compose.foundation.text.TextLayoutResultProxy
+import androidx.compose.foundation.text.updateTextDelegate
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.Snapshot
+import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
+
+@OptIn(InternalFoundationTextApi::class)
+internal class TextLayoutState(initialTextDelegate: TextDelegate) {
+ /**
+ * Set of parameters and an internal cache to compute text layout.
+ */
+ var textDelegate: TextDelegate = initialTextDelegate
+ private set
+
+ /**
+ * Text Layout State.
+ */
+ var layoutResult: TextLayoutResult? by mutableStateOf(null)
+ private set
+
+ /**
+ * A helper class to find positions on text layout relative to wrapping decoration box.
+ */
+ var proxy: TextLayoutResultProxy? = null
+
+ fun MeasureScope.layout(
+ text: AnnotatedString,
+ textStyle: TextStyle,
+ softWrap: Boolean,
+ density: Density,
+ fontFamilyResolver: FontFamily.Resolver,
+ constraints: Constraints,
+ onTextLayout: Density.(TextLayoutResult) -> Unit
+ ): TextLayoutResult {
+ val prevResult = Snapshot.withoutReadObservation { layoutResult }
+
+ val newTextDelegate = updateTextDelegate(
+ current = textDelegate,
+ text = text,
+ style = textStyle,
+ softWrap = softWrap,
+ density = density,
+ fontFamilyResolver = fontFamilyResolver,
+ placeholders = emptyList(),
+ )
+
+ return newTextDelegate.layout(
+ layoutDirection = layoutDirection,
+ constraints = constraints,
+ prevResult = prevResult
+ ).also {
+ textDelegate = newTextDelegate
+ if (prevResult != it) {
+ onTextLayout(it)
+ }
+ layoutResult = it
+ proxy = TextLayoutResultProxy(it).apply {
+ decorationBoxCoordinates = proxy?.decorationBoxCoordinates
+ innerTextFieldCoordinates = proxy?.innerTextFieldCoordinates
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextPreparedSelection.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextPreparedSelection.kt
new file mode 100644
index 0000000..9bc6d85
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextPreparedSelection.kt
@@ -0,0 +1,427 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.TextLayoutResultProxy
+import androidx.compose.foundation.text.findFollowingBreak
+import androidx.compose.foundation.text.findParagraphEnd
+import androidx.compose.foundation.text.findParagraphStart
+import androidx.compose.foundation.text.findPrecedingBreak
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.runtime.snapshots.Snapshot
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.style.ResolvedTextDirection
+import kotlin.math.abs
+
+/**
+ * [TextFieldPreparedSelection] provides a scope for many selection-related operations. However,
+ * some vertical cursor operations like moving between lines or page up and down require a cache of
+ * X position in text to remember where to move the cursor in next line.
+ * [TextFieldPreparedSelection] is a disposable scope that cannot hold its own state. This class
+ * helps to pass a cached X value between selection operations in different scopes.
+ */
+internal class TextFieldPreparedSelectionState {
+ /**
+ * it's set at the start of vertical navigation and used as the preferred value to set a new
+ * cursor position.
+ */
+ var cachedX: Float? = null
+
+ /**
+ * Remove and forget the cached X used for vertical navigation.
+ */
+ fun resetCachedX() {
+ cachedX = null
+ }
+}
+
+/**
+ * This utility class implements many selection-related operations on text (including basic
+ * cursor movements and deletions) and combines them, taking into account how the text was
+ * rendered. So, for example, [moveCursorToLineEnd] moves it to the visual line end.
+ *
+ * For many of these operations, it's particularly important to keep the difference between
+ * selection start and selection end. In some systems, they are called "anchor" and "caret"
+ * respectively. For example, for selection from scratch, after [moveCursorLeftByWord]
+ * [moveCursorRight] will move the left side of the selection, but after [moveCursorRightByWord]
+ * the right one.
+ *
+ * To use it in scope of text fields see [TextFieldPreparedSelection]
+ */
+@OptIn(ExperimentalFoundationApi::class)
+internal class TextFieldPreparedSelection(
+ private val state: TextFieldState,
+ private val textLayoutState: TextLayoutState,
+ private val textPreparedSelectionState: TextFieldPreparedSelectionState
+) {
+ /**
+ * Read the value from state without read observation to not accidentally cause recompositions.
+ * Freezing the initial value is necessary to make atomic operations in the scope of this
+ * [TextFieldPreparedSelection]. It is also used to make comparison between the initial state
+ * and the modified state of selection and content.
+ */
+ val initialValue = Snapshot.withoutReadObservation { state.text }
+
+ /**
+ * Current active selection in the context of this [TextFieldPreparedSelection]
+ */
+ var selection = initialValue.selectionInChars
+
+ /**
+ * Initial text value.
+ */
+ private val text: String = initialValue.toString()
+
+ /**
+ * If there is a non-collapsed selection, delete its contents. Or execute the given [or] block.
+ * Either way this function returns list of [EditCommand]s that should be applied on
+ * [TextFieldState].
+ */
+ fun deleteIfSelectedOr(or: TextFieldPreparedSelection.() -> EditCommand?): List<EditCommand>? {
+ return if (selection.collapsed) {
+ or(this)?.let { editCommand -> listOf(editCommand) }
+ } else {
+ listOf(
+ CommitTextCommand("", 0),
+ SetSelectionCommand(selection.min, selection.min)
+ )
+ }
+ }
+
+ /**
+ * Executes PageUp key
+ */
+ fun moveCursorUpByPage() = applyIfNotEmpty(false) {
+ textLayoutState.proxy?.jumpByPagesOffset(-1)?.let { setCursor(it) }
+ }
+
+ /**
+ * Executes PageDown key
+ */
+ fun moveCursorDownByPage() = applyIfNotEmpty(false) {
+ textLayoutState.proxy?.jumpByPagesOffset(1)?.let { setCursor(it) }
+ }
+
+ /**
+ * Returns a cursor position after jumping back or forth by [pagesAmount] number of pages,
+ * where `page` is the visible amount of space in the text field. Visible rectangle is
+ * calculated by the coordinates of decoration box around the TextField.
+ */
+ private fun TextLayoutResultProxy.jumpByPagesOffset(pagesAmount: Int): Int {
+ val visibleInnerTextFieldRect = innerTextFieldCoordinates?.let { inner ->
+ decorationBoxCoordinates?.localBoundingBoxOf(inner)
+ } ?: Rect.Zero
+ val currentOffset = initialValue.selectionInChars.end
+ val currentPos = value.getCursorRect(currentOffset)
+ val newPos = currentPos.translate(
+ translateX = 0f,
+ translateY = visibleInnerTextFieldRect.size.height * pagesAmount
+ )
+ // which line does the new cursor position belong?
+ val topLine = value.getLineForVerticalPosition(newPos.top)
+ val lineSeparator = value.getLineBottom(topLine)
+ return if (abs(newPos.top - lineSeparator) > abs(newPos.bottom - lineSeparator)) {
+ // most of new cursor is on top line
+ value.getOffsetForPosition(newPos.topLeft)
+ } else {
+ // most of new cursor is on bottom line
+ value.getOffsetForPosition(newPos.bottomLeft)
+ }
+ }
+
+ /**
+ * Only apply the given [block] if the text is not empty.
+ *
+ * @param resetCachedX Whether to reset the cachedX parameter in [TextFieldPreparedSelectionState].
+ */
+ inline fun applyIfNotEmpty(
+ resetCachedX: Boolean = true,
+ block: TextFieldPreparedSelection.() -> Unit
+ ): TextFieldPreparedSelection {
+ if (resetCachedX) {
+ textPreparedSelectionState.resetCachedX()
+ }
+ if (text.isNotEmpty()) {
+ this.block()
+ }
+ return this
+ }
+
+ /**
+ * Sets a collapsed selection at given [offset].
+ */
+ private fun setCursor(offset: Int) {
+ selection = TextRange(offset, offset)
+ }
+
+ fun selectAll() = applyIfNotEmpty {
+ selection = TextRange(0, text.length)
+ }
+
+ fun deselect() = applyIfNotEmpty {
+ setCursor(selection.end)
+ }
+
+ fun moveCursorLeft() = applyIfNotEmpty {
+ if (isLtr()) {
+ moveCursorPrev()
+ } else {
+ moveCursorNext()
+ }
+ }
+
+ fun moveCursorRight() = applyIfNotEmpty {
+ if (isLtr()) {
+ moveCursorNext()
+ } else {
+ moveCursorPrev()
+ }
+ }
+
+ /**
+ * If there is already a selection, collapse it to the left side. Otherwise, execute [or]
+ */
+ fun collapseLeftOr(or: TextFieldPreparedSelection.() -> Unit) = applyIfNotEmpty {
+ if (selection.collapsed) {
+ or(this)
+ } else {
+ if (isLtr()) {
+ setCursor(selection.min)
+ } else {
+ setCursor(selection.max)
+ }
+ }
+ }
+
+ /**
+ * If there is already a selection, collapse it to the right side. Otherwise, execute [or]
+ */
+ fun collapseRightOr(or: TextFieldPreparedSelection.() -> Unit) = applyIfNotEmpty {
+ if (selection.collapsed) {
+ or(this)
+ } else {
+ if (isLtr()) {
+ setCursor(selection.max)
+ } else {
+ setCursor(selection.min)
+ }
+ }
+ }
+
+ /**
+ * Returns the index of the character break preceding the end of [selection].
+ */
+ fun getPrecedingCharacterIndex() = text.findPrecedingBreak(selection.end)
+
+ /**
+ * Returns the index of the character break following the end of [selection]. Returns
+ * [NoCharacterFound] if there are no more breaks before the end of the string.
+ */
+ fun getNextCharacterIndex() = text.findFollowingBreak(selection.end)
+
+ private fun moveCursorPrev() = applyIfNotEmpty {
+ val prev = getPrecedingCharacterIndex()
+ if (prev != -1) setCursor(prev)
+ }
+
+ private fun moveCursorNext() = applyIfNotEmpty {
+ val next = getNextCharacterIndex()
+ if (next != -1) setCursor(next)
+ }
+
+ fun moveCursorToHome() = applyIfNotEmpty {
+ setCursor(0)
+ }
+
+ fun moveCursorToEnd() = applyIfNotEmpty {
+ setCursor(text.length)
+ }
+
+ fun moveCursorLeftByWord() = applyIfNotEmpty {
+ if (isLtr()) {
+ moveCursorPrevByWord()
+ } else {
+ moveCursorNextByWord()
+ }
+ }
+
+ fun moveCursorRightByWord() = applyIfNotEmpty {
+ if (isLtr()) {
+ moveCursorNextByWord()
+ } else {
+ moveCursorPrevByWord()
+ }
+ }
+
+ fun getNextWordOffset(): Int? = textLayoutState.layoutResult?.getNextWordOffsetForLayout()
+
+ private fun moveCursorNextByWord() = applyIfNotEmpty {
+ getNextWordOffset()?.let { setCursor(it) }
+ }
+
+ fun getPreviousWordOffset(): Int? = textLayoutState.layoutResult?.getPrevWordOffset()
+
+ private fun moveCursorPrevByWord() = applyIfNotEmpty {
+ getPreviousWordOffset()?.let { setCursor(it) }
+ }
+
+ fun moveCursorPrevByParagraph() = applyIfNotEmpty {
+ setCursor(getParagraphStart())
+ }
+
+ fun moveCursorNextByParagraph() = applyIfNotEmpty {
+ setCursor(getParagraphEnd())
+ }
+
+ fun moveCursorUpByLine() = applyIfNotEmpty(false) {
+ textLayoutState.layoutResult?.jumpByLinesOffset(-1)?.let { setCursor(it) }
+ }
+
+ fun moveCursorDownByLine() = applyIfNotEmpty(false) {
+ textLayoutState.layoutResult?.jumpByLinesOffset(1)?.let { setCursor(it) }
+ }
+
+ fun getLineStartByOffset(): Int? = textLayoutState.layoutResult?.getLineStartByOffsetForLayout()
+
+ fun moveCursorToLineStart() = applyIfNotEmpty {
+ getLineStartByOffset()?.let { setCursor(it) }
+ }
+
+ fun getLineEndByOffset(): Int? = textLayoutState.layoutResult?.getLineEndByOffsetForLayout()
+
+ fun moveCursorToLineEnd() = applyIfNotEmpty {
+ getLineEndByOffset()?.let { setCursor(it) }
+ }
+
+ fun moveCursorToLineLeftSide() = applyIfNotEmpty {
+ if (isLtr()) {
+ moveCursorToLineStart()
+ } else {
+ moveCursorToLineEnd()
+ }
+ }
+
+ fun moveCursorToLineRightSide() = applyIfNotEmpty {
+ if (isLtr()) {
+ moveCursorToLineEnd()
+ } else {
+ moveCursorToLineStart()
+ }
+ }
+
+ // it selects a text from the original selection start to a current selection end
+ fun selectMovement() = applyIfNotEmpty(false) {
+ selection = TextRange(initialValue.selectionInChars.start, selection.end)
+ }
+
+ private fun isLtr(): Boolean {
+ val direction = textLayoutState.layoutResult?.getParagraphDirection(selection.end)
+ return direction != ResolvedTextDirection.Rtl
+ }
+
+ private tailrec fun TextLayoutResult.getNextWordOffsetForLayout(
+ currentOffset: Int = selection.end
+ ): Int {
+ if (currentOffset >= initialValue.length) {
+ return initialValue.length
+ }
+ val currentWord = getWordBoundary(charOffset(currentOffset))
+ return if (currentWord.end <= currentOffset) {
+ getNextWordOffsetForLayout(currentOffset + 1)
+ } else {
+ currentWord.end
+ }
+ }
+
+ private tailrec fun TextLayoutResult.getPrevWordOffset(
+ currentOffset: Int = selection.end
+ ): Int {
+ if (currentOffset <= 0) {
+ return 0
+ }
+ val currentWord = getWordBoundary(charOffset(currentOffset))
+ return if (currentWord.start >= currentOffset) {
+ getPrevWordOffset(currentOffset - 1)
+ } else {
+ currentWord.start
+ }
+ }
+
+ private fun TextLayoutResult.getLineStartByOffsetForLayout(
+ currentOffset: Int = selection.min
+ ): Int {
+ val currentLine = getLineForOffset(currentOffset)
+ return getLineStart(currentLine)
+ }
+
+ private fun TextLayoutResult.getLineEndByOffsetForLayout(
+ currentOffset: Int = selection.max
+ ): Int {
+ val currentLine = getLineForOffset(currentOffset)
+ return getLineEnd(currentLine, true)
+ }
+
+ private fun TextLayoutResult.jumpByLinesOffset(linesAmount: Int): Int {
+ val currentOffset = selection.end
+
+ if (textPreparedSelectionState.cachedX == null) {
+ textPreparedSelectionState.cachedX = getCursorRect(currentOffset).left
+ }
+
+ val targetLine = getLineForOffset(currentOffset) + linesAmount
+ when {
+ targetLine < 0 -> {
+ return 0
+ }
+
+ targetLine >= lineCount -> {
+ return text.length
+ }
+ }
+
+ val y = getLineBottom(targetLine) - 1
+ val x = textPreparedSelectionState.cachedX!!.also {
+ if ((isLtr() && it >= getLineRight(targetLine)) ||
+ (!isLtr() && it <= getLineLeft(targetLine))
+ ) {
+ return getLineEnd(targetLine, true)
+ }
+ }
+
+ return getOffsetForPosition(Offset(x, y))
+ }
+
+ private fun charOffset(offset: Int) = offset.coerceAtMost(text.length - 1)
+
+ private fun getParagraphStart() = text.findParagraphStart(selection.min)
+
+ private fun getParagraphEnd() = text.findParagraphEnd(selection.max)
+
+ companion object {
+ /**
+ * Value returned by [getNextCharacterIndex] and [getPrecedingCharacterIndex] when no valid
+ * index could be found, e.g. it would be the end of the string.
+ *
+ * This is equivalent to `BreakIterator.DONE` on JVM/Android.
+ */
+ const val NoCharacterFound = -1
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt
index c95216d..0bae435 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt
@@ -133,14 +133,24 @@
var width = widthParameter
set(value) {
- field = value
- drawWithCacheModifierNode.invalidateDrawCache()
+ if (field != value) {
+ field = value
+ drawWithCacheModifierNode.invalidateDrawCache()
+ }
}
var brush = brushParameter
+ set(value) {
+ if (field != value) {
+ field = value
+ drawWithCacheModifierNode.invalidateDrawCache()
+ }
+ }
var shape = shapeParameter
set(value) {
- field = value
- drawWithCacheModifierNode.invalidateDrawCache()
+ if (field != value) {
+ field = value
+ drawWithCacheModifierNode.invalidateDrawCache()
+ }
}
private val drawWithCacheModifierNode = delegate(
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
index 86fda0b..87e9610 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
@@ -269,16 +269,18 @@
.indication(interactionSource, indication)
.hoverable(enabled = enabled, interactionSource = interactionSource)
.focusableInNonTouchMode(enabled = enabled, interactionSource = interactionSource)
- .then(CombinedClickableElement(
- interactionSource,
- enabled,
- onClickLabel,
- role,
- onClick,
- onLongClickLabel,
- onLongClick,
- onDoubleClick
- ))
+ .then(
+ CombinedClickableElement(
+ interactionSource,
+ enabled,
+ onClickLabel,
+ role,
+ onClick,
+ onLongClickLabel,
+ onLongClick,
+ onDoubleClick
+ )
+ )
}
private suspend fun PressGestureScope.handlePressInteraction(
@@ -462,28 +464,28 @@
private val onLongClickLabel: String?,
private val onLongClick: (() -> Unit)?,
private val onDoubleClick: (() -> Unit)?
-) : ModifierNodeElement<CombinedClickableNode>() {
- override fun create() = CombinedClickableNode(
+) : ModifierNodeElement<CombinedClickableNodeImpl>() {
+ override fun create() = CombinedClickableNodeImpl(
+ onClick,
+ onLongClickLabel,
+ onLongClick,
+ onDoubleClick,
interactionSource,
enabled,
onClickLabel,
role,
- onClick,
- onLongClickLabel,
- onLongClick,
- onDoubleClick
)
- override fun update(node: CombinedClickableNode) {
+ override fun update(node: CombinedClickableNodeImpl) {
node.update(
+ onClick,
+ onLongClickLabel,
+ onLongClick,
+ onDoubleClick,
interactionSource,
enabled,
onClickLabel,
role,
- onClick,
- onLongClickLabel,
- onLongClick,
- onDoubleClick
)
}
@@ -572,16 +574,95 @@
}
}
-private class CombinedClickableNode(
+/**
+ * Create a [CombinedClickableNode] that can be delegated to inside custom modifier nodes.
+ *
+ * This API is experimental and is temporarily being exposed to enable performance analysis, you
+ * should use [combinedClickable] instead for the majority of use cases.
+ *
+ * @param onClick will be called when user clicks on the element
+ * @param onLongClickLabel semantic / accessibility label for the [onLongClick] action
+ * @param onLongClick will be called when user long presses on the element
+ * @param onDoubleClick will be called when user double clicks on the element
+ * @param interactionSource [MutableInteractionSource] that will be used to emit
+ * [PressInteraction.Press] when this clickable is pressed. Only the initial (first) press will be
+ * recorded and emitted with [MutableInteractionSource].
+ * @param enabled Controls the enabled state. When false, [onClick], [onLongClick] or
+ * [onDoubleClick] won't be invoked
+ * @param onClickLabel semantic / accessibility label for the [onClick] action
+ * @param role the type of user interface element. Accessibility services might use this
+ * to describe the element or do customizations
+ */
+@ExperimentalFoundationApi
+fun CombinedClickableNode(
+ onClick: () -> Unit,
+ onLongClickLabel: String?,
+ onLongClick: (() -> Unit)?,
+ onDoubleClick: (() -> Unit)?,
interactionSource: MutableInteractionSource,
enabled: Boolean,
onClickLabel: String?,
role: Role?,
+): CombinedClickableNode = CombinedClickableNodeImpl(
+ onClick,
+ onLongClickLabel,
+ onLongClick,
+ onDoubleClick,
+ interactionSource,
+ enabled,
+ onClickLabel,
+ role,
+)
+
+/**
+ * Public interface for the internal node used inside [combinedClickable], to allow for custom
+ * modifier nodes to delegate to it.
+ *
+ * This API is experimental and is temporarily being exposed to enable performance analysis, you
+ * should use [combinedClickable] instead for the majority of use cases.
+ */
+@ExperimentalFoundationApi
+sealed interface CombinedClickableNode : PointerInputModifierNode {
+ /**
+ * Updates this node with new values, and resets any invalidated state accordingly.
+ *
+ * @param onClick will be called when user clicks on the element
+ * @param onLongClickLabel semantic / accessibility label for the [onLongClick] action
+ * @param onLongClick will be called when user long presses on the element
+ * @param onDoubleClick will be called when user double clicks on the element
+ * @param interactionSource [MutableInteractionSource] that will be used to emit
+ * [PressInteraction.Press] when this clickable is pressed. Only the initial (first) press will
+ * be recorded and emitted with [MutableInteractionSource].
+ * @param enabled Controls the enabled state. When false, [onClick], [onLongClick] or
+ * [onDoubleClick] won't be invoked
+ * @param onClickLabel semantic / accessibility label for the [onClick] action
+ * @param role the type of user interface element. Accessibility services might use this
+ * to describe the element or do customizations
+ */
+ fun update(
+ onClick: () -> Unit,
+ onLongClickLabel: String?,
+ onLongClick: (() -> Unit)?,
+ onDoubleClick: (() -> Unit)?,
+ interactionSource: MutableInteractionSource,
+ enabled: Boolean,
+ onClickLabel: String?,
+ role: Role?,
+ )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+private class CombinedClickableNodeImpl(
onClick: () -> Unit,
onLongClickLabel: String?,
private var onLongClick: (() -> Unit)?,
- onDoubleClick: (() -> Unit)?
-) : AbstractClickableNode(interactionSource, enabled, onClickLabel, role, onClick) {
+ onDoubleClick: (() -> Unit)?,
+ interactionSource: MutableInteractionSource,
+ enabled: Boolean,
+ onClickLabel: String?,
+ role: Role?,
+) : CombinedClickableNode,
+ AbstractClickableNode(interactionSource, enabled, onClickLabel, role, onClick) {
override val clickableSemanticsNode = delegate(
ClickableSemanticsNode(
enabled = enabled,
@@ -604,15 +685,15 @@
)
)
- fun update(
+ override fun update(
+ onClick: () -> Unit,
+ onLongClickLabel: String?,
+ onLongClick: (() -> Unit)?,
+ onDoubleClick: (() -> Unit)?,
interactionSource: MutableInteractionSource,
enabled: Boolean,
onClickLabel: String?,
role: Role?,
- onClick: () -> Unit,
- onLongClickLabel: String?,
- onLongClick: (() -> Unit)?,
- onDoubleClick: (() -> Unit)?
) {
// If we have gone from no long click to having a long click or vice versa,
// cancel any existing press interactions.
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Image.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Image.kt
index 64b4556..2791752 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Image.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Image.kt
@@ -254,7 +254,6 @@
// Explicitly use a simple Layout implementation here as Spacer squashes any non fixed
// constraint with zero
Layout(
- {},
modifier.then(semantics).clipToBounds().paint(
painter,
alignment = alignment,
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
index 4eefc4c..412590f 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
@@ -327,7 +327,7 @@
}
)
-private class ScrollingLayoutElement(
+internal class ScrollingLayoutElement(
val scrollState: ScrollState,
val isReversed: Boolean,
val isVertical: Boolean
@@ -368,7 +368,7 @@
}
}
-private class ScrollingLayoutNode(
+internal class ScrollingLayoutNode(
var scrollerState: ScrollState,
var isReversed: Boolean,
var isVertical: Boolean
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/ContentInViewNode.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/ContentInViewNode.kt
index bf1ffd3..40edcad 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/ContentInViewNode.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/ContentInViewNode.kt
@@ -30,6 +30,7 @@
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.toSize
import kotlin.math.abs
+import kotlin.math.absoluteValue
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineName
@@ -47,6 +48,11 @@
private const val TAG = "ContentInViewModifier"
/**
+ * A minimum amount of delta that it is considered a valid scroll.
+ */
+private const val MinScrollThreshold = 0.5f
+
+/**
* A [Modifier] to be placed on a scrollable container (i.e. [Modifier.scrollable]) that animates
* the [ScrollableState] to handle [BringIntoViewRequester] requests and keep the currently-focused
* child in view when the viewport shrinks.
@@ -57,7 +63,8 @@
internal class ContentInViewNode(
private var orientation: Orientation,
private var scrollState: ScrollableState,
- private var reverseDirection: Boolean
+ private var reverseDirection: Boolean,
+ private var bringIntoViewScroller: BringIntoViewScroller
) : Modifier.Node(), BringIntoViewResponder, LayoutAwareModifierNode {
/**
@@ -94,7 +101,8 @@
/** The size of the scrollable container. */
private var viewportSize = IntSize.Zero
private var isAnimationRunning = false
- private val animationState = UpdatableAnimationState()
+ private val animationState =
+ UpdatableAnimationState(bringIntoViewScroller.scrollAnimationSpec)
override fun calculateRectForParent(localRect: Rect): Rect {
check(viewportSize != IntSize.Zero) {
@@ -197,7 +205,7 @@
)
val consumedScroll = scrollMultiplier * scrollBy(adjustedDelta)
if (DEBUG) println("[$TAG] Consumed $consumedScroll of scroll")
- if (consumedScroll < delta) {
+ if (consumedScroll.absoluteValue < delta.absoluteValue) {
// If the scroll state didn't consume all the scroll on this frame,
// it probably won't consume any more later either (we might have
// hit the scroll bounds). This is a terminal condition for the
@@ -291,15 +299,15 @@
val size = viewportSize.toSize()
return when (orientation) {
- Vertical -> relocationDistance(
+ Vertical -> bringIntoViewScroller.calculateScrollDistance(
rectangleToMakeVisible.top,
- rectangleToMakeVisible.bottom,
+ rectangleToMakeVisible.bottom - rectangleToMakeVisible.top,
size.height
)
- Horizontal -> relocationDistance(
+ Horizontal -> bringIntoViewScroller.calculateScrollDistance(
rectangleToMakeVisible.left,
- rectangleToMakeVisible.right,
+ rectangleToMakeVisible.right - rectangleToMakeVisible.left,
size.width
)
}
@@ -342,7 +350,9 @@
* already filling the whole viewport.
*/
private fun Rect.isMaxVisible(size: IntSize = viewportSize): Boolean {
- return relocationOffset(this, size) == Offset.Zero
+ val relocationOffset = relocationOffset(this, size)
+ return abs(relocationOffset.x) <= MinScrollThreshold &&
+ abs(relocationOffset.y) <= MinScrollThreshold
}
private fun relocationOffset(childBounds: Rect, containerSize: IntSize): Offset {
@@ -350,36 +360,24 @@
return when (orientation) {
Vertical -> Offset(
x = 0f,
- y = relocationDistance(childBounds.top, childBounds.bottom, size.height)
+ y = bringIntoViewScroller.calculateScrollDistance(
+ childBounds.top,
+ childBounds.bottom - childBounds.top,
+ size.height
+ )
)
Horizontal -> Offset(
- x = relocationDistance(childBounds.left, childBounds.right, size.width),
+ x = bringIntoViewScroller.calculateScrollDistance(
+ childBounds.left,
+ childBounds.right - childBounds.left,
+ size.width
+ ),
y = 0f
)
}
}
- /**
- * Calculate the offset needed to bring one of the edges into view. The leadingEdge is the side
- * closest to the origin (For the x-axis this is 'left', for the y-axis this is 'top').
- * The trailing edge is the other side (For the x-axis this is 'right', for the y-axis this is
- * 'bottom').
- */
- private fun relocationDistance(leadingEdge: Float, trailingEdge: Float, containerSize: Float) =
- when {
- // If the item is already visible, no need to scroll.
- leadingEdge >= 0 && trailingEdge <= containerSize -> 0f
-
- // If the item is visible but larger than the parent, we don't scroll.
- leadingEdge < 0 && trailingEdge > containerSize -> 0f
-
- // Find the minimum scroll needed to make one of the edges coincide with the parent's
- // edge.
- abs(leadingEdge) < abs(trailingEdge - containerSize) -> leadingEdge
- else -> trailingEdge - containerSize
- }
-
private operator fun IntSize.compareTo(other: IntSize): Int = when (orientation) {
Horizontal -> width.compareTo(other.width)
Vertical -> height.compareTo(other.height)
@@ -390,10 +388,16 @@
Vertical -> height.compareTo(other.height)
}
- fun update(orientation: Orientation, state: ScrollableState, reverseDirection: Boolean) {
+ fun update(
+ orientation: Orientation,
+ state: ScrollableState,
+ reverseDirection: Boolean,
+ bringIntoViewScroller: BringIntoViewScroller
+ ) {
this.orientation = orientation
this.scrollState = state
this.reverseDirection = reverseDirection
+ this.bringIntoViewScroller = bringIntoViewScroller
}
/**
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
index fb5dc19..baaf516 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
@@ -16,33 +16,38 @@
package androidx.compose.foundation.gestures
+import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.AnimationState
import androidx.compose.animation.core.DecayAnimationSpec
import androidx.compose.animation.core.animateDecay
+import androidx.compose.animation.core.spring
import androidx.compose.animation.rememberSplineBasedDecay
import androidx.compose.animation.splineBasedDecay
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.FocusedBoundsObserverNode
import androidx.compose.foundation.MutatePriority
import androidx.compose.foundation.OverscrollEffect
+import androidx.compose.foundation.gestures.BringIntoViewScroller.Companion.DefaultBringIntoViewScroller
import androidx.compose.foundation.gestures.Orientation.Horizontal
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.relocation.BringIntoViewResponderNode
import androidx.compose.foundation.rememberOverscrollEffect
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.MotionDurationScale
import androidx.compose.ui.focus.FocusProperties
import androidx.compose.ui.focus.FocusPropertiesModifierNode
-import androidx.compose.ui.focus.FocusTargetNode
+import androidx.compose.ui.focus.FocusTargetModifierNode
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion.Drag
import androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion.Fling
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion.Wheel
import androidx.compose.ui.input.nestedscroll.nestedScrollModifierNode
import androidx.compose.ui.input.pointer.AwaitPointerEventScope
import androidx.compose.ui.input.pointer.PointerEvent
@@ -70,6 +75,7 @@
import androidx.compose.ui.util.fastAll
import androidx.compose.ui.util.fastForEach
import kotlin.math.abs
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -144,6 +150,8 @@
* `null`, default from [ScrollableDefaults.flingBehavior] will be used.
* @param interactionSource [MutableInteractionSource] that will be used to emit
* drag events when this scrollable is being dragged.
+ * @param bringIntoViewScroller The configuration that this scrollable should use to perform
+ * scrolling when scroll requests are received from the focus system.
*/
@ExperimentalFoundationApi
fun Modifier.scrollable(
@@ -153,15 +161,17 @@
enabled: Boolean = true,
reverseDirection: Boolean = false,
flingBehavior: FlingBehavior? = null,
- interactionSource: MutableInteractionSource? = null
-): Modifier = this then ScrollableElement(
+ interactionSource: MutableInteractionSource? = null,
+ bringIntoViewScroller: BringIntoViewScroller = ScrollableDefaults.bringIntoViewScroller()
+) = this then ScrollableElement(
state,
orientation,
overscrollEffect,
enabled,
reverseDirection,
flingBehavior,
- interactionSource
+ interactionSource,
+ bringIntoViewScroller
)
@OptIn(ExperimentalFoundationApi::class)
@@ -172,7 +182,8 @@
val enabled: Boolean,
val reverseDirection: Boolean,
val flingBehavior: FlingBehavior?,
- val interactionSource: MutableInteractionSource?
+ val interactionSource: MutableInteractionSource?,
+ val bringIntoViewScroller: BringIntoViewScroller
) : ModifierNodeElement<ScrollableNode>() {
override fun create(): ScrollableNode {
return ScrollableNode(
@@ -182,7 +193,8 @@
enabled,
reverseDirection,
flingBehavior,
- interactionSource
+ interactionSource,
+ bringIntoViewScroller
)
}
@@ -194,7 +206,8 @@
enabled,
reverseDirection,
flingBehavior,
- interactionSource
+ interactionSource,
+ bringIntoViewScroller
)
}
@@ -206,6 +219,7 @@
result = 31 * result + reverseDirection.hashCode()
result = 31 * result + flingBehavior.hashCode()
result = 31 * result + interactionSource.hashCode()
+ result = 31 * result + bringIntoViewScroller.hashCode()
return result
}
@@ -221,6 +235,7 @@
if (reverseDirection != other.reverseDirection) return false
if (flingBehavior != other.flingBehavior) return false
if (interactionSource != other.interactionSource) return false
+ if (bringIntoViewScroller != other.bringIntoViewScroller) return false
return true
}
@@ -234,6 +249,7 @@
properties["reverseDirection"] = reverseDirection
properties["flingBehavior"] = flingBehavior
properties["interactionSource"] = interactionSource
+ properties["scrollableBringIntoViewConfig"] = bringIntoViewScroller
}
}
@@ -245,7 +261,8 @@
private var enabled: Boolean,
private var reverseDirection: Boolean,
private var flingBehavior: FlingBehavior?,
- private var interactionSource: MutableInteractionSource?
+ private var interactionSource: MutableInteractionSource?,
+ bringIntoViewScroller: BringIntoViewScroller
) : DelegatingNode(), ObserverModifierNode, CompositionLocalConsumerModifierNode,
FocusPropertiesModifierNode {
@@ -268,7 +285,15 @@
val nestedScrollConnection =
ScrollableNestedScrollConnection(enabled = enabled, scrollingLogic = scrollingLogic)
- val contentInViewNode = delegate(ContentInViewNode(orientation, state, reverseDirection))
+ val contentInViewNode =
+ delegate(
+ ContentInViewNode(
+ orientation,
+ state,
+ reverseDirection,
+ bringIntoViewScroller
+ )
+ )
val scrollableContainer = delegate(ModifierLocalScrollableContainerProvider(enabled))
init {
@@ -280,7 +305,7 @@
/**
* Focus scrolling
*/
- delegate(FocusTargetNode())
+ delegate(FocusTargetModifierNode())
delegate(BringIntoViewResponderNode(contentInViewNode))
delegate(FocusedBoundsObserverNode { contentInViewNode.onFocusBoundsChanged(it) })
}
@@ -306,7 +331,8 @@
enabled: Boolean,
reverseDirection: Boolean,
flingBehavior: FlingBehavior?,
- interactionSource: MutableInteractionSource?
+ interactionSource: MutableInteractionSource?,
+ bringIntoViewScroller: BringIntoViewScroller
) {
if (this.enabled != enabled) { // enabled changed
@@ -332,7 +358,12 @@
enabled = enabled
)
- contentInViewNode.update(orientation, state, reverseDirection)
+ contentInViewNode.update(
+ orientation,
+ state,
+ reverseDirection,
+ bringIntoViewScroller
+ )
this.state = state
this.orientation = orientation
@@ -365,6 +396,78 @@
}
/**
+ * The configuration of how a scrollable reacts to bring into view requests.
+ */
+@ExperimentalFoundationApi
+@Stable
+interface BringIntoViewScroller {
+
+ /**
+ * A retargetable Animation Spec to be used as the animation to run to fulfill the
+ * BringIntoView requests.
+ */
+ val scrollAnimationSpec: AnimationSpec<Float>
+
+ /**
+ * Calculate the offset needed to bring one of the scrollable container's child into view.
+ *
+ * @param offset is the side closest to the origin (For the x-axis this is 'left',
+ * for the y-axis this is 'top').
+ * @param size is the child size.
+ * @param containerSize Is the main axis size of the scrollable container.
+ *
+ * All distances above are represented in pixels.
+ *
+ * @return The necessary amount to scroll to satisfy the bring into view request.
+ * Returning zero from here means that the request was satisfied and the scrolling animation
+ * should stop.
+ *
+ * This will be called for every frame of the scrolling animation. This means that, as the
+ * animation progresses, the offset will naturally change to fulfill the scroll request.
+ */
+ fun calculateScrollDistance(
+ offset: Float,
+ size: Float,
+ containerSize: Float
+ ): Float
+
+ companion object {
+
+ /**
+ * The default animation spec used by [Modifier.scrollable] to run Bring Into View requests.
+ */
+ val DefaultScrollAnimationSpec: AnimationSpec<Float> = spring()
+
+ internal val DefaultBringIntoViewScroller = object : BringIntoViewScroller {
+
+ override val scrollAnimationSpec: AnimationSpec<Float> = DefaultScrollAnimationSpec
+
+ override fun calculateScrollDistance(
+ offset: Float,
+ size: Float,
+ containerSize: Float
+ ): Float {
+ val trailingEdge = offset + size
+ val leadingEdge = offset
+ return when {
+
+ // If the item is already visible, no need to scroll.
+ leadingEdge >= 0 && trailingEdge <= containerSize -> 0f
+
+ // If the item is visible but larger than the parent, we don't scroll.
+ leadingEdge < 0 && trailingEdge > containerSize -> 0f
+
+ // Find the minimum scroll needed to make one of the edges coincide with the parent's
+ // edge.
+ abs(leadingEdge) < abs(trailingEdge - containerSize) -> leadingEdge
+ else -> trailingEdge - containerSize
+ }
+ }
+ }
+ }
+}
+
+/**
* Contains the default values used by [scrollable]
*/
object ScrollableDefaults {
@@ -415,6 +518,13 @@
}
return reverseDirection
}
+
+ /**
+ * A default implementation for [BringIntoViewScroller] that brings a child into view
+ * using the least amount of effort.
+ */
+ @ExperimentalFoundationApi
+ fun bringIntoViewScroller(): BringIntoViewScroller = DefaultBringIntoViewScroller
}
internal interface ScrollConfig {
@@ -496,7 +606,6 @@
private val scrollingLogic: ScrollingLogic,
private var mouseWheelScrollConfig: ScrollConfig
) : DelegatingNode() {
-
private val pointerInputNode = delegate(SuspendingPointerInputModifierNode {
awaitPointerEventScope {
while (true) {
@@ -504,12 +613,20 @@
if (event.changes.fastAll { !it.isConsumed }) {
with(mouseWheelScrollConfig) {
val scrollAmount = calculateMouseWheelScroll(event, size)
+
with(scrollingLogic) {
- val delta = scrollAmount.toFloat().reverseIfNeeded()
- val consumedDelta = scrollableState.dispatchRawDelta(delta)
- if (consumedDelta != 0f) {
- event.changes.fastForEach { it.consume() }
+ // A coroutine is launched for every individual scroll event in the
+ // larger scroll gesture. If we see degradation in the future (that is,
+ // a fast scroll gesture on a slow device causes UI jank [not seen up to
+ // this point), we can switch to a more efficient solution where we
+ // lazily launch one coroutine (with the first event) and use a Channel
+ // to communicate the scroll amount to the UI thread.
+ coroutineScope.launch {
+ scrollableState.scroll(MutatePriority.UserInput) {
+ dispatchScroll(scrollAmount, Wheel)
+ }
}
+ event.changes.fastForEach { it.consume() }
}
}
}
@@ -577,8 +694,7 @@
val scrollDelta = availableDelta.singleAxisOffset()
val performScroll: (Offset) -> Offset = { delta ->
- val preConsumedByParent = nestedScrollDispatcher
- .dispatchPreScroll(delta, source)
+ val preConsumedByParent = nestedScrollDispatcher.dispatchPreScroll(delta, source)
val scrollAvailable = delta - preConsumedByParent
// Consume on a single axis
@@ -591,12 +707,14 @@
leftForParent,
source
)
-
preConsumedByParent + axisConsumed + parentConsumed
}
val overscroll = overscrollEffect
- return if (overscroll != null && shouldDispatchOverscroll) {
+
+ return if (source == Wheel) {
+ performScroll(scrollDelta)
+ } else if (overscroll != null && shouldDispatchOverscroll) {
overscroll.applyToScroll(scrollDelta, source, performScroll)
} else {
performScroll(scrollDelta)
@@ -625,7 +743,9 @@
val preConsumedByParent = nestedScrollDispatcher
.dispatchPreFling(velocity)
val available = velocity - preConsumedByParent
+
val velocityLeft = doFlingAnimation(available)
+
val consumedPost =
nestedScrollDispatcher.dispatchPostFling(
(available - velocityLeft),
@@ -777,17 +897,22 @@
if (abs(initialVelocity) > 1f) {
var velocityLeft = initialVelocity
var lastValue = 0f
- AnimationState(
+ val animationState = AnimationState(
initialValue = 0f,
initialVelocity = initialVelocity,
- ).animateDecay(flingDecay) {
- val delta = value - lastValue
- val consumed = scrollBy(delta)
- lastValue = value
- velocityLeft = this.velocity
- // avoid rounding errors and stop if anything is unconsumed
- if (abs(delta - consumed) > 0.5f) this.cancelAnimation()
- lastAnimationCycleCount++
+ )
+ try {
+ animationState.animateDecay(flingDecay) {
+ val delta = value - lastValue
+ val consumed = scrollBy(delta)
+ lastValue = value
+ velocityLeft = this.velocity
+ // avoid rounding errors and stop if anything is unconsumed
+ if (abs(delta - consumed) > 0.5f) this.cancelAnimation()
+ lastAnimationCycleCount++
+ }
+ } catch (exception: CancellationException) {
+ velocityLeft = animationState.velocity
}
velocityLeft
} else {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationState.kt
index 8df5998..ea6faa7 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationState.kt
@@ -17,10 +17,10 @@
package androidx.compose.foundation.gestures
import androidx.compose.animation.core.AnimationConstants.UnspecifiedTime
+import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.AnimationState
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.animation.core.VectorConverter
-import androidx.compose.animation.core.spring
import androidx.compose.runtime.withFrameNanos
import androidx.compose.ui.MotionDurationScale
import kotlin.contracts.ExperimentalContracts
@@ -48,8 +48,9 @@
* update the value, which makes for a more convenient API for this particular use case, and makes
* it cheaper to update [value] on every frame.
*/
-internal class UpdatableAnimationState {
+internal class UpdatableAnimationState(animationSpec: AnimationSpec<Float>) {
+ private val vectorizedSpec = animationSpec.vectorize(Float.VectorConverter)
private var lastFrameTime = UnspecifiedTime
private var lastVelocity = ZeroVector
private var isRunning = false
@@ -106,7 +107,7 @@
val playTime = if (durationScale == 0f) {
// The duration scale will be 0 when animations are disabled via a11y
// settings or developer settings.
- RebasableAnimationSpec.getDurationNanos(
+ vectorizedSpec.getDurationNanos(
initialValue = AnimationVector1D(value),
targetValue = ZeroVector,
initialVelocity = lastVelocity
@@ -114,13 +115,13 @@
} else {
((frameTime - lastFrameTime) / durationScale).roundToLong()
}
- val newValue = RebasableAnimationSpec.getValueFromNanos(
+ val newValue = vectorizedSpec.getValueFromNanos(
playTimeNanos = playTime,
initialValue = vectorizedCurrentValue,
targetValue = ZeroVector,
initialVelocity = lastVelocity
).value
- lastVelocity = RebasableAnimationSpec.getVelocityFromNanos(
+ lastVelocity = vectorizedSpec.getVelocityFromNanos(
playTimeNanos = playTime,
initialValue = vectorizedCurrentValue,
targetValue = ZeroVector,
@@ -163,12 +164,6 @@
const val VisibilityThreshold = 0.01f
val ZeroVector = AnimationVector1D(0f)
- /**
- * Only the spring spec actually supports the way this class runs the animation, so we
- * don't allow other specs to be passed in.
- */
- val RebasableAnimationSpec = spring<Float>().vectorize(Float.VectorConverter)
-
fun Float.isZeroish() = absoluteValue < VisibilityThreshold
}
}
\ No newline at end of file
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 05949c7..27b1d40 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
@@ -38,6 +38,7 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntOffset
@@ -75,12 +76,12 @@
/** The content of the list */
content: LazyListScope.() -> Unit
) {
- val itemProvider = rememberLazyListItemProvider(state, content)
+ val itemProviderLambda = rememberLazyListItemProviderLambda(state, content)
val semanticState = rememberLazyListSemanticState(state, isVertical)
val measurePolicy = rememberLazyListMeasurePolicy(
- itemProvider,
+ itemProviderLambda,
state,
contentPadding,
reverseLayout,
@@ -92,7 +93,7 @@
verticalArrangement
)
- ScrollPositionUpdater(itemProvider, state)
+ ScrollPositionUpdater(itemProviderLambda, state)
val overscrollEffect = ScrollableDefaults.overscrollEffect()
val orientation = if (isVertical) Orientation.Vertical else Orientation.Horizontal
@@ -101,7 +102,7 @@
.then(state.remeasurementModifier)
.then(state.awaitLayoutModifier)
.lazyLayoutSemantics(
- itemProvider = itemProvider,
+ itemProviderLambda = itemProviderLambda,
state = semanticState,
orientation = orientation,
userScrollEnabled = userScrollEnabled,
@@ -130,7 +131,7 @@
),
prefetchState = state.prefetchState,
measurePolicy = measurePolicy,
- itemProvider = itemProvider
+ itemProvider = itemProviderLambda
)
}
@@ -138,9 +139,10 @@
@ExperimentalFoundationApi
@Composable
private fun ScrollPositionUpdater(
- itemProvider: LazyListItemProvider,
+ itemProviderLambda: () -> LazyListItemProvider,
state: LazyListState
) {
+ val itemProvider = itemProviderLambda()
if (itemProvider.itemCount > 0) {
state.updateScrollPositionIfTheFirstItemWasMoved(itemProvider)
}
@@ -150,7 +152,7 @@
@Composable
private fun rememberLazyListMeasurePolicy(
/** Items provider of the list. */
- itemProvider: LazyListItemProvider,
+ itemProviderLambda: () -> LazyListItemProvider,
/** The state of the list. */
state: LazyListState,
/** The inner padding to be added for the whole content(nor for each individual item) */
@@ -216,11 +218,10 @@
val contentConstraints =
containerConstraints.offset(-totalHorizontalPadding, -totalVerticalPadding)
- state.updateScrollPositionIfTheFirstItemWasMoved(itemProvider)
-
// Update the state's cached Density
state.density = this
+ val itemProvider = itemProviderLambda()
// this will update the scope used by the item composables
itemProvider.itemScope.setMaxSize(
width = contentConstraints.maxWidth,
@@ -254,37 +255,46 @@
)
}
- val measuredItemProvider = LazyListMeasuredItemProvider(
+ val measuredItemProvider = object : LazyListMeasuredItemProvider(
contentConstraints,
isVertical,
itemProvider,
this
- ) { index, key, contentType, placeables ->
- // we add spaceBetweenItems as an extra spacing for all items apart from the last one so
- // the lazy list measuring logic will take it into account.
- val spacing = if (index == itemsCount - 1) 0 else spaceBetweenItems
- LazyListMeasuredItem(
- index = index,
- placeables = placeables,
- isVertical = isVertical,
- horizontalAlignment = horizontalAlignment,
- verticalAlignment = verticalAlignment,
- layoutDirection = layoutDirection,
- reverseLayout = reverseLayout,
- beforeContentPadding = beforeContentPadding,
- afterContentPadding = afterContentPadding,
- spacing = spacing,
- visualOffset = visualItemOffset,
- key = key,
- contentType = contentType
- )
+ ) {
+ override fun createItem(
+ index: Int,
+ key: Any,
+ contentType: Any?,
+ placeables: List<Placeable>
+ ): LazyListMeasuredItem {
+ // we add spaceBetweenItems as an extra spacing for all items apart from the last one so
+ // the lazy list measuring logic will take it into account.
+ val spacing = if (index == itemsCount - 1) 0 else spaceBetweenItems
+ return LazyListMeasuredItem(
+ index = index,
+ placeables = placeables,
+ isVertical = isVertical,
+ horizontalAlignment = horizontalAlignment,
+ verticalAlignment = verticalAlignment,
+ layoutDirection = layoutDirection,
+ reverseLayout = reverseLayout,
+ beforeContentPadding = beforeContentPadding,
+ afterContentPadding = afterContentPadding,
+ spacing = spacing,
+ visualOffset = visualItemOffset,
+ key = key,
+ contentType = contentType
+ )
+ }
}
state.premeasureConstraints = measuredItemProvider.childConstraints
val firstVisibleItemIndex: Int
val firstVisibleScrollOffset: Int
Snapshot.withoutReadObservation {
- firstVisibleItemIndex = state.firstVisibleItemIndex
+ firstVisibleItemIndex = state.updateScrollPositionIfTheFirstItemWasMoved(
+ itemProvider, state.firstVisibleItemIndex
+ )
firstVisibleScrollOffset = state.firstVisibleItemScrollOffset
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListHeaders.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListHeaders.kt
index 978d3a8..8cf55e5f 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListHeaders.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListHeaders.kt
@@ -28,13 +28,13 @@
* @param beforeContentPadding the padding before the first item in the list
*/
internal fun findOrComposeLazyListHeader(
- composedVisibleItems: MutableList<LazyListPositionedItem>,
+ composedVisibleItems: MutableList<LazyListMeasuredItem>,
itemProvider: LazyListMeasuredItemProvider,
headerIndexes: List<Int>,
beforeContentPadding: Int,
layoutWidth: Int,
layoutHeight: Int,
-): LazyListPositionedItem? {
+): LazyListMeasuredItem? {
var currentHeaderOffset: Int = Int.MIN_VALUE
var nextHeaderOffset: Int = Int.MIN_VALUE
@@ -83,11 +83,11 @@
headerOffset = minOf(headerOffset, nextHeaderOffset - measuredHeaderItem.size)
}
- return measuredHeaderItem.position(headerOffset, layoutWidth, layoutHeight).also {
- if (indexInComposedVisibleItems != -1) {
- composedVisibleItems[indexInComposedVisibleItems] = it
- } else {
- composedVisibleItems.add(0, it)
- }
+ measuredHeaderItem.position(headerOffset, layoutWidth, layoutHeight)
+ if (indexInComposedVisibleItems != -1) {
+ composedVisibleItems[indexInComposedVisibleItems] = measuredHeaderItem
+ } else {
+ composedVisibleItems.add(0, measuredHeaderItem)
}
+ return measuredHeaderItem
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemPlacementAnimator.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemPlacementAnimator.kt
index 497ba6d..ec0fb82 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemPlacementAnimator.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemPlacementAnimator.kt
@@ -40,8 +40,8 @@
// stored to not allocate it every pass.
private val movingAwayKeys = LinkedHashSet<Any>()
- private val movingInFromStartBound = mutableListOf<LazyListPositionedItem>()
- private val movingInFromEndBound = mutableListOf<LazyListPositionedItem>()
+ private val movingInFromStartBound = mutableListOf<LazyListMeasuredItem>()
+ private val movingInFromEndBound = mutableListOf<LazyListMeasuredItem>()
private val movingAwayToStartBound = mutableListOf<LazyListMeasuredItem>()
private val movingAwayToEndBound = mutableListOf<LazyListMeasuredItem>()
@@ -54,7 +54,7 @@
consumedScroll: Int,
layoutWidth: Int,
layoutHeight: Int,
- positionedItems: MutableList<LazyListPositionedItem>,
+ positionedItems: MutableList<LazyListMeasuredItem>,
itemProvider: LazyListMeasuredItemProvider,
isVertical: Boolean
) {
@@ -167,9 +167,9 @@
accumulatedOffset += item.size
val mainAxisOffset = 0 - accumulatedOffset
- val positionedItem = item.position(mainAxisOffset, layoutWidth, layoutHeight)
- positionedItems.add(positionedItem)
- startAnimationsIfNeeded(positionedItem)
+ item.position(mainAxisOffset, layoutWidth, layoutHeight)
+ positionedItems.add(item)
+ startAnimationsIfNeeded(item)
}
accumulatedOffset = 0
movingAwayToEndBound.sortBy { keyIndexMap.getIndex(it.key) }
@@ -177,9 +177,9 @@
val mainAxisOffset = mainAxisLayoutSize + accumulatedOffset
accumulatedOffset += item.size
- val positionedItem = item.position(mainAxisOffset, layoutWidth, layoutHeight)
- positionedItems.add(positionedItem)
- startAnimationsIfNeeded(positionedItem)
+ item.position(mainAxisOffset, layoutWidth, layoutHeight)
+ positionedItems.add(item)
+ startAnimationsIfNeeded(item)
}
movingInFromStartBound.clear()
@@ -200,7 +200,7 @@
}
private fun initializeNode(
- item: LazyListPositionedItem,
+ item: LazyListMeasuredItem,
mainAxisOffset: Int
) {
val firstPlaceableOffset = item.getOffset(0)
@@ -219,7 +219,7 @@
}
}
- private fun startAnimationsIfNeeded(item: LazyListPositionedItem) {
+ private fun startAnimationsIfNeeded(item: LazyListMeasuredItem) {
item.forEachNode { placeableIndex, node ->
val newTarget = item.getOffset(placeableIndex)
val currentTarget = node.rawOffset
@@ -234,13 +234,13 @@
private val Any?.node get() = this as? LazyLayoutAnimateItemModifierNode
- private val LazyListPositionedItem.hasAnimations: Boolean
+ private val LazyListMeasuredItem.hasAnimations: Boolean
get() {
forEachNode { _, _ -> return true }
return false
}
- private inline fun LazyListPositionedItem.forEachNode(
+ private inline fun LazyListMeasuredItem.forEachNode(
block: (placeableIndex: Int, node: LazyLayoutAnimateItemModifierNode) -> Unit
) {
repeat(placeablesCount) { index ->
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemProvider.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemProvider.kt
index 1a5eb66..ae95eb2 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemProvider.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemProvider.kt
@@ -20,10 +20,9 @@
import androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider
import androidx.compose.foundation.lazy.layout.LazyLayoutKeyIndexMap
import androidx.compose.foundation.lazy.layout.LazyLayoutPinnableItem
-import androidx.compose.foundation.lazy.layout.NearestRangeKeyIndexMapState
+import androidx.compose.foundation.lazy.layout.NearestRangeKeyIndexMap
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.referentialEqualityPolicy
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
@@ -39,64 +38,68 @@
@OptIn(ExperimentalFoundationApi::class)
@Composable
-internal fun rememberLazyListItemProvider(
+internal fun rememberLazyListItemProviderLambda(
state: LazyListState,
content: LazyListScope.() -> Unit
-): LazyListItemProvider {
+): () -> LazyListItemProvider {
val latestContent = rememberUpdatedState(content)
- return remember(state, latestContent) {
- LazyListItemProviderImpl(
- state = state,
- latestContent = { latestContent.value },
- itemScope = LazyItemScopeImpl()
- )
+ return remember(state) {
+ val scope = LazyItemScopeImpl()
+ val intervalContentState = derivedStateOf(referentialEqualityPolicy()) {
+ LazyListIntervalContent(latestContent.value)
+ }
+ val itemProviderState = derivedStateOf(referentialEqualityPolicy()) {
+ val intervalContent = intervalContentState.value
+ val map = NearestRangeKeyIndexMap(state.nearestRange, intervalContent)
+ LazyListItemProviderImpl(
+ state = state,
+ intervalContent = intervalContent,
+ itemScope = scope,
+ keyIndexMap = map
+ )
+ }
+ itemProviderState::value
}
}
@ExperimentalFoundationApi
private class LazyListItemProviderImpl constructor(
private val state: LazyListState,
- private val latestContent: () -> (LazyListScope.() -> Unit),
- override val itemScope: LazyItemScopeImpl
+ private val intervalContent: LazyListIntervalContent,
+ override val itemScope: LazyItemScopeImpl,
+ override val keyIndexMap: LazyLayoutKeyIndexMap,
) : LazyListItemProvider {
- private val listContent by derivedStateOf(referentialEqualityPolicy()) {
- LazyListIntervalContent(latestContent())
- }
- override val itemCount: Int get() = listContent.itemCount
+ override val itemCount: Int get() = intervalContent.itemCount
@Composable
override fun Item(index: Int, key: Any) {
LazyLayoutPinnableItem(key, index, state.pinnedItems) {
- listContent.withInterval(index) { localIndex, content ->
+ intervalContent.withInterval(index) { localIndex, content ->
content.item(itemScope, localIndex)
}
}
}
- override fun getKey(index: Int): Any = keyIndexMap.getKey(index) ?: listContent.getKey(index)
+ override fun getKey(index: Int): Any =
+ keyIndexMap.getKey(index) ?: intervalContent.getKey(index)
- override fun getContentType(index: Int): Any? = listContent.getContentType(index)
+ override fun getContentType(index: Int): Any? = intervalContent.getContentType(index)
- override val headerIndexes: List<Int> get() = listContent.headerIndexes
-
- override val keyIndexMap by NearestRangeKeyIndexMapState(
- firstVisibleItemIndex = { state.firstVisibleItemIndex },
- slidingWindowSize = { NearestItemsSlidingWindowSize },
- extraItemCount = { NearestItemsExtraItemCount },
- content = { listContent }
- )
+ override val headerIndexes: List<Int> get() = intervalContent.headerIndexes
override fun getIndex(key: Any): Int = keyIndexMap.getIndex(key)
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is LazyListItemProviderImpl) return false
+
+ // the identity of this class is represented by intervalContent object.
+ // having equals() allows us to skip items recomposition when intervalContent didn't change
+ return intervalContent == other.intervalContent
+ }
+
+ override fun hashCode(): Int {
+ return intervalContent.hashCode()
+ }
}
-
-/**
- * We use the idea of sliding window as an optimization, so user can scroll up to this number of
- * items until we have to regenerate the key to index map.
- */
-internal const val NearestItemsSlidingWindowSize = 30
-
-/**
- * The minimum amount of items near the current first visible item we want to have mapping for.
- */
-internal const val NearestItemsExtraItemCount = 100
\ No newline at end of file
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 c247a1d..7b4d920 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
@@ -102,7 +102,7 @@
}
// this will contain all the MeasuredItems representing the visible items
- val visibleItems = mutableListOf<LazyListMeasuredItem>()
+ val visibleItems = ArrayDeque<LazyListMeasuredItem>()
// define min and max offsets
val minOffset = -beforeContentPadding + if (spaceBetweenItems < 0) spaceBetweenItems else 0
@@ -403,7 +403,7 @@
horizontalArrangement: Arrangement.Horizontal?,
reverseLayout: Boolean,
density: Density,
-): MutableList<LazyListPositionedItem> {
+): MutableList<LazyListMeasuredItem> {
val mainAxisLayoutSize = if (isVertical) layoutHeight else layoutWidth
val hasSpareSpace = finalMainAxisOffset < minOf(mainAxisLayoutSize, maxOffset)
if (hasSpareSpace) {
@@ -411,7 +411,7 @@
}
val positionedItems =
- ArrayList<LazyListPositionedItem>(items.size + extraItemsBefore.size + extraItemsAfter.size)
+ ArrayList<LazyListMeasuredItem>(items.size + extraItemsBefore.size + extraItemsAfter.size)
if (hasSpareSpace) {
require(extraItemsBefore.isEmpty() && extraItemsAfter.isEmpty())
@@ -447,29 +447,29 @@
} else {
absoluteOffset
}
- positionedItems.add(item.position(relativeOffset, layoutWidth, layoutHeight))
+ item.position(relativeOffset, layoutWidth, layoutHeight)
+ positionedItems.add(item)
}
} else {
var currentMainAxis = itemsScrollOffset
extraItemsBefore.fastForEach {
currentMainAxis -= it.sizeWithSpacings
- positionedItems.add(it.position(currentMainAxis, layoutWidth, layoutHeight))
+ it.position(currentMainAxis, layoutWidth, layoutHeight)
+ positionedItems.add(it)
}
currentMainAxis = itemsScrollOffset
items.fastForEach {
- positionedItems.add(it.position(currentMainAxis, layoutWidth, layoutHeight))
+ it.position(currentMainAxis, layoutWidth, layoutHeight)
+ positionedItems.add(it)
currentMainAxis += it.sizeWithSpacings
}
extraItemsAfter.fastForEach {
- positionedItems.add(it.position(currentMainAxis, layoutWidth, layoutHeight))
+ it.position(currentMainAxis, layoutWidth, layoutHeight)
+ positionedItems.add(it)
currentMainAxis += it.sizeWithSpacings
}
}
return positionedItems
}
-
-private val EmptyRange = Int.MIN_VALUE to Int.MIN_VALUE
-private val Int.notInEmptyRange
- get() = this != Int.MIN_VALUE
\ No newline at end of file
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 0c4b130..5fb7dc9 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
@@ -23,15 +23,16 @@
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.util.fastForEach
+import androidx.compose.ui.util.fastForEachIndexed
/**
* Represents one measured item of the lazy list. It can in fact consist of multiple placeables
* if the user emit multiple layout nodes in the item callback.
*/
internal class LazyListMeasuredItem @ExperimentalFoundationApi constructor(
- val index: Int,
+ override val index: Int,
private val placeables: List<Placeable>,
- private val isVertical: Boolean,
+ val isVertical: Boolean,
private val horizontalAlignment: Alignment.Horizontal?,
private val verticalAlignment: Alignment.Vertical?,
private val layoutDirection: LayoutDirection,
@@ -48,13 +49,16 @@
* value passed into the place() call.
*/
private val visualOffset: IntOffset,
- val key: Any,
- private val contentType: Any?
-) {
+ override val key: Any,
+ override val contentType: Any?
+) : LazyListItemInfo {
+ override var offset: Int = 0
+ private set
+
/**
* Sum of the main axis sizes of all the inner placeables.
*/
- val size: Int
+ override val size: Int
/**
* Sum of the main axis sizes of all the inner placeables and [spacing].
@@ -66,6 +70,14 @@
*/
val crossAxisSize: Int
+ private var mainAxisLayoutSize: Int = Unset
+ private var minMainAxisOffset: Int = 0
+ private var maxMainAxisOffset: Int = 0
+
+ // optimized for storing x and y offsets for each placeable one by one.
+ // array's size == placeables.size * 2, first we store x, then y.
+ private val placeableOffsets: IntArray
+
init {
var mainAxisSize = 0
var maxCrossAxis = 0
@@ -76,6 +88,7 @@
size = mainAxisSize
sizeWithSpacings = (size + spacing).coerceAtLeast(0)
crossAxisSize = maxCrossAxis
+ placeableOffsets = IntArray(placeables.size * 2)
}
val placeablesCount: Int get() = placeables.size
@@ -90,64 +103,37 @@
offset: Int,
layoutWidth: Int,
layoutHeight: Int
- ): LazyListPositionedItem {
- val wrappers = mutableListOf<LazyListPlaceableWrapper>()
- val mainAxisLayoutSize = if (isVertical) layoutHeight else layoutWidth
+ ) {
+ this.offset = offset
+ mainAxisLayoutSize = if (isVertical) layoutHeight else layoutWidth
var mainAxisOffset = offset
- placeables.fastForEach {
- val placeableOffset = if (isVertical) {
- val x = requireNotNull(horizontalAlignment)
- .align(it.width, layoutWidth, layoutDirection)
- IntOffset(x, mainAxisOffset)
+ placeables.fastForEachIndexed { index, placeable ->
+ val indexInArray = index * 2
+ if (isVertical) {
+ placeableOffsets[indexInArray] = requireNotNull(horizontalAlignment)
+ .align(placeable.width, layoutWidth, layoutDirection)
+ placeableOffsets[indexInArray + 1] = mainAxisOffset
+ mainAxisOffset += placeable.height
} else {
- val y = requireNotNull(verticalAlignment).align(it.height, layoutHeight)
- IntOffset(mainAxisOffset, y)
+ placeableOffsets[indexInArray] = mainAxisOffset
+ placeableOffsets[indexInArray + 1] = requireNotNull(verticalAlignment)
+ .align(placeable.height, layoutHeight)
+ mainAxisOffset += placeable.width
}
- mainAxisOffset += if (isVertical) it.height else it.width
- wrappers.add(LazyListPlaceableWrapper(placeableOffset, it))
}
- return LazyListPositionedItem(
- offset = offset,
- index = this.index,
- key = key,
- size = size,
- minMainAxisOffset = -beforeContentPadding,
- maxMainAxisOffset = mainAxisLayoutSize + afterContentPadding,
- isVertical = isVertical,
- wrappers = wrappers,
- visualOffset = visualOffset,
- reverseLayout = reverseLayout,
- mainAxisLayoutSize = mainAxisLayoutSize,
- contentType = contentType
- )
+ minMainAxisOffset = -beforeContentPadding
+ maxMainAxisOffset = mainAxisLayoutSize + afterContentPadding
}
-}
-internal class LazyListPositionedItem(
- override val offset: Int,
- override val index: Int,
- override val key: Any,
- override val size: Int,
- private val minMainAxisOffset: Int,
- private val maxMainAxisOffset: Int,
- val isVertical: Boolean,
- private val wrappers: List<LazyListPlaceableWrapper>,
- private val visualOffset: IntOffset,
- private val reverseLayout: Boolean,
- private val mainAxisLayoutSize: Int,
- override val contentType: Any?
-) : LazyListItemInfo {
- val placeablesCount: Int get() = wrappers.size
-
- fun getOffset(index: Int) = wrappers[index].offset
-
- fun getParentData(index: Int) = wrappers[index].placeable.parentData
+ fun getOffset(index: Int) =
+ IntOffset(placeableOffsets[index * 2], placeableOffsets[index * 2 + 1])
fun place(
scope: Placeable.PlacementScope,
) = with(scope) {
+ require(mainAxisLayoutSize != Unset) { "position() should be called first" }
repeat(placeablesCount) { index ->
- val placeable = wrappers[index].placeable
+ val placeable = placeables[index]
val minOffset = minMainAxisOffset - placeable.mainAxisSize
val maxOffset = maxMainAxisOffset
var offset = getOffset(index)
@@ -182,7 +168,4 @@
IntOffset(if (isVertical) x else mainAxisMap(x), if (isVertical) mainAxisMap(y) else y)
}
-internal class LazyListPlaceableWrapper(
- val offset: IntOffset,
- val placeable: Placeable
-)
+private const val Unset = Int.MIN_VALUE
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItemProvider.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItemProvider.kt
index 77ec076..d983cd7 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItemProvider.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItemProvider.kt
@@ -26,12 +26,11 @@
* Abstracts away the subcomposition from the measuring logic.
*/
@OptIn(ExperimentalFoundationApi::class)
-internal class LazyListMeasuredItemProvider @ExperimentalFoundationApi constructor(
+internal abstract class LazyListMeasuredItemProvider @ExperimentalFoundationApi constructor(
constraints: Constraints,
isVertical: Boolean,
private val itemProvider: LazyListItemProvider,
- private val measureScope: LazyLayoutMeasureScope,
- private val measuredItemFactory: MeasuredItemFactory
+ private val measureScope: LazyLayoutMeasureScope
) {
// the constraints we will measure child with. the main axis is not restricted
val childConstraints = Constraints(
@@ -44,22 +43,19 @@
* correct constraints and wrapped into [LazyListMeasuredItem].
*/
fun getAndMeasure(index: Int): LazyListMeasuredItem {
- val key = keyIndexMap.getKey(index) ?: itemProvider.getKey(index)
+ val key = itemProvider.getKey(index)
val contentType = itemProvider.getContentType(index)
val placeables = measureScope.measure(index, childConstraints)
- return measuredItemFactory.createItem(index, key, contentType, placeables)
+ return createItem(index, key, contentType, placeables)
}
/**
* Contains the mapping between the key and the index. It could contain not all the items of
* the list as an optimization.
**/
- val keyIndexMap: LazyLayoutKeyIndexMap = itemProvider.keyIndexMap
-}
+ val keyIndexMap: LazyLayoutKeyIndexMap get() = itemProvider.keyIndexMap
-// This interface allows to avoid autoboxing on index param
-internal fun interface MeasuredItemFactory {
- fun createItem(
+ abstract fun createItem(
index: Int,
key: Any,
contentType: Any?,
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListScrollPosition.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListScrollPosition.kt
index 16eb1c7..44eade1 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListScrollPosition.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListScrollPosition.kt
@@ -17,11 +17,11 @@
package androidx.compose.foundation.lazy
import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.lazy.layout.LazyLayoutNearestRangeState
import androidx.compose.foundation.lazy.layout.findIndexByKey
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.setValue
-import androidx.compose.runtime.snapshots.Snapshot
/**
* Contains the current scroll position represented by the first visible item index and the first
@@ -41,6 +41,12 @@
/** The last know key of the item at [index] position. */
private var lastKnownFirstItemKey: Any? = null
+ val nearestRangeState = LazyLayoutNearestRangeState(
+ initialIndex,
+ NearestItemsSlidingWindowSize,
+ NearestItemsExtraItemCount
+ )
+
/**
* Updates the current scroll position based on the results of the last measurement.
*/
@@ -54,12 +60,8 @@
val scrollOffset = measureResult.firstVisibleItemScrollOffset
check(scrollOffset >= 0f) { "scrollOffset should be non-negative ($scrollOffset)" }
- Snapshot.withoutReadObservation {
- update(
- measureResult.firstVisibleItem?.index ?: 0,
- scrollOffset
- )
- }
+ val firstIndex = measureResult.firstVisibleItem?.index ?: 0
+ update(firstIndex, scrollOffset)
}
}
@@ -88,22 +90,33 @@
* as the first visible one even given that its index has been changed.
*/
@ExperimentalFoundationApi
- fun updateScrollPositionIfTheFirstItemWasMoved(itemProvider: LazyListItemProvider) {
- Snapshot.withoutReadObservation {
- update(
- itemProvider.findIndexByKey(lastKnownFirstItemKey, index),
- scrollOffset
- )
+ fun updateScrollPositionIfTheFirstItemWasMoved(
+ itemProvider: LazyListItemProvider,
+ index: Int
+ ): Int {
+ val newIndex = itemProvider.findIndexByKey(lastKnownFirstItemKey, index)
+ if (index != newIndex) {
+ this.index = newIndex
+ nearestRangeState.update(index)
}
+ return newIndex
}
private fun update(index: Int, scrollOffset: Int) {
require(index >= 0f) { "Index should be non-negative ($index)" }
- if (index != this.index) {
- this.index = index
- }
- if (scrollOffset != this.scrollOffset) {
- this.scrollOffset = scrollOffset
- }
+ this.index = index
+ nearestRangeState.update(index)
+ this.scrollOffset = scrollOffset
}
}
+
+/**
+ * We use the idea of sliding window as an optimization, so user can scroll up to this number of
+ * items until we have to regenerate the key to index map.
+ */
+internal const val NearestItemsSlidingWindowSize = 30
+
+/**
+ * The minimum amount of items near the current first visible item we want to have mapping for.
+ */
+internal const val NearestItemsExtraItemCount = 100
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListState.kt
index 3bd36be..1d2cf7a 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListState.kt
@@ -36,6 +36,7 @@
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.ui.layout.Remeasurement
import androidx.compose.ui.layout.RemeasurementModifier
import androidx.compose.ui.unit.Constraints
@@ -152,7 +153,7 @@
/**
* Needed for [animateScrollToItem]. Updated on every measure.
*/
- internal var density: Density by mutableStateOf(Density(1f, 1f))
+ internal var density: Density = Density(1f, 1f)
/**
* The ScrollableController instance. We keep it as we need to call stopAnimation on it once
@@ -193,7 +194,7 @@
* The [Remeasurement] object associated with our layout. It allows us to remeasure
* synchronously during scroll.
*/
- internal var remeasurement: Remeasurement? by mutableStateOf(null)
+ internal var remeasurement: Remeasurement? = null
private set
/**
@@ -218,13 +219,15 @@
/**
* Constraints passed to the prefetcher for premeasuring the prefetched items.
*/
- internal var premeasureConstraints by mutableStateOf(Constraints())
+ internal var premeasureConstraints = Constraints()
/**
* Stores currently pinned items which are always composed.
*/
internal val pinnedItems = LazyLayoutPinnedItemList()
+ internal val nearestRange: IntRange by scrollPosition.nearestRangeState
+
/**
* Instantly brings the item at [index] to the top of the viewport, offset by [scrollOffset]
* pixels.
@@ -401,9 +404,10 @@
* items added or removed before our current first visible item and keep this item
* as the first visible one even given that its index has been changed.
*/
- internal fun updateScrollPositionIfTheFirstItemWasMoved(itemProvider: LazyListItemProvider) {
- scrollPosition.updateScrollPositionIfTheFirstItemWasMoved(itemProvider)
- }
+ internal fun updateScrollPositionIfTheFirstItemWasMoved(
+ itemProvider: LazyListItemProvider,
+ firstItemIndex: Int = Snapshot.withoutReadObservation { scrollPosition.index }
+ ): Int = scrollPosition.updateScrollPositionIfTheFirstItemWasMoved(itemProvider, firstItemIndex)
companion object {
/**
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 4f84478..385b153 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
@@ -37,6 +37,7 @@
import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Density
@@ -75,12 +76,12 @@
) {
val overscrollEffect = ScrollableDefaults.overscrollEffect()
- val itemProvider = rememberLazyGridItemProvider(state, content)
+ val itemProviderLambda = rememberLazyGridItemProviderLambda(state, content)
val semanticState = rememberLazyGridSemanticState(state, reverseLayout)
val measurePolicy = rememberLazyGridMeasurePolicy(
- itemProvider,
+ itemProviderLambda,
state,
slots,
contentPadding,
@@ -92,7 +93,7 @@
state.isVertical = isVertical
- ScrollPositionUpdater(itemProvider, state)
+ ScrollPositionUpdater(itemProviderLambda, state)
val orientation = if (isVertical) Orientation.Vertical else Orientation.Horizontal
LazyLayout(
@@ -100,7 +101,7 @@
.then(state.remeasurementModifier)
.then(state.awaitLayoutModifier)
.lazyLayoutSemantics(
- itemProvider = itemProvider,
+ itemProviderLambda = itemProviderLambda,
state = semanticState,
orientation = orientation,
userScrollEnabled = userScrollEnabled,
@@ -128,7 +129,7 @@
),
prefetchState = state.prefetchState,
measurePolicy = measurePolicy,
- itemProvider = itemProvider
+ itemProvider = itemProviderLambda
)
}
@@ -136,9 +137,10 @@
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun ScrollPositionUpdater(
- itemProvider: LazyGridItemProvider,
+ itemProviderLambda: () -> LazyGridItemProvider,
state: LazyGridState
) {
+ val itemProvider = itemProviderLambda()
if (itemProvider.itemCount > 0) {
state.updateScrollPositionIfTheFirstItemWasMoved(itemProvider)
}
@@ -154,7 +156,7 @@
@Composable
private fun rememberLazyGridMeasurePolicy(
/** Items provider of the list. */
- itemProvider: LazyGridItemProvider,
+ itemProviderLambda: () -> LazyGridItemProvider,
/** The state of the list. */
state: LazyGridState,
/** Prefix sums of cross axis sizes of slots of the grid. */
@@ -215,8 +217,7 @@
val contentConstraints =
containerConstraints.offset(-totalHorizontalPadding, -totalVerticalPadding)
- state.updateScrollPositionIfTheFirstItemWasMoved(itemProvider)
-
+ val itemProvider = itemProviderLambda()
val spanLayoutProvider = itemProvider.spanLayoutProvider
val resolvedSlots = slots(containerConstraints)
val slotsPerLine = resolvedSlots.sizes.size
@@ -252,12 +253,19 @@
)
}
- val measuredItemProvider = LazyGridMeasuredItemProvider(
+ val measuredItemProvider = object : LazyGridMeasuredItemProvider(
itemProvider,
this,
spaceBetweenLines
- ) { index, key, contentType, crossAxisSize, mainAxisSpacing, placeables ->
- LazyGridMeasuredItem(
+ ) {
+ override fun createItem(
+ index: Int,
+ key: Any,
+ contentType: Any?,
+ crossAxisSize: Int,
+ mainAxisSpacing: Int,
+ placeables: List<Placeable>
+ ) = LazyGridMeasuredItem(
index = index,
key = key,
isVertical = isVertical,
@@ -272,15 +280,20 @@
contentType = contentType
)
}
- val measuredLineProvider = LazyGridMeasuredLineProvider(
+ val measuredLineProvider = object : LazyGridMeasuredLineProvider(
isVertical = isVertical,
slots = resolvedSlots,
gridItemsCount = itemsCount,
spaceBetweenLines = spaceBetweenLines,
measuredItemProvider = measuredItemProvider,
spanLayoutProvider = spanLayoutProvider
- ) { index, items, spans, mainAxisSpacing ->
- LazyGridMeasuredLine(
+ ) {
+ override fun createLine(
+ index: Int,
+ items: Array<LazyGridMeasuredItem>,
+ spans: List<GridItemSpan>,
+ mainAxisSpacing: Int
+ ) = LazyGridMeasuredLine(
index = index,
items = items,
spans = spans,
@@ -307,10 +320,11 @@
val firstVisibleLineScrollOffset: Int
Snapshot.withoutReadObservation {
- if (state.firstVisibleItemIndex < itemsCount || itemsCount <= 0) {
- firstVisibleLineIndex = spanLayoutProvider.getLineIndexOfItem(
- state.firstVisibleItemIndex
- )
+ val index = state.updateScrollPositionIfTheFirstItemWasMoved(
+ itemProvider, state.firstVisibleItemIndex
+ )
+ if (index < itemsCount || itemsCount <= 0) {
+ firstVisibleLineIndex = spanLayoutProvider.getLineIndexOfItem(index)
firstVisibleLineScrollOffset = state.firstVisibleItemScrollOffset
} else {
// the data set has been updated and now we have less items that we were
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 fbd96ee..918f2a2 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
@@ -41,8 +41,8 @@
// stored to not allocate it every pass.
private val movingAwayKeys = LinkedHashSet<Any>()
- private val movingInFromStartBound = mutableListOf<LazyGridPositionedItem>()
- private val movingInFromEndBound = mutableListOf<LazyGridPositionedItem>()
+ private val movingInFromStartBound = mutableListOf<LazyGridMeasuredItem>()
+ private val movingInFromEndBound = mutableListOf<LazyGridMeasuredItem>()
private val movingAwayToStartBound = mutableListOf<LazyGridMeasuredItem>()
private val movingAwayToEndBound = mutableListOf<LazyGridMeasuredItem>()
@@ -55,7 +55,7 @@
consumedScroll: Int,
layoutWidth: Int,
layoutHeight: Int,
- positionedItems: MutableList<LazyGridPositionedItem>,
+ positionedItems: MutableList<LazyGridMeasuredItem>,
itemProvider: LazyGridMeasuredItemProvider,
spanLayoutProvider: LazyGridSpanLayoutProvider,
isVertical: Boolean
@@ -91,7 +91,7 @@
// there is no state associated with this item yet
if (itemInfo == null) {
keyToItemInfoMap[item.key] =
- ItemInfo(item.getCrossAxisSize(), item.getCrossAxisOffset())
+ ItemInfo(item.crossAxisSize, item.crossAxisOffset)
val previousIndex = previousKeyToIndexMap.getIndex(item.key)
if (previousIndex != -1 && item.index != previousIndex) {
if (previousIndex < previousFirstVisibleIndex) {
@@ -112,8 +112,8 @@
it.rawOffset += scrollOffset
}
}
- itemInfo.crossAxisSize = item.getCrossAxisSize()
- itemInfo.crossAxisOffset = item.getCrossAxisOffset()
+ itemInfo.crossAxisSize = item.crossAxisSize
+ itemInfo.crossAxisOffset = item.crossAxisOffset
startAnimationsIfNeeded(item)
}
} else {
@@ -129,13 +129,13 @@
movingInFromStartBound.fastForEach { item ->
val line = if (isVertical) item.row else item.column
if (line != -1 && line == previousLine) {
- previousLineMainAxisSize = maxOf(previousLineMainAxisSize, item.getMainAxisSize())
+ previousLineMainAxisSize = maxOf(previousLineMainAxisSize, item.mainAxisSize)
} else {
accumulatedOffset += previousLineMainAxisSize
- previousLineMainAxisSize = item.getMainAxisSize()
+ previousLineMainAxisSize = item.mainAxisSize
previousLine = line
}
- val mainAxisOffset = 0 - accumulatedOffset - item.getMainAxisSize()
+ val mainAxisOffset = 0 - accumulatedOffset - item.mainAxisSize
initializeNode(item, mainAxisOffset)
startAnimationsIfNeeded(item)
}
@@ -146,10 +146,10 @@
movingInFromEndBound.fastForEach { item ->
val line = if (isVertical) item.row else item.column
if (line != -1 && line == previousLine) {
- previousLineMainAxisSize = maxOf(previousLineMainAxisSize, item.getMainAxisSize())
+ previousLineMainAxisSize = maxOf(previousLineMainAxisSize, item.mainAxisSize)
} else {
accumulatedOffset += previousLineMainAxisSize
- previousLineMainAxisSize = item.getMainAxisSize()
+ previousLineMainAxisSize = item.mainAxisSize
previousLine = line
}
val mainAxisOffset = mainAxisLayoutSize + accumulatedOffset
@@ -211,16 +211,14 @@
val itemInfo = keyToItemInfoMap.getValue(item.key)
- val positionedItem = item.position(
- mainAxisOffset,
- itemInfo.crossAxisOffset,
- layoutWidth,
- layoutHeight,
- LazyGridItemInfo.UnknownRow,
- LazyGridItemInfo.UnknownColumn
+ item.position(
+ mainAxisOffset = mainAxisOffset,
+ crossAxisOffset = itemInfo.crossAxisOffset,
+ layoutWidth = layoutWidth,
+ layoutHeight = layoutHeight
)
- positionedItems.add(positionedItem)
- startAnimationsIfNeeded(positionedItem)
+ positionedItems.add(item)
+ startAnimationsIfNeeded(item)
}
accumulatedOffset = 0
previousLine = -1
@@ -238,17 +236,15 @@
val mainAxisOffset = mainAxisLayoutSize + accumulatedOffset
val itemInfo = keyToItemInfoMap.getValue(item.key)
- val positionedItem = item.position(
- mainAxisOffset,
- itemInfo.crossAxisOffset,
- layoutWidth,
- layoutHeight,
- LazyGridItemInfo.UnknownRow,
- LazyGridItemInfo.UnknownColumn
+ item.position(
+ mainAxisOffset = mainAxisOffset,
+ crossAxisOffset = itemInfo.crossAxisOffset,
+ layoutWidth = layoutWidth,
+ layoutHeight = layoutHeight,
)
- positionedItems.add(positionedItem)
- startAnimationsIfNeeded(positionedItem)
+ positionedItems.add(item)
+ startAnimationsIfNeeded(item)
}
movingInFromStartBound.clear()
@@ -269,7 +265,7 @@
}
private fun initializeNode(
- item: LazyGridPositionedItem,
+ item: LazyGridMeasuredItem,
mainAxisOffset: Int
) {
val firstPlaceableOffset = item.offset
@@ -288,7 +284,7 @@
}
}
- private fun startAnimationsIfNeeded(item: LazyGridPositionedItem) {
+ private fun startAnimationsIfNeeded(item: LazyGridMeasuredItem) {
item.forEachNode { node ->
val newTarget = item.offset
val currentTarget = node.rawOffset
@@ -303,13 +299,13 @@
private val Any?.node get() = this as? LazyLayoutAnimateItemModifierNode
- private val LazyGridPositionedItem.hasAnimations: Boolean
+ private val LazyGridMeasuredItem.hasAnimations: Boolean
get() {
forEachNode { return true }
return false
}
- private inline fun LazyGridPositionedItem.forEachNode(
+ private inline fun LazyGridMeasuredItem.forEachNode(
block: (LazyLayoutAnimateItemModifierNode) -> Unit
) {
repeat(placeablesCount) { index ->
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemProvider.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemProvider.kt
index 95c2af3..55d346b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemProvider.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemProvider.kt
@@ -20,10 +20,9 @@
import androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider
import androidx.compose.foundation.lazy.layout.LazyLayoutKeyIndexMap
import androidx.compose.foundation.lazy.layout.LazyLayoutPinnableItem
-import androidx.compose.foundation.lazy.layout.NearestRangeKeyIndexMapState
+import androidx.compose.foundation.lazy.layout.NearestRangeKeyIndexMap
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.referentialEqualityPolicy
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
@@ -36,63 +35,66 @@
@ExperimentalFoundationApi
@Composable
-internal fun rememberLazyGridItemProvider(
+internal fun rememberLazyGridItemProviderLambda(
state: LazyGridState,
content: LazyGridScope.() -> Unit,
-): LazyGridItemProvider {
+): () -> LazyGridItemProvider {
val latestContent = rememberUpdatedState(content)
return remember(state) {
- LazyGridItemProviderImpl(
- state,
- { latestContent.value },
- )
+ val intervalContentState = derivedStateOf(referentialEqualityPolicy()) {
+ LazyGridIntervalContent(latestContent.value)
+ }
+ val itemProviderState = derivedStateOf(referentialEqualityPolicy()) {
+ val intervalContent = intervalContentState.value
+ val map = NearestRangeKeyIndexMap(state.nearestRange, intervalContent)
+ LazyGridItemProviderImpl(
+ state = state,
+ intervalContent = intervalContent,
+ keyIndexMap = map
+ )
+ }
+ itemProviderState::value
}
}
@ExperimentalFoundationApi
private class LazyGridItemProviderImpl(
private val state: LazyGridState,
- private val latestContent: () -> (LazyGridScope.() -> Unit)
+ private val intervalContent: LazyGridIntervalContent,
+ override val keyIndexMap: LazyLayoutKeyIndexMap,
) : LazyGridItemProvider {
- private val gridContent by derivedStateOf(referentialEqualityPolicy()) {
- LazyGridIntervalContent(latestContent())
- }
- override val keyIndexMap: LazyLayoutKeyIndexMap by NearestRangeKeyIndexMapState(
- firstVisibleItemIndex = { state.firstVisibleItemIndex },
- slidingWindowSize = { NearestItemsSlidingWindowSize },
- extraItemCount = { NearestItemsExtraItemCount },
- content = { gridContent }
- )
+ override val itemCount: Int get() = intervalContent.itemCount
- override val itemCount: Int get() = gridContent.itemCount
+ override fun getKey(index: Int): Any =
+ keyIndexMap.getKey(index) ?: intervalContent.getKey(index)
- override fun getKey(index: Int): Any = keyIndexMap.getKey(index) ?: gridContent.getKey(index)
-
- override fun getContentType(index: Int): Any? = gridContent.getContentType(index)
+ override fun getContentType(index: Int): Any? = intervalContent.getContentType(index)
@Composable
override fun Item(index: Int, key: Any) {
LazyLayoutPinnableItem(key, index, state.pinnedItems) {
- gridContent.withInterval(index) { localIndex, content ->
+ intervalContent.withInterval(index) { localIndex, content ->
content.item(LazyGridItemScopeImpl, localIndex)
}
}
}
override val spanLayoutProvider: LazyGridSpanLayoutProvider
- get() = gridContent.spanLayoutProvider
+ get() = intervalContent.spanLayoutProvider
override fun getIndex(key: Any): Int = keyIndexMap.getIndex(key)
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is LazyGridItemProviderImpl) return false
+
+ // the identity of this class is represented by intervalContent object.
+ // having equals() allows us to skip items recomposition when intervalContent didn't change
+ return intervalContent == other.intervalContent
+ }
+
+ override fun hashCode(): Int {
+ return intervalContent.hashCode()
+ }
}
-
-/**
- * We use the idea of sliding window as an optimization, so user can scroll up to this number of
- * items until we have to regenerate the key to index map.
- */
-private const val NearestItemsSlidingWindowSize = 90
-
-/**
- * The minimum amount of items near the current first visible item we want to have mapping for.
- */
-private const val NearestItemsExtraItemCount = 200
\ No newline at end of file
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 d5fa3ec..b925889 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
@@ -98,7 +98,7 @@
}
// this will contain all the MeasuredItems representing the visible lines
- val visibleLines = mutableListOf<LazyGridMeasuredLine>()
+ val visibleLines = ArrayDeque<LazyGridMeasuredLine>()
// define min and max offsets
val minOffset = -beforeContentPadding + if (spaceBetweenLines < 0) spaceBetweenLines else 0
@@ -343,14 +343,14 @@
horizontalArrangement: Arrangement.Horizontal?,
reverseLayout: Boolean,
density: Density,
-): MutableList<LazyGridPositionedItem> {
+): MutableList<LazyGridMeasuredItem> {
val mainAxisLayoutSize = if (isVertical) layoutHeight else layoutWidth
val hasSpareSpace = finalMainAxisOffset < min(mainAxisLayoutSize, maxOffset)
if (hasSpareSpace) {
check(firstLineScrollOffset == 0)
}
- val positionedItems = ArrayList<LazyGridPositionedItem>(lines.fastSumBy { it.items.size })
+ val positionedItems = ArrayList<LazyGridMeasuredItem>(lines.fastSumBy { it.items.size })
if (hasSpareSpace) {
require(itemsBefore.isEmpty() && itemsAfter.isEmpty())
@@ -395,7 +395,8 @@
itemsBefore.fastForEach {
currentMainAxis -= it.mainAxisSizeWithSpacings
- positionedItems.add(it.positionExtraItem(currentMainAxis, layoutWidth, layoutHeight))
+ it.position(currentMainAxis, 0, layoutWidth, layoutHeight)
+ positionedItems.add(it)
}
currentMainAxis = firstLineScrollOffset
@@ -405,23 +406,10 @@
}
itemsAfter.fastForEach {
- positionedItems.add(it.positionExtraItem(currentMainAxis, layoutWidth, layoutHeight))
+ it.position(currentMainAxis, 0, layoutWidth, layoutHeight)
+ positionedItems.add(it)
currentMainAxis += it.mainAxisSizeWithSpacings
}
}
return positionedItems
}
-
-private fun LazyGridMeasuredItem.positionExtraItem(
- mainAxisOffset: Int,
- layoutWidth: Int,
- layoutHeight: Int
-): LazyGridPositionedItem =
- position(
- mainAxisOffset = mainAxisOffset,
- crossAxisOffset = 0,
- layoutWidth = layoutWidth,
- layoutHeight = layoutHeight,
- row = -1,
- column = -1
- )
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 74a6896..ecf9ff7 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
@@ -28,27 +28,27 @@
* if the user emit multiple layout nodes in the item callback.
*/
internal class LazyGridMeasuredItem(
- val index: Int,
- val key: Any,
- private val isVertical: Boolean,
+ override val index: Int,
+ override val key: Any,
+ val isVertical: Boolean,
/**
* Cross axis size is the same for all [placeables]. Take it as parameter for the case when
* [placeables] is empty.
*/
val crossAxisSize: Int,
- val mainAxisSpacing: Int,
+ mainAxisSpacing: Int,
private val reverseLayout: Boolean,
private val layoutDirection: LayoutDirection,
private val beforeContentPadding: Int,
private val afterContentPadding: Int,
- val placeables: List<Placeable>,
+ private val placeables: List<Placeable>,
/**
* The offset which shouldn't affect any calculations but needs to be applied for the final
* value passed into the place() call.
*/
private val visualOffset: IntOffset,
- private val contentType: Any?
-) {
+ override val contentType: Any?
+) : LazyGridItemInfo {
/**
* Main axis size of the item - the max main axis size of the placeables.
*/
@@ -61,6 +61,10 @@
val placeablesCount: Int get() = placeables.size
+ private var mainAxisLayoutSize: Int = Unset
+ private var minMainAxisOffset: Int = 0
+ private var maxMainAxisOffset: Int = 0
+
fun getParentData(index: Int) = placeables[index].parentData
init {
@@ -72,6 +76,19 @@
mainAxisSizeWithSpacings = (maxMainAxis + mainAxisSpacing).coerceAtLeast(0)
}
+ override val size: IntSize = if (isVertical) {
+ IntSize(crossAxisSize, mainAxisSize)
+ } else {
+ IntSize(mainAxisSize, crossAxisSize)
+ }
+ override var offset: IntOffset = IntOffset.Zero
+ private set
+ val crossAxisOffset get() = if (isVertical) offset.x else offset.y
+ override var row: Int = LazyGridItemInfo.UnknownRow
+ private set
+ override var column: Int = LazyGridItemInfo.UnknownColumn
+ private set
+
/**
* Calculates positions for the inner placeables at [mainAxisOffset], [crossAxisOffset].
* [layoutWidth] and [layoutHeight] should be provided to not place placeables which are ended
@@ -84,10 +101,10 @@
crossAxisOffset: Int,
layoutWidth: Int,
layoutHeight: Int,
- row: Int,
- column: Int
- ): LazyGridPositionedItem {
- val mainAxisLayoutSize = if (isVertical) layoutHeight else layoutWidth
+ row: Int = LazyGridItemInfo.UnknownRow,
+ column: Int = LazyGridItemInfo.UnknownColumn
+ ) {
+ mainAxisLayoutSize = if (isVertical) layoutHeight else layoutWidth
val crossAxisLayoutSize = if (isVertical) layoutWidth else layoutHeight
@Suppress("NAME_SHADOWING")
val crossAxisOffset = if (isVertical && layoutDirection == LayoutDirection.Rtl) {
@@ -95,62 +112,21 @@
} else {
crossAxisOffset
}
- return LazyGridPositionedItem(
- offset = if (isVertical) {
- IntOffset(crossAxisOffset, mainAxisOffset)
- } else {
- IntOffset(mainAxisOffset, crossAxisOffset)
- },
- index = index,
- key = key,
- row = row,
- column = column,
- size = if (isVertical) {
- IntSize(crossAxisSize, mainAxisSize)
- } else {
- IntSize(mainAxisSize, crossAxisSize)
- },
- minMainAxisOffset = -beforeContentPadding,
- maxMainAxisOffset = mainAxisLayoutSize + afterContentPadding,
- isVertical = isVertical,
- placeables = placeables,
- visualOffset = visualOffset,
- mainAxisLayoutSize = mainAxisLayoutSize,
- reverseLayout = reverseLayout,
- contentType = contentType
- )
+ offset = if (isVertical) {
+ IntOffset(crossAxisOffset, mainAxisOffset)
+ } else {
+ IntOffset(mainAxisOffset, crossAxisOffset)
+ }
+ this.row = row
+ this.column = column
+ minMainAxisOffset = -beforeContentPadding
+ maxMainAxisOffset = mainAxisLayoutSize + afterContentPadding
}
-}
-
-internal class LazyGridPositionedItem(
- override val offset: IntOffset,
- override val index: Int,
- override val key: Any,
- override val row: Int,
- override val column: Int,
- override val size: IntSize,
- private val minMainAxisOffset: Int,
- private val maxMainAxisOffset: Int,
- val isVertical: Boolean,
- private val placeables: List<Placeable>,
- private val visualOffset: IntOffset,
- private val mainAxisLayoutSize: Int,
- private val reverseLayout: Boolean,
- override val contentType: Any?
-) : LazyGridItemInfo {
- val placeablesCount: Int get() = placeables.size
-
- fun getMainAxisSize() = if (isVertical) size.height else size.width
-
- fun getCrossAxisSize() = if (isVertical) size.width else size.height
-
- fun getCrossAxisOffset() = if (isVertical) offset.x else offset.y
-
- fun getParentData(index: Int) = placeables[index].parentData
fun place(
scope: Placeable.PlacementScope,
) = with(scope) {
+ require(mainAxisLayoutSize != Unset) { "position() should be called first" }
repeat(placeablesCount) { index ->
val placeable = placeables[index]
val minOffset = minMainAxisOffset - placeable.mainAxisSize
@@ -187,3 +163,5 @@
private inline fun IntOffset.copy(mainAxisMap: (Int) -> Int): IntOffset =
IntOffset(if (isVertical) x else mainAxisMap(x), if (isVertical) mainAxisMap(y) else y)
}
+
+private const val Unset = Int.MIN_VALUE
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItemProvider.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItemProvider.kt
index c984631..05be19d 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItemProvider.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItemProvider.kt
@@ -26,11 +26,10 @@
* Abstracts away the subcomposition from the measuring logic.
*/
@OptIn(ExperimentalFoundationApi::class)
-internal class LazyGridMeasuredItemProvider @ExperimentalFoundationApi constructor(
+internal abstract class LazyGridMeasuredItemProvider @ExperimentalFoundationApi constructor(
private val itemProvider: LazyGridItemProvider,
private val measureScope: LazyLayoutMeasureScope,
- private val defaultMainAxisSpacing: Int,
- private val measuredItemFactory: MeasuredItemFactory
+ private val defaultMainAxisSpacing: Int
) {
/**
* Used to subcompose individual items of lazy grids. Composed placeables will be measured
@@ -41,7 +40,7 @@
mainAxisSpacing: Int = defaultMainAxisSpacing,
constraints: Constraints
): LazyGridMeasuredItem {
- val key = keyIndexMap.getKey(index) ?: itemProvider.getKey(index)
+ val key = itemProvider.getKey(index)
val contentType = itemProvider.getContentType(index)
val placeables = measureScope.measure(index, constraints)
val crossAxisSize = if (constraints.hasFixedWidth) {
@@ -50,7 +49,7 @@
require(constraints.hasFixedHeight)
constraints.minHeight
}
- return measuredItemFactory.createItem(
+ return createItem(
index,
key,
contentType,
@@ -64,12 +63,9 @@
* Contains the mapping between the key and the index. It could contain not all the items of
* the list as an optimization.
**/
- val keyIndexMap: LazyLayoutKeyIndexMap = itemProvider.keyIndexMap
-}
+ val keyIndexMap: LazyLayoutKeyIndexMap get() = itemProvider.keyIndexMap
-// This interface allows to avoid autoboxing on index param
-internal fun interface MeasuredItemFactory {
- fun createItem(
+ abstract fun createItem(
index: Int,
key: Any,
contentType: Any?,
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredLine.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredLine.kt
index 0b3f5e0..f5f8349 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredLine.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredLine.kt
@@ -66,9 +66,9 @@
offset: Int,
layoutWidth: Int,
layoutHeight: Int
- ): List<LazyGridPositionedItem> {
+ ): Array<LazyGridMeasuredItem> {
var usedSpan = 0
- return items.mapIndexed { itemIndex, item ->
+ items.forEachIndexed { itemIndex, item ->
val span = spans[itemIndex].currentLineSpan
val startSlot = usedSpan
@@ -83,5 +83,6 @@
usedSpan += span
}
}
+ return items
}
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredLineProvider.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredLineProvider.kt
index fe5ff54..c852c3f 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredLineProvider.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredLineProvider.kt
@@ -24,14 +24,13 @@
* Abstracts away subcomposition and span calculation from the measuring logic of entire lines.
*/
@OptIn(ExperimentalFoundationApi::class)
-internal class LazyGridMeasuredLineProvider(
+internal abstract class LazyGridMeasuredLineProvider(
private val isVertical: Boolean,
private val slots: LazyGridSlots,
private val gridItemsCount: Int,
private val spaceBetweenLines: Int,
private val measuredItemProvider: LazyGridMeasuredItemProvider,
- private val spanLayoutProvider: LazyGridSpanLayoutProvider,
- private val measuredLineFactory: MeasuredLineFactory
+ private val spanLayoutProvider: LazyGridSpanLayoutProvider
) {
// The constraints for cross axis size. The main axis is not restricted.
internal fun childConstraints(startSlot: Int, span: Int): Constraints {
@@ -67,7 +66,8 @@
// we add space between lines as an extra spacing for all lines apart from the last one
// so the lazy grid measuring logic will take it into account.
val mainAxisSpacing = if (lineItemsCount == 0 ||
- lineConfiguration.firstItemIndex + lineItemsCount == gridItemsCount) {
+ lineConfiguration.firstItemIndex + lineItemsCount == gridItemsCount
+ ) {
0
} else {
spaceBetweenLines
@@ -83,7 +83,7 @@
constraints
).also { startSlot += span }
}
- return measuredLineFactory.createLine(
+ return createLine(
lineIndex,
items,
lineConfiguration.spans,
@@ -96,12 +96,8 @@
* the list as an optimization.
**/
val keyIndexMap: LazyLayoutKeyIndexMap get() = measuredItemProvider.keyIndexMap
-}
-// This interface allows to avoid autoboxing on index param
-@OptIn(ExperimentalFoundationApi::class)
-internal fun interface MeasuredLineFactory {
- fun createLine(
+ abstract fun createLine(
index: Int,
items: Array<LazyGridMeasuredItem>,
spans: List<GridItemSpan>,
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridScrollPosition.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridScrollPosition.kt
index 7b19619..7ec7f70 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridScrollPosition.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridScrollPosition.kt
@@ -17,11 +17,11 @@
package androidx.compose.foundation.lazy.grid
import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.lazy.layout.LazyLayoutNearestRangeState
import androidx.compose.foundation.lazy.layout.findIndexByKey
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.setValue
-import androidx.compose.runtime.snapshots.Snapshot
/**
* Contains the current scroll position represented by the first visible item index and the first
@@ -43,6 +43,12 @@
/** The last known key of the first item at [index] line. */
private var lastKnownFirstItemKey: Any? = null
+ val nearestRangeState = LazyLayoutNearestRangeState(
+ initialIndex,
+ NearestItemsSlidingWindowSize,
+ NearestItemsExtraItemCount
+ )
+
/**
* Updates the current scroll position based on the results of the last measurement.
*/
@@ -56,12 +62,8 @@
val scrollOffset = measureResult.firstVisibleLineScrollOffset
check(scrollOffset >= 0f) { "scrollOffset should be non-negative ($scrollOffset)" }
- Snapshot.withoutReadObservation {
- update(
- measureResult.firstVisibleLine?.items?.firstOrNull()?.index ?: 0,
- scrollOffset
- )
- }
+ val firstIndex = measureResult.firstVisibleLine?.items?.firstOrNull()?.index ?: 0
+ update(firstIndex, scrollOffset)
}
}
@@ -89,22 +91,33 @@
* there were items added or removed before our current first visible item and keep this item
* as the first visible one even given that its index has been changed.
*/
- fun updateScrollPositionIfTheFirstItemWasMoved(itemProvider: LazyGridItemProvider) {
- Snapshot.withoutReadObservation {
- update(
- itemProvider.findIndexByKey(lastKnownFirstItemKey, index),
- scrollOffset
- )
+ fun updateScrollPositionIfTheFirstItemWasMoved(
+ itemProvider: LazyGridItemProvider,
+ index: Int
+ ): Int {
+ val newIndex = itemProvider.findIndexByKey(lastKnownFirstItemKey, index)
+ if (index != newIndex) {
+ this.index = newIndex
+ nearestRangeState.update(index)
}
+ return newIndex
}
private fun update(index: Int, scrollOffset: Int) {
require(index >= 0f) { "Index should be non-negative ($index)" }
- if (index != this.index) {
- this.index = index
- }
- if (scrollOffset != this.scrollOffset) {
- this.scrollOffset = scrollOffset
- }
+ this.index = index
+ nearestRangeState.update(index)
+ this.scrollOffset = scrollOffset
}
}
+
+/**
+ * We use the idea of sliding window as an optimization, so user can scroll up to this number of
+ * items until we have to regenerate the key to index map.
+ */
+private const val NearestItemsSlidingWindowSize = 90
+
+/**
+ * The minimum amount of items near the current first visible item we want to have mapping for.
+ */
+private const val NearestItemsExtraItemCount = 200
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridState.kt
index 73e2a21..2ab8a16 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridState.kt
@@ -38,6 +38,7 @@
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.ui.layout.Remeasurement
import androidx.compose.ui.layout.RemeasurementModifier
import androidx.compose.ui.unit.Constraints
@@ -155,12 +156,12 @@
/**
* Needed for [animateScrollToItem]. Updated on every measure.
*/
- internal var density: Density by mutableStateOf(Density(1f, 1f))
+ internal var density: Density = Density(1f, 1f)
/**
* Needed for [notifyPrefetch].
*/
- internal var isVertical: Boolean by mutableStateOf(true)
+ internal var isVertical: Boolean = true
/**
* The ScrollableController instance. We keep it as we need to call stopAnimation on it once
@@ -202,7 +203,7 @@
* The [Remeasurement] object associated with our layout. It allows us to remeasure
* synchronously during scroll.
*/
- internal var remeasurement: Remeasurement? by mutableStateOf(null)
+ internal var remeasurement: Remeasurement? = null
/**
* The modifier which provides [remeasurement].
@@ -236,6 +237,8 @@
*/
internal val pinnedItems = LazyLayoutPinnedItemList()
+ internal val nearestRange: IntRange by scrollPosition.nearestRangeState
+
/**
* Instantly brings the item at [index] to the top of the viewport, offset by [scrollOffset]
* pixels.
@@ -428,9 +431,10 @@
* items added or removed before our current first visible item and keep this item
* as the first visible one even given that its index has been changed.
*/
- internal fun updateScrollPositionIfTheFirstItemWasMoved(itemProvider: LazyGridItemProvider) {
- scrollPosition.updateScrollPositionIfTheFirstItemWasMoved(itemProvider)
- }
+ internal fun updateScrollPositionIfTheFirstItemWasMoved(
+ itemProvider: LazyGridItemProvider,
+ firstItemIndex: Int = Snapshot.withoutReadObservation { scrollPosition.index }
+ ): Int = scrollPosition.updateScrollPositionIfTheFirstItemWasMoved(itemProvider, firstItemIndex)
companion object {
/**
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 f43b274..ffc8ddc 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
@@ -45,11 +45,22 @@
prefetchState: LazyLayoutPrefetchState? = null,
measurePolicy: LazyLayoutMeasureScope.(Constraints) -> MeasureResult
) {
+ LazyLayout({ itemProvider }, modifier, prefetchState, measurePolicy)
+}
+
+@ExperimentalFoundationApi
+@Composable
+internal fun LazyLayout(
+ itemProvider: () -> LazyLayoutItemProvider,
+ modifier: Modifier = Modifier,
+ prefetchState: LazyLayoutPrefetchState? = null,
+ measurePolicy: LazyLayoutMeasureScope.(Constraints) -> MeasureResult
+) {
val currentItemProvider = rememberUpdatedState(itemProvider)
LazySaveableStateHolderProvider { saveableStateHolder ->
val itemContentFactory = remember {
- LazyLayoutItemContentFactory(saveableStateHolder) { currentItemProvider.value }
+ LazyLayoutItemContentFactory(saveableStateHolder) { currentItemProvider.value() }
}
val subcomposeLayoutState = remember {
SubcomposeLayoutState(LazyLayoutItemReusePolicy(itemContentFactory))
@@ -67,11 +78,13 @@
modifier,
remember(itemContentFactory, measurePolicy) {
{ constraints ->
- with(LazyLayoutMeasureScopeImpl(
- itemContentFactory,
- this,
- prefetchState?.prefetcher?.timeTracker
- )) {
+ with(
+ LazyLayoutMeasureScopeImpl(
+ itemContentFactory,
+ this,
+ prefetchState?.prefetcher?.timeTracker
+ )
+ ) {
measurePolicy(constraints)
}
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory.kt
index 0b3039b..c6a41ab 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory.kt
@@ -21,10 +21,7 @@
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.ReusableContentHost
import androidx.compose.runtime.Stable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.saveable.SaveableStateHolder
-import androidx.compose.runtime.setValue
/**
* This class:
@@ -52,7 +49,7 @@
val cachedContent = lambdasCache[key]
return if (cachedContent != null) {
- cachedContent.type
+ cachedContent.contentType
} else {
val itemProvider = itemProvider()
val index = itemProvider.getIndex(key)
@@ -67,24 +64,24 @@
/**
* Return cached item content lambda or creates a new lambda and puts it in the cache.
*/
- fun getContent(index: Int, key: Any): @Composable () -> Unit {
+ fun getContent(index: Int, key: Any, contentType: Any?): @Composable () -> Unit {
val cached = lambdasCache[key]
- val type = itemProvider().getContentType(index)
- return if (cached != null && cached.lastKnownIndex == index && cached.type == type) {
+ return if (cached != null && cached.index == index && cached.contentType == contentType) {
cached.content
} else {
- val newContent = CachedItemContent(index, key, type)
+ val newContent = CachedItemContent(index, key, contentType)
lambdasCache[key] = newContent
newContent.content
}
}
private inner class CachedItemContent(
- initialIndex: Int,
+ index: Int,
val key: Any,
- val type: Any?
+ val contentType: Any?
) {
- var lastKnownIndex by mutableIntStateOf(initialIndex)
+ // the index resolved during the latest composition
+ var index = index
private set
private var _content: (@Composable () -> Unit)? = null
@@ -94,10 +91,10 @@
private fun createContentLambda() = @Composable {
val itemProvider = itemProvider()
- var index = lastKnownIndex
+ var index = index
if (index >= itemProvider.itemCount || itemProvider.getKey(index) != key) {
index = itemProvider.getIndex(key)
- if (index != -1) lastKnownIndex = index
+ if (index != -1) this.index = index
}
ReusableContentHost(active = index != -1) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutItemProvider.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutItemProvider.kt
index 9498578..e9f2858 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutItemProvider.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutItemProvider.kt
@@ -70,7 +70,7 @@
key: Any?,
lastKnownIndex: Int,
): Int {
- if (key == null) {
+ if (key == null || itemCount == 0) {
// there were no real item during the previous measure
return lastKnownIndex
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt
index a6485ee..8ba9d37 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt
@@ -17,11 +17,6 @@
package androidx.compose.foundation.lazy.layout
import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.runtime.State
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.referentialEqualityPolicy
-import androidx.compose.runtime.structuralEqualityPolicy
/**
* A key-index mapping used inside the [LazyLayoutItemProvider]. It might not contain all items
@@ -51,60 +46,22 @@
}
/**
- * State containing [LazyLayoutKeyIndexMap] precalculated for range of indexes near first visible
- * item.
- * It is optimized to return the same range for small changes in the firstVisibleItemIndex
- * value so we do not regenerate the map on each scroll.
- *
- * @param firstVisibleItemIndex Provider of the first item index currently visible on screen.
- * @param slidingWindowSize Number of items between current and `firstVisibleItem` until
- * [LazyLayoutKeyIndexMap] is regenerated.
- * @param extraItemCount The minimum amount of items in one direction near the first visible item
- * to calculate mapping for.
- * @param content Provider of [LazyLayoutIntervalContent] to generate key index mapping for.
- */
-@ExperimentalFoundationApi
-internal class NearestRangeKeyIndexMapState(
- firstVisibleItemIndex: () -> Int,
- slidingWindowSize: () -> Int,
- extraItemCount: () -> Int,
- content: () -> LazyLayoutIntervalContent<*>
-) : State<LazyLayoutKeyIndexMap> {
- private val nearestRangeState by derivedStateOf(structuralEqualityPolicy()) {
- if (content().itemCount < extraItemCount() * 2 + slidingWindowSize()) {
- 0 until content().itemCount
- } else {
- calculateNearestItemsRange(
- firstVisibleItemIndex(),
- slidingWindowSize(),
- extraItemCount()
- )
- }
- }
-
- override val value: LazyLayoutKeyIndexMap by derivedStateOf(referentialEqualityPolicy()) {
- NearestRangeKeyIndexMap(nearestRangeState, content())
- }
-}
-
-/**
* Implementation of [LazyLayoutKeyIndexMap] indexing over given [IntRange] of items.
* Items outside of given range are considered unknown, with null returned as the index.
*/
@ExperimentalFoundationApi
-private class NearestRangeKeyIndexMap(
+internal class NearestRangeKeyIndexMap(
nearestRange: IntRange,
- content: LazyLayoutIntervalContent<*>
+ intervalContent: LazyLayoutIntervalContent<*>
) : LazyLayoutKeyIndexMap {
private val map: Map<Any, Int>
private val keys: Array<Any?>
private val keysStartIndex: Int
init {
- // Traverses the interval [list] in order to create a mapping from the key to the index for all
- // the indexes in the passed [range].
- // The returned map will not contain the values for intervals with no key mapping provided.
- val list = content.intervals
+ // Traverses the interval [list] in order to create a mapping from the key to the index for
+ // all the indexes in the passed [range].
+ val list = intervalContent.intervals
val first = nearestRange.first
check(first >= 0)
val last = minOf(nearestRange.last, list.size - 1)
@@ -113,31 +70,24 @@
keys = emptyArray()
keysStartIndex = 0
} else {
- var tmpKeys = emptyArray<Any?>()
- var tmpKeysStartIndex = 0
+ keys = arrayOfNulls<Any?>(last - first + 1)
+ keysStartIndex = first
map = hashMapOf<Any, Int>().also { map ->
list.forEach(
fromIndex = first,
toIndex = last,
) {
- if (it.value.key != null) {
- val keyFactory = requireNotNull(it.value.key)
- val start = maxOf(first, it.startIndex)
- if (tmpKeys.isEmpty()) {
- tmpKeysStartIndex = start
- tmpKeys = Array(last - start + 1) { null }
- }
- val end = minOf(last, it.startIndex + it.size - 1)
- for (i in start..end) {
- val key = keyFactory(i - it.startIndex)
- map[key] = i
- tmpKeys[i - tmpKeysStartIndex] = key
- }
+ val keyFactory = it.value.key
+ val start = maxOf(first, it.startIndex)
+ val end = minOf(last, it.startIndex + it.size - 1)
+ for (i in start..end) {
+ val key =
+ keyFactory?.invoke(i - it.startIndex) ?: getDefaultLazyLayoutKey(i)
+ map[key] = i
+ keys[i - keysStartIndex] = key
}
}
}
- keys = tmpKeys
- keysStartIndex = tmpKeysStartIndex
}
}
@@ -146,20 +96,3 @@
override fun getKey(index: Int) =
keys.getOrElse(index - keysStartIndex) { null }
}
-
-/**
- * Returns a range of indexes which contains at least [extraItemCount] items near
- * the first visible item. It is optimized to return the same range for small changes in the
- * firstVisibleItem value so we do not regenerate the map on each scroll.
- */
-private fun calculateNearestItemsRange(
- firstVisibleItem: Int,
- slidingWindowSize: Int,
- extraItemCount: Int
-): IntRange {
- val slidingWindowStart = slidingWindowSize * (firstVisibleItem / slidingWindowSize)
-
- val start = maxOf(slidingWindowStart - extraItemCount, 0)
- val end = slidingWindowStart + slidingWindowSize + extraItemCount
- return start until end
-}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutMeasureScope.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutMeasureScope.kt
index fad7467..2a8bb45 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutMeasureScope.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutMeasureScope.kt
@@ -103,6 +103,8 @@
private val timeTracker: LazyLayoutPrefetchState.AverageTimeTracker?
) : LazyLayoutMeasureScope, MeasureScope by subcomposeMeasureScope {
+ private val itemProvider = itemContentFactory.itemProvider()
+
/**
* A cache of the previously composed items. It allows us to support [get]
* re-executions with the same index during the same measure pass.
@@ -114,8 +116,9 @@
return if (cachedPlaceable != null) {
cachedPlaceable
} else {
- val key = itemContentFactory.itemProvider().getKey(index)
- val itemContent = itemContentFactory.getContent(index, key)
+ val key = itemProvider.getKey(index)
+ val contentType = itemProvider.getContentType(index)
+ val itemContent = itemContentFactory.getContent(index, key, contentType)
val measurables = trackComposition {
subcomposeMeasureScope.subcompose(key, itemContent)
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutNearestRangeState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutNearestRangeState.kt
new file mode 100644
index 0000000..69766ea
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutNearestRangeState.kt
@@ -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.compose.foundation.lazy.layout
+
+import androidx.compose.runtime.State
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.structuralEqualityPolicy
+
+internal class LazyLayoutNearestRangeState(
+ firstVisibleItem: Int,
+ private val slidingWindowSize: Int,
+ private val extraItemCount: Int
+) : State<IntRange> {
+
+ override var value: IntRange by mutableStateOf(
+ calculateNearestItemsRange(firstVisibleItem, slidingWindowSize, extraItemCount),
+ structuralEqualityPolicy()
+ )
+ private set
+
+ private var lastFirstVisibleItem = firstVisibleItem
+
+ fun update(firstVisibleItem: Int) {
+ if (firstVisibleItem != lastFirstVisibleItem) {
+ lastFirstVisibleItem = firstVisibleItem
+ value = calculateNearestItemsRange(firstVisibleItem, slidingWindowSize, extraItemCount)
+ }
+ }
+
+ private companion object {
+ /**
+ * Returns a range of indexes which contains at least [extraItemCount] items near
+ * the first visible item. It is optimized to return the same range for small changes in the
+ * firstVisibleItem value so we do not regenerate the map on each scroll.
+ */
+ private fun calculateNearestItemsRange(
+ firstVisibleItem: Int,
+ slidingWindowSize: Int,
+ extraItemCount: Int
+ ): IntRange {
+ val slidingWindowStart = slidingWindowSize * (firstVisibleItem / slidingWindowSize)
+
+ val start = maxOf(slidingWindowStart - extraItemCount, 0)
+ val end = slidingWindowStart + slidingWindowSize + extraItemCount
+ return start until end
+ }
+ }
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState.kt
index 9a47017..1184ff7 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState.kt
@@ -18,9 +18,6 @@
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.runtime.Stable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
import androidx.compose.ui.unit.Constraints
/**
@@ -29,7 +26,7 @@
@ExperimentalFoundationApi
@Stable
class LazyLayoutPrefetchState {
- internal var prefetcher: Prefetcher? by mutableStateOf(null)
+ internal var prefetcher: Prefetcher? = null
/**
* Schedules precomposition and premeasure for the new item.
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt
index a81ca87..b7e1ca9 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt
@@ -39,7 +39,7 @@
@Suppress("ComposableModifierFactory")
@Composable
internal fun Modifier.lazyLayoutSemantics(
- itemProvider: LazyLayoutItemProvider,
+ itemProviderLambda: () -> LazyLayoutItemProvider,
state: LazyLayoutSemanticState,
orientation: Orientation,
userScrollEnabled: Boolean,
@@ -48,13 +48,14 @@
val coroutineScope = rememberCoroutineScope()
return this.then(
remember(
- itemProvider,
+ itemProviderLambda,
state,
orientation,
userScrollEnabled
) {
val isVertical = orientation == Orientation.Vertical
val indexForKeyMapping: (Any) -> Int = { needle ->
+ val itemProvider = itemProviderLambda()
var result = -1
for (index in 0 until itemProvider.itemCount) {
if (itemProvider.getKey(index) == needle) {
@@ -74,6 +75,7 @@
state.currentPosition
},
maxValue = {
+ val itemProvider = itemProviderLambda()
if (state.canScrollForward) {
// If we can scroll further, we don't know the end yet,
// but it's upper bounded by #items + 1
@@ -105,6 +107,7 @@
val scrollToIndexAction: ((Int) -> Boolean)? = if (userScrollEnabled) {
{ index ->
+ val itemProvider = itemProviderLambda()
require(index >= 0 && index < itemProvider.itemCount) {
"Can't scroll to index $index, it is out of " +
"bounds [0, ${itemProvider.itemCount})"
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 79423ba..50ae912 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
@@ -63,10 +63,10 @@
) {
val overscrollEffect = ScrollableDefaults.overscrollEffect()
- val itemProvider = rememberStaggeredGridItemProvider(state, content)
+ val itemProviderLambda = rememberStaggeredGridItemProviderLambda(state, content)
val measurePolicy = rememberStaggeredGridMeasurePolicy(
state,
- itemProvider,
+ itemProviderLambda,
contentPadding,
reverseLayout,
orientation,
@@ -76,14 +76,14 @@
)
val semanticState = rememberLazyStaggeredGridSemanticState(state, reverseLayout)
- ScrollPositionUpdater(itemProvider, state)
+ ScrollPositionUpdater(itemProviderLambda, state)
LazyLayout(
modifier = modifier
.then(state.remeasurementModifier)
.then(state.awaitLayoutModifier)
.lazyLayoutSemantics(
- itemProvider = itemProvider,
+ itemProviderLambda = itemProviderLambda,
state = semanticState,
orientation = orientation,
userScrollEnabled = userScrollEnabled,
@@ -110,7 +110,7 @@
enabled = userScrollEnabled
),
prefetchState = state.prefetchState,
- itemProvider = itemProvider,
+ itemProvider = itemProviderLambda,
measurePolicy = measurePolicy
)
}
@@ -119,9 +119,10 @@
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun ScrollPositionUpdater(
- itemProvider: LazyLayoutItemProvider,
+ itemProviderLambda: () -> LazyLayoutItemProvider,
state: LazyStaggeredGridState
) {
+ val itemProvider = itemProviderLambda()
if (itemProvider.itemCount > 0) {
state.updateScrollPositionIfTheFirstItemWasMoved(itemProvider)
}
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 f9dec0d..4c36812 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
@@ -41,8 +41,8 @@
// stored to not allocate it every pass.
private val movingAwayKeys = LinkedHashSet<Any>()
- private val movingInFromStartBound = mutableListOf<LazyStaggeredGridPositionedItem>()
- private val movingInFromEndBound = mutableListOf<LazyStaggeredGridPositionedItem>()
+ private val movingInFromStartBound = mutableListOf<LazyStaggeredGridMeasuredItem>()
+ private val movingInFromEndBound = mutableListOf<LazyStaggeredGridMeasuredItem>()
private val movingAwayToStartBound = mutableListOf<LazyStaggeredGridMeasuredItem>()
private val movingAwayToEndBound = mutableListOf<LazyStaggeredGridMeasuredItem>()
@@ -55,7 +55,7 @@
consumedScroll: Int,
layoutWidth: Int,
layoutHeight: Int,
- positionedItems: MutableList<LazyStaggeredGridPositionedItem>,
+ positionedItems: MutableList<LazyStaggeredGridMeasuredItem>,
itemProvider: LazyStaggeredGridMeasureProvider,
isVertical: Boolean,
laneCount: Int
@@ -185,10 +185,9 @@
val mainAxisOffset = 0 - accumulatedOffsetPerLane[item.lane]
val itemInfo = keyToItemInfoMap.getValue(item.key)
- val positionedItem =
- item.position(mainAxisOffset, itemInfo.crossAxisOffset, mainAxisLayoutSize)
- positionedItems.add(positionedItem)
- startAnimationsIfNeeded(positionedItem)
+ item.position(mainAxisOffset, itemInfo.crossAxisOffset, mainAxisLayoutSize)
+ positionedItems.add(item)
+ startAnimationsIfNeeded(item)
}
accumulatedOffsetPerLane.fill(0)
}
@@ -199,10 +198,9 @@
accumulatedOffsetPerLane[item.lane] += item.mainAxisSize
val itemInfo = keyToItemInfoMap.getValue(item.key)
- val positionedItem =
- item.position(mainAxisOffset, itemInfo.crossAxisOffset, mainAxisLayoutSize)
- positionedItems.add(positionedItem)
- startAnimationsIfNeeded(positionedItem)
+ item.position(mainAxisOffset, itemInfo.crossAxisOffset, mainAxisLayoutSize)
+ positionedItems.add(item)
+ startAnimationsIfNeeded(item)
}
}
@@ -224,7 +222,7 @@
}
private fun initializeNode(
- item: LazyStaggeredGridPositionedItem,
+ item: LazyStaggeredGridMeasuredItem,
mainAxisOffset: Int
) {
val firstPlaceableOffset = item.offset
@@ -243,7 +241,7 @@
}
}
- private fun startAnimationsIfNeeded(item: LazyStaggeredGridPositionedItem) {
+ private fun startAnimationsIfNeeded(item: LazyStaggeredGridMeasuredItem) {
item.forEachNode { node ->
val newTarget = item.offset
val currentTarget = node.rawOffset
@@ -258,13 +256,13 @@
private val Any?.node get() = this as? LazyLayoutAnimateItemModifierNode
- private val LazyStaggeredGridPositionedItem.hasAnimations: Boolean
+ private val LazyStaggeredGridMeasuredItem.hasAnimations: Boolean
get() {
forEachNode { return true }
return false
}
- private inline fun LazyStaggeredGridPositionedItem.forEachNode(
+ private inline fun LazyStaggeredGridMeasuredItem.forEachNode(
block: (LazyLayoutAnimateItemModifierNode) -> Unit
) {
repeat(placeablesCount) { index ->
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemProvider.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemProvider.kt
index b76423c..c1569e3 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemProvider.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemProvider.kt
@@ -20,10 +20,9 @@
import androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider
import androidx.compose.foundation.lazy.layout.LazyLayoutKeyIndexMap
import androidx.compose.foundation.lazy.layout.LazyLayoutPinnableItem
-import androidx.compose.foundation.lazy.layout.NearestRangeKeyIndexMapState
+import androidx.compose.foundation.lazy.layout.NearestRangeKeyIndexMap
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.referentialEqualityPolicy
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
@@ -34,53 +33,67 @@
val keyIndexMap: LazyLayoutKeyIndexMap
}
+@OptIn(ExperimentalFoundationApi::class)
@Composable
-internal fun rememberStaggeredGridItemProvider(
+internal fun rememberStaggeredGridItemProviderLambda(
state: LazyStaggeredGridState,
content: LazyStaggeredGridScope.() -> Unit,
-): LazyStaggeredGridItemProvider {
+): () -> LazyStaggeredGridItemProvider {
val latestContent = rememberUpdatedState(content)
return remember(state) {
- LazyStaggeredGridItemProviderImpl(
- state,
- { latestContent.value },
- )
+ val intervalContentState = derivedStateOf(referentialEqualityPolicy()) {
+ LazyStaggeredGridIntervalContent(latestContent.value)
+ }
+ val itemProviderState = derivedStateOf(referentialEqualityPolicy()) {
+ val intervalContent = intervalContentState.value
+ val map = NearestRangeKeyIndexMap(state.nearestRange, intervalContent)
+ LazyStaggeredGridItemProviderImpl(
+ state = state,
+ intervalContent = intervalContent,
+ keyIndexMap = map
+ )
+ }
+ itemProviderState::value
}
}
@OptIn(ExperimentalFoundationApi::class)
private class LazyStaggeredGridItemProviderImpl(
private val state: LazyStaggeredGridState,
- private val latestContent: () -> (LazyStaggeredGridScope.() -> Unit)
+ private val intervalContent: LazyStaggeredGridIntervalContent,
+ override val keyIndexMap: LazyLayoutKeyIndexMap,
) : LazyStaggeredGridItemProvider {
- private val staggeredGridContent by derivedStateOf(referentialEqualityPolicy()) {
- LazyStaggeredGridIntervalContent(latestContent())
- }
- override val keyIndexMap: LazyLayoutKeyIndexMap by NearestRangeKeyIndexMapState(
- firstVisibleItemIndex = { state.firstVisibleItemIndex },
- slidingWindowSize = { 90 },
- extraItemCount = { 200 },
- content = { staggeredGridContent }
- )
-
- override val itemCount: Int get() = staggeredGridContent.itemCount
+ override val itemCount: Int get() = intervalContent.itemCount
override fun getKey(index: Int): Any =
- keyIndexMap.getKey(index) ?: staggeredGridContent.getKey(index)
+ keyIndexMap.getKey(index) ?: intervalContent.getKey(index)
override fun getIndex(key: Any): Int = keyIndexMap.getIndex(key)
- override fun getContentType(index: Int): Any? = staggeredGridContent.getContentType(index)
+ override fun getContentType(index: Int): Any? = intervalContent.getContentType(index)
@Composable
override fun Item(index: Int, key: Any) {
LazyLayoutPinnableItem(key, index, state.pinnedItems) {
- staggeredGridContent.withInterval(index) { localIndex, content ->
+ intervalContent.withInterval(index) { localIndex, content ->
content.item(LazyStaggeredGridItemScopeImpl, localIndex)
}
}
}
- override val spanProvider get() = staggeredGridContent.spanProvider
+ override val spanProvider get() = intervalContent.spanProvider
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is LazyStaggeredGridItemProviderImpl) return false
+
+ // the identity of this class is represented by intervalContent object.
+ // having equals() allows us to skip items recomposition when intervalContent didn't change
+ return intervalContent == other.intervalContent
+ }
+
+ override fun hashCode(): Int {
+ return intervalContent.hashCode()
+ }
}
\ No newline at end of file
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 d92ad20..51ef3b9 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
@@ -109,7 +109,12 @@
val initialItemOffsets: IntArray
Snapshot.withoutReadObservation {
- val firstVisibleIndices = state.scrollPosition.indices
+ // ensure scroll position is up to date
+ val firstVisibleIndices =
+ state.updateScrollPositionIfTheFirstItemWasMoved(
+ itemProvider,
+ state.scrollPosition.indices
+ )
val firstVisibleOffsets = state.scrollPosition.offsets
initialItemIndices =
@@ -181,13 +186,20 @@
val reverseLayout: Boolean,
val mainAxisSpacing: Int,
) {
- val measuredItemProvider = LazyStaggeredGridMeasureProvider(
+ val measuredItemProvider = object : LazyStaggeredGridMeasureProvider(
isVertical = isVertical,
itemProvider = itemProvider,
measureScope = measureScope,
resolvedSlots = resolvedSlots,
- ) { index, lane, span, key, contentType, placeables ->
- LazyStaggeredGridMeasuredItem(
+ ) {
+ override fun createItem(
+ index: Int,
+ lane: Int,
+ span: Int,
+ key: Any,
+ contentType: Any?,
+ placeables: List<Placeable>
+ ) = LazyStaggeredGridMeasuredItem(
index = index,
key = key,
placeables = placeables,
@@ -751,13 +763,12 @@
extraItemOffset = itemScrollOffsets[0]
val extraItemsAfter = calculateExtraItems(
position = {
- val positionedItem = it.position(
+ it.position(
mainAxis = extraItemOffset,
crossAxis = 0,
mainAxisLayoutSize = mainAxisLayoutSize
)
extraItemOffset += it.sizeWithSpacings
- positionedItem
},
filter = { itemIndex ->
if (itemIndex >= itemCount) {
@@ -775,7 +786,7 @@
}
)
- val positionedItems = mutableListOf<LazyStaggeredGridPositionedItem>()
+ val positionedItems = mutableListOf<LazyStaggeredGridMeasuredItem>()
positionedItems.addAll(extraItemsBefore)
positionedItems.addAll(visibleItems)
positionedItems.addAll(extraItemsAfter)
@@ -830,8 +841,8 @@
measuredItems: Array<ArrayDeque<LazyStaggeredGridMeasuredItem>>,
itemScrollOffsets: IntArray,
mainAxisLayoutSize: Int,
-): List<LazyStaggeredGridPositionedItem> {
- val positionedItems = ArrayList<LazyStaggeredGridPositionedItem>(
+): List<LazyStaggeredGridMeasuredItem> {
+ val positionedItems = ArrayList<LazyStaggeredGridMeasuredItem>(
measuredItems.sumOf { it.size }
)
while (measuredItems.any { it.isNotEmpty() }) {
@@ -853,14 +864,12 @@
// nothing to place, ignore spacings
continue
}
-
- positionedItems +=
- item.position(
- mainAxis = mainAxisOffset,
- crossAxis = crossAxisOffset,
- mainAxisLayoutSize = mainAxisLayoutSize,
- lane = laneIndex
- )
+ item.position(
+ mainAxis = mainAxisOffset,
+ crossAxis = crossAxisOffset,
+ mainAxisLayoutSize = mainAxisLayoutSize,
+ )
+ positionedItems += item
spanRange.forEach { lane ->
itemScrollOffsets[lane] = mainAxisOffset + item.sizeWithSpacings
}
@@ -870,10 +879,10 @@
@ExperimentalFoundationApi
private inline fun LazyStaggeredGridMeasureContext.calculateExtraItems(
- position: (LazyStaggeredGridMeasuredItem) -> LazyStaggeredGridPositionedItem,
+ position: (LazyStaggeredGridMeasuredItem) -> Unit,
filter: (itemIndex: Int) -> Boolean
-): List<LazyStaggeredGridPositionedItem> {
- var result: MutableList<LazyStaggeredGridPositionedItem>? = null
+): List<LazyStaggeredGridMeasuredItem> {
+ var result: MutableList<LazyStaggeredGridMeasuredItem>? = null
pinnedItems.fastForEach { index ->
if (filter(index)) {
@@ -882,7 +891,8 @@
result = mutableListOf()
}
val measuredItem = measuredItemProvider.getAndMeasure(index, spanRange)
- result?.add(position(measuredItem))
+ position(measuredItem)
+ result?.add(measuredItem)
}
}
@@ -987,14 +997,17 @@
laneInfo.findPreviousItemIndex(item, lane)
@OptIn(ExperimentalFoundationApi::class)
-internal class LazyStaggeredGridMeasureProvider(
+internal abstract class LazyStaggeredGridMeasureProvider(
private val isVertical: Boolean,
private val itemProvider: LazyStaggeredGridItemProvider,
private val measureScope: LazyLayoutMeasureScope,
- private val resolvedSlots: LazyStaggeredGridSlots,
- private val measuredItemFactory: MeasuredItemFactory,
+ private val resolvedSlots: LazyStaggeredGridSlots
) {
- private fun childConstraints(slot: Int, span: Int): Constraints {
+ private fun childConstraints(requestedSlot: Int, requestedSpan: Int): Constraints {
+ val slotCount = resolvedSlots.sizes.size
+ val slot = requestedSlot.coerceAtMost(slotCount - 1)
+ val span = requestedSpan.coerceAtMost(slotCount - slot)
+
// resolved slots contain [offset, size] pair per each slot.
val crossAxisSize = if (span == 1) {
resolvedSlots.sizes[slot]
@@ -1013,10 +1026,10 @@
}
fun getAndMeasure(index: Int, span: SpanRange): LazyStaggeredGridMeasuredItem {
- val key = keyIndexMap.getKey(index) ?: itemProvider.getKey(index)
+ val key = itemProvider.getKey(index)
val contentType = itemProvider.getContentType(index)
val placeables = measureScope.measure(index, childConstraints(span.start, span.size))
- return measuredItemFactory.createItem(
+ return createItem(
index,
span.start,
span.size,
@@ -1026,12 +1039,9 @@
)
}
- val keyIndexMap: LazyLayoutKeyIndexMap = itemProvider.keyIndexMap
-}
+ val keyIndexMap: LazyLayoutKeyIndexMap get() = itemProvider.keyIndexMap
-// This interface allows to avoid autoboxing on index param
-internal fun interface MeasuredItemFactory {
- fun createItem(
+ abstract fun createItem(
index: Int,
lane: Int,
span: Int,
@@ -1042,17 +1052,17 @@
}
internal class LazyStaggeredGridMeasuredItem(
- val index: Int,
- val key: Any,
+ override val index: Int,
+ override val key: Any,
private val placeables: List<Placeable>,
- private val isVertical: Boolean,
+ val isVertical: Boolean,
spacing: Int,
- val lane: Int,
+ override val lane: Int,
val span: Int,
private val beforeContentPadding: Int,
private val afterContentPadding: Int,
- private val contentType: Any?
-) {
+ override val contentType: Any?
+) : LazyStaggeredGridItemInfo {
var isVisible = true
val placeablesCount: Int get() = placeables.size
@@ -1069,63 +1079,40 @@
if (isVertical) it.width else it.height
} ?: 0
+ private var mainAxisLayoutSize: Int = Unset
+ private var minMainAxisOffset: Int = 0
+ private var maxMainAxisOffset: Int = 0
+
+ override val size: IntSize = if (isVertical) {
+ IntSize(crossAxisSize, mainAxisSize)
+ } else {
+ IntSize(mainAxisSize, crossAxisSize)
+ }
+ override var offset: IntOffset = IntOffset.Zero
+ private set
+
fun position(
mainAxis: Int,
crossAxis: Int,
mainAxisLayoutSize: Int,
- lane: Int = 0
- ): LazyStaggeredGridPositionedItem =
- LazyStaggeredGridPositionedItem(
- offset = if (isVertical) {
- IntOffset(crossAxis, mainAxis)
- } else {
- IntOffset(mainAxis, crossAxis)
- },
- lane = lane,
- index = index,
- key = key,
- size = if (isVertical) {
- IntSize(crossAxisSize, mainAxisSize)
- } else {
- IntSize(mainAxisSize, crossAxisSize)
- },
- placeables = placeables,
- isVertical = isVertical,
- mainAxisLayoutSize = mainAxisLayoutSize,
- minMainAxisOffset = -beforeContentPadding,
- maxMainAxisOffset = mainAxisLayoutSize + afterContentPadding,
- span = span,
- contentType = contentType
- )
-}
-
-internal class LazyStaggeredGridPositionedItem(
- override val offset: IntOffset,
- override val index: Int,
- override val lane: Int,
- override val key: Any,
- override val size: IntSize,
- private val placeables: List<Placeable>,
- val isVertical: Boolean,
- private val mainAxisLayoutSize: Int,
- private val minMainAxisOffset: Int,
- private val maxMainAxisOffset: Int,
- val span: Int,
- override val contentType: Any?
-) : LazyStaggeredGridItemInfo {
-
- val placeablesCount: Int get() = placeables.size
-
- val mainAxisSize get() = if (isVertical) size.height else size.width
+ ) {
+ this.mainAxisLayoutSize = mainAxisLayoutSize
+ minMainAxisOffset = -beforeContentPadding
+ maxMainAxisOffset = mainAxisLayoutSize + afterContentPadding
+ offset = if (isVertical) {
+ IntOffset(crossAxis, mainAxis)
+ } else {
+ IntOffset(mainAxis, crossAxis)
+ }
+ }
val crossAxisOffset get() = if (isVertical) offset.x else offset.y
- fun getParentData(index: Int) = placeables[index].parentData
-
fun place(
scope: Placeable.PlacementScope,
context: LazyStaggeredGridMeasureContext
) = with(context) {
+ require(mainAxisLayoutSize != Unset) { "position() should be called first" }
with(scope) {
placeables.fastForEachIndexed { index, placeable ->
val minOffset = minMainAxisOffset - placeable.mainAxisSize
@@ -1166,3 +1153,5 @@
super.toString()
}
}
+
+private const val Unset = Int.MIN_VALUE
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 c72c114..2ef1a74 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
@@ -38,7 +38,7 @@
@Composable
internal fun rememberStaggeredGridMeasurePolicy(
state: LazyStaggeredGridState,
- itemProvider: LazyStaggeredGridItemProvider,
+ itemProviderLambda: () -> LazyStaggeredGridItemProvider,
contentPadding: PaddingValues,
reverseLayout: Boolean,
orientation: Orientation,
@@ -47,7 +47,7 @@
slots: Density.(Constraints) -> LazyStaggeredGridSlots
): LazyLayoutMeasureScope.(Constraints) -> LazyStaggeredGridMeasureResult = remember(
state,
- itemProvider,
+ itemProviderLambda,
contentPadding,
reverseLayout,
orientation,
@@ -62,15 +62,13 @@
)
val resolvedSlots = slots(this, constraints)
val isVertical = orientation == Orientation.Vertical
+ val itemProvider = itemProviderLambda()
// setup information for prefetch
state.slots = resolvedSlots
state.isVertical = isVertical
state.spanProvider = itemProvider.spanProvider
- // ensure scroll position is up to date
- state.updateScrollPositionIfTheFirstItemWasMoved(itemProvider)
-
// setup measure
val beforeContentPadding = contentPadding.beforePadding(
orientation, reverseLayout, layoutDirection
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridScrollPosition.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridScrollPosition.kt
index 5d5fe33..7f8809d 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridScrollPosition.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridScrollPosition.kt
@@ -18,7 +18,9 @@
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider
+import androidx.compose.foundation.lazy.layout.LazyLayoutNearestRangeState
import androidx.compose.foundation.lazy.layout.findIndexByKey
+import androidx.compose.runtime.SnapshotMutationPolicy
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
@@ -30,15 +32,23 @@
initialIndices: IntArray,
initialOffsets: IntArray,
private val fillIndices: (targetIndex: Int, laneCount: Int) -> IntArray
-) {
- var indices by mutableStateOf(initialIndices)
- var offsets by mutableStateOf(initialOffsets)
+) : SnapshotMutationPolicy<IntArray> {
+ var indices by mutableStateOf(initialIndices, this)
+ private set
+ var offsets by mutableStateOf(initialOffsets, this)
+ private set
private var hadFirstNotEmptyLayout = false
/** The last know key of the item at lowest of [indices] position. */
private var lastKnownFirstItemKey: Any? = null
+ val nearestRangeState = LazyLayoutNearestRangeState(
+ initialIndices.minOrNull() ?: 0,
+ NearestItemsSlidingWindowSize,
+ NearestItemsExtraItemCount
+ )
+
/**
* Updates the current scroll position based on the results of the last measurement.
*/
@@ -50,6 +60,7 @@
lastKnownFirstItemKey = measureResult.visibleItemsInfo
.fastFirstOrNull { it.index == firstVisibleIndex }
?.key
+ nearestRangeState.update(firstVisibleIndex)
// we ignore the index and offset from measureResult until we get at least one
// measurement with real items. otherwise the initial index and scroll passed to the
// state would be lost and overridden with zeros.
@@ -79,6 +90,7 @@
val newIndices = fillIndices(index, indices.size)
val newOffsets = IntArray(newIndices.size) { scrollOffset }
update(newIndices, newOffsets)
+ nearestRangeState.update(index)
// clear the stored key as we have a direct request to scroll to [index] position and the
// next [updateScrollPositionIfTheFirstItemWasMoved] shouldn't override this.
lastKnownFirstItemKey = null
@@ -91,27 +103,40 @@
* as the first visible one even given that its index has been changed.
*/
@ExperimentalFoundationApi
- fun updateScrollPositionIfTheFirstItemWasMoved(itemProvider: LazyLayoutItemProvider) {
- Snapshot.withoutReadObservation {
- val lastIndex = itemProvider.findIndexByKey(
- key = lastKnownFirstItemKey,
- lastKnownIndex = indices.getOrNull(0) ?: 0
- )
- if (lastIndex !in indices) {
- update(
- fillIndices(lastIndex, indices.size),
- offsets
- )
- }
+ fun updateScrollPositionIfTheFirstItemWasMoved(
+ itemProvider: LazyLayoutItemProvider,
+ indices: IntArray
+ ): IntArray {
+ val newIndex = itemProvider.findIndexByKey(
+ key = lastKnownFirstItemKey,
+ lastKnownIndex = indices.getOrNull(0) ?: 0
+ )
+ return if (newIndex !in indices) {
+ nearestRangeState.update(newIndex)
+ val newIndices = fillIndices(newIndex, indices.size)
+ this.indices = newIndices
+ newIndices
+ } else {
+ indices
}
}
private fun update(indices: IntArray, offsets: IntArray) {
- if (!indices.contentEquals(this.indices)) {
- this.indices = indices
- }
- if (!offsets.contentEquals(this.offsets)) {
- this.offsets = offsets
- }
+ this.indices = indices
+ this.offsets = offsets
}
-}
\ No newline at end of file
+
+ // mutation policy for int arrays
+ override fun equivalent(a: IntArray, b: IntArray) = a.contentEquals(b)
+}
+
+/**
+ * We use the idea of sliding window as an optimization, so user can scroll up to this number of
+ * items until we have to regenerate the key to index map.
+ */
+private const val NearestItemsSlidingWindowSize = 90
+
+/**
+ * The minimum amount of items near the current first visible item we want to have mapping for.
+ */
+private const val NearestItemsExtraItemCount = 200
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridState.kt
index 84f9df6..f37ea64 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridState.kt
@@ -39,6 +39,7 @@
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.runtime.structuralEqualityPolicy
import androidx.compose.ui.layout.Remeasurement
import androidx.compose.ui.layout.RemeasurementModifier
@@ -223,6 +224,8 @@
internal val placementAnimator = LazyStaggeredGridItemPlacementAnimator()
+ internal val nearestRange: IntRange by scrollPosition.nearestRangeState
+
/**
* Call this function to take control of scrolling and gain the ability to send scroll events
* via [ScrollScope.scrollBy]. All actions that change the logical scroll position must be
@@ -331,9 +334,11 @@
/**
* Maintain scroll position for item based on custom key if its index has changed.
*/
- internal fun updateScrollPositionIfTheFirstItemWasMoved(itemProvider: LazyLayoutItemProvider) {
- scrollPosition.updateScrollPositionIfTheFirstItemWasMoved(itemProvider)
- }
+ internal fun updateScrollPositionIfTheFirstItemWasMoved(
+ itemProvider: LazyLayoutItemProvider,
+ firstItemIndex: IntArray = Snapshot.withoutReadObservation { scrollPosition.indices }
+ ): IntArray =
+ scrollPosition.updateScrollPositionIfTheFirstItemWasMoved(itemProvider, firstItemIndex)
override fun dispatchRawDelta(delta: Float): Float =
scrollableState.dispatchRawDelta(delta)
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/LazyLayoutPager.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/LazyLayoutPager.kt
index d42eaed..ffb2dea 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/LazyLayoutPager.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/LazyLayoutPager.kt
@@ -16,8 +16,11 @@
package androidx.compose.foundation.pager
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.spring
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clipScrollableContainer
+import androidx.compose.foundation.gestures.BringIntoViewScroller
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.ScrollableDefaults
import androidx.compose.foundation.gestures.awaitEachGesture
@@ -25,8 +28,6 @@
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.gestures.snapping.SnapFlingBehavior
import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.lazy.NearestItemsExtraItemCount
-import androidx.compose.foundation.lazy.NearestItemsSlidingWindowSize
import androidx.compose.foundation.lazy.layout.IntervalList
import androidx.compose.foundation.lazy.layout.LazyLayout
import androidx.compose.foundation.lazy.layout.LazyLayoutIntervalContent
@@ -34,15 +35,14 @@
import androidx.compose.foundation.lazy.layout.LazyLayoutKeyIndexMap
import androidx.compose.foundation.lazy.layout.LazyLayoutPinnableItem
import androidx.compose.foundation.lazy.layout.MutableIntervalList
-import androidx.compose.foundation.lazy.layout.NearestRangeKeyIndexMapState
+import androidx.compose.foundation.lazy.layout.NearestRangeKeyIndexMap
import androidx.compose.foundation.lazy.layout.lazyLayoutSemantics
import androidx.compose.foundation.overscroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
+import androidx.compose.runtime.referentialEqualityPolicy
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.runtime.structuralEqualityPolicy
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
@@ -55,6 +55,7 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastAll
+import kotlin.math.absoluteValue
import kotlinx.coroutines.coroutineScope
@ExperimentalFoundationApi
@@ -98,7 +99,7 @@
val overscrollEffect = ScrollableDefaults.overscrollEffect()
- val pagerItemProvider = rememberPagerItemProvider(
+ val pagerItemProvider = rememberPagerItemProviderLambda(
state = state,
pageContent = pageContent,
key = key
@@ -114,7 +115,7 @@
pageSize = pageSize,
horizontalAlignment = horizontalAlignment,
verticalAlignment = verticalAlignment,
- itemProvider = pagerItemProvider,
+ itemProviderLambda = pagerItemProvider,
pageCount = { state.pageCount },
)
@@ -130,7 +131,6 @@
val semanticState = rememberPagerSemanticState(
state,
- pagerItemProvider,
reverseLayout,
orientation == Orientation.Vertical
)
@@ -141,7 +141,7 @@
.then(state.awaitLayoutModifier)
.then(pagerSemantics)
.lazyLayoutSemantics(
- itemProvider = pagerItemProvider,
+ itemProviderLambda = pagerItemProvider,
state = semanticState,
orientation = orientation,
userScrollEnabled = userScrollEnabled,
@@ -166,7 +166,8 @@
flingBehavior = pagerFlingBehavior,
state = state,
overscrollEffect = overscrollEffect,
- enabled = userScrollEnabled
+ enabled = userScrollEnabled,
+ bringIntoViewScroller = PagerBringIntoViewScroller
)
.dragDirectionDetector(state)
.nestedScroll(pageNestedScrollConnection),
@@ -178,38 +179,42 @@
@ExperimentalFoundationApi
internal class PagerLazyLayoutItemProvider(
- val state: PagerState,
- latestContent: () -> (@Composable PagerScope.(page: Int) -> Unit),
- key: ((index: Int) -> Any)?,
- pageCount: () -> Int
+ private val state: PagerState,
+ private val intervalContent: LazyLayoutIntervalContent<PagerIntervalContent>,
+ private val keyIndexMap: LazyLayoutKeyIndexMap,
) : LazyLayoutItemProvider {
- private val pagerContent by derivedStateOf(structuralEqualityPolicy()) {
- PagerLayoutIntervalContent(latestContent(), key = key, pageCount = pageCount())
- }
- private val keyToIndexMap: LazyLayoutKeyIndexMap by NearestRangeKeyIndexMapState(
- firstVisibleItemIndex = { state.firstVisiblePage },
- slidingWindowSize = { NearestItemsSlidingWindowSize },
- extraItemCount = { NearestItemsExtraItemCount },
- content = { pagerContent }
- )
private val pagerScopeImpl = PagerScopeImpl
override val itemCount: Int
- get() = pagerContent.itemCount
+ get() = intervalContent.itemCount
@Composable
override fun Item(index: Int, key: Any) {
LazyLayoutPinnableItem(key, index, state.pinnedPages) {
- pagerContent.withInterval(index) { localIndex, content ->
+ intervalContent.withInterval(index) { localIndex, content ->
content.item(pagerScopeImpl, localIndex)
}
}
}
- override fun getKey(index: Int): Any = keyToIndexMap.getKey(index) ?: pagerContent.getKey(index)
+ override fun getKey(index: Int): Any =
+ keyIndexMap.getKey(index) ?: intervalContent.getKey(index)
- override fun getIndex(key: Any): Int = keyToIndexMap.getIndex(key)
+ override fun getIndex(key: Any): Int = keyIndexMap.getIndex(key)
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is PagerLazyLayoutItemProvider) return false
+
+ // the identity of this class is represented by intervalContent object.
+ // having equals() allows us to skip items recomposition when intervalContent didn't change
+ return intervalContent == other.intervalContent
+ }
+
+ override fun hashCode(): Int {
+ return intervalContent.hashCode()
+ }
}
@OptIn(ExperimentalFoundationApi::class)
@@ -232,20 +237,27 @@
@OptIn(ExperimentalFoundationApi::class)
@Composable
-private fun rememberPagerItemProvider(
+private fun rememberPagerItemProviderLambda(
state: PagerState,
pageContent: @Composable PagerScope.(page: Int) -> Unit,
key: ((index: Int) -> Any)?,
pageCount: () -> Int
-): PagerLazyLayoutItemProvider {
+): () -> PagerLazyLayoutItemProvider {
val latestContent = rememberUpdatedState(pageContent)
return remember(state, latestContent, key, pageCount) {
- PagerLazyLayoutItemProvider(
- state = state,
- latestContent = { latestContent.value },
- key = key,
- pageCount = pageCount
- )
+ val intervalContentState = derivedStateOf(referentialEqualityPolicy()) {
+ PagerLayoutIntervalContent(latestContent.value, key, pageCount())
+ }
+ val itemProviderState = derivedStateOf(referentialEqualityPolicy()) {
+ val intervalContent = intervalContentState.value
+ val map = NearestRangeKeyIndexMap(state.nearestRange, intervalContent)
+ PagerLazyLayoutItemProvider(
+ state = state,
+ intervalContent = intervalContent,
+ keyIndexMap = map
+ )
+ }
+ itemProviderState::value
}
}
@@ -272,3 +284,28 @@
}
}
}
+
+@OptIn(ExperimentalFoundationApi::class)
+private val PagerBringIntoViewScroller = object : BringIntoViewScroller {
+
+ override val scrollAnimationSpec: AnimationSpec<Float> = spring()
+
+ override fun calculateScrollDistance(offset: Float, size: Float, containerSize: Float): Float {
+ val trailingEdge = offset + size
+ val leadingEdge = offset
+
+ val sizeOfItemRequestingFocus = (trailingEdge - leadingEdge).absoluteValue
+ val childSmallerThanParent = sizeOfItemRequestingFocus <= containerSize
+ val initialTargetForLeadingEdge = 0.0f
+ val spaceAvailableToShowItem = containerSize - initialTargetForLeadingEdge
+
+ val targetForLeadingEdge =
+ if (childSmallerThanParent && spaceAvailableToShowItem < sizeOfItemRequestingFocus) {
+ containerSize - sizeOfItemRequestingFocus
+ } else {
+ initialTargetForLeadingEdge
+ }
+
+ return leadingEdge - targetForLeadingEdge
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/MeasuredPage.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/MeasuredPage.kt
index 8543acd..8ad0a3e 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/MeasuredPage.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/MeasuredPage.kt
@@ -16,86 +16,103 @@
package androidx.compose.foundation.pager
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.ui.Alignment
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.util.fastForEach
+import androidx.compose.ui.util.fastForEachIndexed
+@OptIn(ExperimentalFoundationApi::class)
internal class MeasuredPage(
- val index: Int,
+ override val index: Int,
val size: Int,
- val placeables: List<Placeable>,
- val visualOffset: IntOffset,
+ private val placeables: List<Placeable>,
+ private val visualOffset: IntOffset,
val key: Any,
- val orientation: Orientation,
- val horizontalAlignment: Alignment.Horizontal?,
- val verticalAlignment: Alignment.Vertical?,
- val layoutDirection: LayoutDirection,
- val reverseLayout: Boolean,
- val beforeContentPadding: Int,
- val afterContentPadding: Int,
-) {
+ orientation: Orientation,
+ private val horizontalAlignment: Alignment.Horizontal?,
+ private val verticalAlignment: Alignment.Vertical?,
+ private val layoutDirection: LayoutDirection,
+ private val reverseLayout: Boolean
+) : PageInfo {
+
+ private val isVertical = orientation == Orientation.Vertical
val crossAxisSize: Int
+ // optimized for storing x and y offsets for each placeable one by one.
+ // array's size == placeables.size * 2, first we store x, then y.
+ private val placeableOffsets: IntArray
+
init {
var maxCrossAxis = 0
placeables.fastForEach {
maxCrossAxis = maxOf(
maxCrossAxis,
- if (orientation != Orientation.Vertical) it.height else it.width
+ if (!isVertical) it.height else it.width
)
}
crossAxisSize = maxCrossAxis
+ placeableOffsets = IntArray(placeables.size * 2)
}
+ override var offset: Int = 0
+ private set
+
+ private var mainAxisLayoutSize: Int = Unset
+
fun position(
offset: Int,
layoutWidth: Int,
layoutHeight: Int
- ): PositionedPage {
- val wrappers = mutableListOf<PagerPlaceableWrapper>()
- val mainAxisLayoutSize =
- if (orientation == Orientation.Vertical) layoutHeight else layoutWidth
- var mainAxisOffset = if (reverseLayout) {
- mainAxisLayoutSize - offset - size
- } else {
- offset
- }
- var index = if (reverseLayout) placeables.lastIndex else 0
- while (if (reverseLayout) index >= 0 else index < placeables.size) {
- val it = placeables[index]
- val addIndex = if (reverseLayout) 0 else wrappers.size
- val placeableOffset = if (orientation == Orientation.Vertical) {
- val x = requireNotNull(horizontalAlignment)
- .align(it.width, layoutWidth, layoutDirection)
- IntOffset(x, mainAxisOffset)
+ ) {
+ this.offset = offset
+ mainAxisLayoutSize =
+ if (isVertical) layoutHeight else layoutWidth
+ var mainAxisOffset = offset
+ placeables.fastForEachIndexed { index, placeable ->
+ val indexInArray = index * 2
+ if (isVertical) {
+ placeableOffsets[indexInArray] = requireNotNull(horizontalAlignment)
+ .align(placeable.width, layoutWidth, layoutDirection)
+ placeableOffsets[indexInArray + 1] = mainAxisOffset
+ mainAxisOffset += placeable.height
} else {
- val y = requireNotNull(verticalAlignment).align(it.height, layoutHeight)
- IntOffset(mainAxisOffset, y)
+ placeableOffsets[indexInArray] = mainAxisOffset
+ placeableOffsets[indexInArray + 1] = requireNotNull(verticalAlignment)
+ .align(placeable.height, layoutHeight)
+ mainAxisOffset += placeable.width
}
- mainAxisOffset += if (orientation == Orientation.Vertical) it.height else it.width
- wrappers.add(
- addIndex,
- PagerPlaceableWrapper(placeableOffset, it, placeables[index].parentData)
- )
- if (reverseLayout) index-- else index++
}
- return PositionedPage(
- offset = offset,
- index = this.index,
- key = key,
- orientation = orientation,
- wrappers = wrappers,
- visualOffset = visualOffset,
- )
}
+
+ fun place(scope: Placeable.PlacementScope) = with(scope) {
+ require(mainAxisLayoutSize != Unset) { "position() should be called first" }
+ repeat(placeables.size) { index ->
+ val placeable = placeables[index]
+ var offset = getOffset(index)
+ if (reverseLayout) {
+ offset = offset.copy { mainAxisOffset ->
+ mainAxisLayoutSize - mainAxisOffset - placeable.mainAxisSize
+ }
+ }
+ offset += visualOffset
+ if (isVertical) {
+ placeable.placeWithLayer(offset)
+ } else {
+ placeable.placeRelativeWithLayer(offset)
+ }
+ }
+ }
+
+ private fun getOffset(index: Int) =
+ IntOffset(placeableOffsets[index * 2], placeableOffsets[index * 2 + 1])
+ private val Placeable.mainAxisSize get() = if (isVertical) height else width
+ private inline fun IntOffset.copy(mainAxisMap: (Int) -> Int): IntOffset =
+ IntOffset(if (isVertical) x else mainAxisMap(x), if (isVertical) mainAxisMap(y) else y)
}
-internal class PagerPlaceableWrapper(
- val offset: IntOffset,
- val placeable: Placeable,
- val parentData: Any?
-)
\ No newline at end of file
+private const val Unset = Int.MIN_VALUE
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/Pager.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/Pager.kt
index 96e93f6..d64b834 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/Pager.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/Pager.kt
@@ -54,10 +54,12 @@
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastFirstOrNull
import androidx.compose.ui.util.fastForEach
+import kotlin.math.abs
import kotlin.math.absoluteValue
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.sign
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.launch
/**
@@ -115,9 +117,9 @@
userScrollEnabled: Boolean = true,
reverseLayout: Boolean = false,
key: ((index: Int) -> Any)? = null,
- pageNestedScrollConnection: NestedScrollConnection = PagerDefaults.pageNestedScrollConnection(
- Orientation.Horizontal
- ),
+ pageNestedScrollConnection: NestedScrollConnection = remember(state) {
+ PagerDefaults.pageNestedScrollConnection(state, Orientation.Horizontal)
+ },
pageContent: @Composable PagerScope.(page: Int) -> Unit
) {
Pager(
@@ -223,9 +225,9 @@
userScrollEnabled: Boolean = true,
reverseLayout: Boolean = false,
key: ((index: Int) -> Any)? = null,
- pageNestedScrollConnection: NestedScrollConnection = PagerDefaults.pageNestedScrollConnection(
- Orientation.Horizontal
- ),
+ pageNestedScrollConnection: NestedScrollConnection = remember(state) {
+ PagerDefaults.pageNestedScrollConnection(state, Orientation.Horizontal)
+ },
pageContent: @Composable PagerScope.(page: Int) -> Unit
) {
Pager(
@@ -301,9 +303,9 @@
userScrollEnabled: Boolean = true,
reverseLayout: Boolean = false,
key: ((index: Int) -> Any)? = null,
- pageNestedScrollConnection: NestedScrollConnection = PagerDefaults.pageNestedScrollConnection(
- Orientation.Vertical
- ),
+ pageNestedScrollConnection: NestedScrollConnection = remember(state) {
+ PagerDefaults.pageNestedScrollConnection(state, Orientation.Vertical)
+ },
pageContent: @Composable PagerScope.(page: Int) -> Unit
) {
Pager(
@@ -408,9 +410,9 @@
userScrollEnabled: Boolean = true,
reverseLayout: Boolean = false,
key: ((index: Int) -> Any)? = null,
- pageNestedScrollConnection: NestedScrollConnection = PagerDefaults.pageNestedScrollConnection(
- Orientation.Vertical
- ),
+ pageNestedScrollConnection: NestedScrollConnection = remember(state) {
+ PagerDefaults.pageNestedScrollConnection(state, Orientation.Vertical)
+ },
pageContent: @Composable PagerScope.(page: Int) -> Unit
) {
Pager(
@@ -565,18 +567,17 @@
}
/**
- * The default implementation of Pager's pageNestedScrollConnection. All fling scroll deltas
- * will be consumed by the Pager.
+ * The default implementation of Pager's pageNestedScrollConnection.
*
+ * @param state state of the pager
* @param orientation The orientation of the pager. This will be used to determine which
- * direction it will consume everything. The other direction will not be consumed.
+ * direction the nested scroll connection will operate and react on.
*/
- fun pageNestedScrollConnection(orientation: Orientation): NestedScrollConnection {
- return if (orientation == Orientation.Horizontal) {
- ConsumeHorizontalFlingNestedScrollConnection
- } else {
- ConsumeVerticalFlingNestedScrollConnection
- }
+ fun pageNestedScrollConnection(
+ state: PagerState,
+ orientation: Orientation
+ ): NestedScrollConnection {
+ return DefaultPagerNestedScrollConnection(state, orientation)
}
}
@@ -798,12 +799,11 @@
}
}
-private val ConsumeHorizontalFlingNestedScrollConnection =
- ConsumeAllFlingOnDirection(Orientation.Horizontal)
-private val ConsumeVerticalFlingNestedScrollConnection =
- ConsumeAllFlingOnDirection(Orientation.Vertical)
-
-private class ConsumeAllFlingOnDirection(val orientation: Orientation) : NestedScrollConnection {
+@OptIn(ExperimentalFoundationApi::class)
+private class DefaultPagerNestedScrollConnection(
+ val state: PagerState,
+ val orientation: Orientation
+) : NestedScrollConnection {
fun Velocity.consumeOnOrientation(orientation: Orientation): Velocity {
return if (orientation == Orientation.Vertical) {
@@ -821,15 +821,50 @@
}
}
+ override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
+ return if (
+ // rounding error and drag only
+ source == NestedScrollSource.Drag && abs(state.currentPageOffsetFraction) > 0e-6
+ ) {
+ // find the current and next page (in the direction of dragging)
+ val currentPageOffset = state.currentPageOffsetFraction * state.pageSize
+ val pageAvailableSpace = state.layoutInfo.pageSize + state.layoutInfo.pageSpacing
+ val nextClosestPageOffset =
+ currentPageOffset + pageAvailableSpace * -sign(state.currentPageOffsetFraction)
+
+ val minBound: Float
+ val maxBound: Float
+ // build min and max bounds in absolute coordinates for nested scroll
+ if (state.currentPageOffsetFraction > 0f) {
+ minBound = nextClosestPageOffset
+ maxBound = currentPageOffset
+ } else {
+ minBound = currentPageOffset
+ maxBound = nextClosestPageOffset
+ }
+
+ val delta = if (orientation == Orientation.Horizontal) available.x else available.y
+ val coerced = delta.coerceIn(minBound, maxBound)
+ // dispatch and return reversed as usual
+ val consumed = -state.dispatchRawDelta(-coerced)
+ available.copy(
+ x = if (orientation == Orientation.Horizontal) consumed else available.x,
+ y = if (orientation == Orientation.Vertical) consumed else available.y,
+ )
+ } else {
+ Offset.Zero
+ }
+ }
+
override fun onPostScroll(
consumed: Offset,
available: Offset,
source: NestedScrollSource
): Offset {
- return when (source) {
- NestedScrollSource.Fling -> available.consumeOnOrientation(orientation)
- else -> Offset.Zero
+ if (source == NestedScrollSource.Fling && available != Offset.Zero) {
+ throw CancellationException()
}
+ return Offset.Zero
}
override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasure.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasure.kt
index 4c6eb09..90e0f3d 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasure.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasure.kt
@@ -119,7 +119,7 @@
}
// this will contain all the measured pages representing the visible pages
- val visiblePages = mutableListOf<MeasuredPage>()
+ val visiblePages = ArrayDeque<MeasuredPage>()
// define min and max offsets
val minOffset = -beforeContentPadding + if (spaceBetweenPages < 0) spaceBetweenPages else 0
@@ -146,8 +146,6 @@
orientation = orientation,
horizontalAlignment = horizontalAlignment,
verticalAlignment = verticalAlignment,
- afterContentPadding = afterContentPadding,
- beforeContentPadding = beforeContentPadding,
layoutDirection = layoutDirection,
reverseLayout = reverseLayout,
pageAvailableSize = pageAvailableSize
@@ -194,8 +192,6 @@
orientation = orientation,
horizontalAlignment = horizontalAlignment,
verticalAlignment = verticalAlignment,
- afterContentPadding = afterContentPadding,
- beforeContentPadding = beforeContentPadding,
layoutDirection = layoutDirection,
reverseLayout = reverseLayout,
pageAvailableSize = pageAvailableSize
@@ -232,8 +228,6 @@
orientation = orientation,
horizontalAlignment = horizontalAlignment,
verticalAlignment = verticalAlignment,
- afterContentPadding = afterContentPadding,
- beforeContentPadding = beforeContentPadding,
layoutDirection = layoutDirection,
reverseLayout = reverseLayout,
pageAvailableSize = pageAvailableSize
@@ -298,8 +292,6 @@
orientation = orientation,
horizontalAlignment = horizontalAlignment,
verticalAlignment = verticalAlignment,
- afterContentPadding = afterContentPadding,
- beforeContentPadding = beforeContentPadding,
layoutDirection = layoutDirection,
reverseLayout = reverseLayout,
pageAvailableSize = pageAvailableSize
@@ -326,8 +318,6 @@
orientation = orientation,
horizontalAlignment = horizontalAlignment,
verticalAlignment = verticalAlignment,
- afterContentPadding = afterContentPadding,
- beforeContentPadding = beforeContentPadding,
layoutDirection = layoutDirection,
reverseLayout = reverseLayout,
pageAvailableSize = pageAvailableSize
@@ -478,8 +468,6 @@
orientation: Orientation,
horizontalAlignment: Alignment.Horizontal?,
verticalAlignment: Alignment.Vertical?,
- afterContentPadding: Int,
- beforeContentPadding: Int,
layoutDirection: LayoutDirection,
reverseLayout: Boolean,
pageAvailableSize: Int
@@ -493,8 +481,6 @@
visualOffset = visualPageOffset,
horizontalAlignment = horizontalAlignment,
verticalAlignment = verticalAlignment,
- afterContentPadding = afterContentPadding,
- beforeContentPadding = beforeContentPadding,
layoutDirection = layoutDirection,
reverseLayout = reverseLayout,
size = pageAvailableSize,
@@ -518,7 +504,7 @@
density: Density,
spaceBetweenPages: Int,
pageAvailableSize: Int
-): MutableList<PositionedPage> {
+): MutableList<MeasuredPage> {
val pageSizeWithSpacing = (pageAvailableSize + spaceBetweenPages)
val mainAxisLayoutSize = if (orientation == Orientation.Vertical) layoutHeight else layoutWidth
val hasSpareSpace = finalMainAxisOffset < minOf(mainAxisLayoutSize, maxOffset)
@@ -526,7 +512,7 @@
check(pagesScrollOffset == 0)
}
val positionedPages =
- ArrayList<PositionedPage>(pages.size + extraPagesBefore.size + extraPagesAfter.size)
+ ArrayList<MeasuredPage>(pages.size + extraPagesBefore.size + extraPagesAfter.size)
if (hasSpareSpace) {
require(extraPagesBefore.isEmpty() && extraPagesAfter.isEmpty())
@@ -560,23 +546,27 @@
} else {
absoluteOffset
}
- positionedPages.add(page.position(relativeOffset, layoutWidth, layoutHeight))
+ page.position(relativeOffset, layoutWidth, layoutHeight)
+ positionedPages.add(page)
}
} else {
var currentMainAxis = pagesScrollOffset
extraPagesBefore.fastForEach {
currentMainAxis -= pageSizeWithSpacing
- positionedPages.add(it.position(currentMainAxis, layoutWidth, layoutHeight))
+ it.position(currentMainAxis, layoutWidth, layoutHeight)
+ positionedPages.add(it)
}
currentMainAxis = pagesScrollOffset
pages.fastForEach {
- positionedPages.add(it.position(currentMainAxis, layoutWidth, layoutHeight))
+ it.position(currentMainAxis, layoutWidth, layoutHeight)
+ positionedPages.add(it)
currentMainAxis += pageSizeWithSpacing
}
extraPagesAfter.fastForEach {
- positionedPages.add(it.position(currentMainAxis, layoutWidth, layoutHeight))
+ it.position(currentMainAxis, layoutWidth, layoutHeight)
+ positionedPages.add(it)
currentMainAxis += pageSizeWithSpacing
}
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasurePolicy.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasurePolicy.kt
index 2049609..d803fb0b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasurePolicy.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasurePolicy.kt
@@ -40,7 +40,7 @@
@OptIn(ExperimentalFoundationApi::class)
@Composable
internal fun rememberPagerMeasurePolicy(
- itemProvider: PagerLazyLayoutItemProvider,
+ itemProviderLambda: () -> PagerLazyLayoutItemProvider,
state: PagerState,
contentPadding: PaddingValues,
reverseLayout: Boolean,
@@ -150,6 +150,7 @@
}
}
+ val itemProvider = itemProviderLambda()
val pinnedPages = itemProvider.calculateLazyLayoutPinnedIndices(
pinnedItemList = state.pinnedPages,
beyondBoundsInfo = state.beyondBoundsInfo
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerScrollPosition.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerScrollPosition.kt
index cecb371..5597496 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerScrollPosition.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerScrollPosition.kt
@@ -17,10 +17,10 @@
package androidx.compose.foundation.pager
import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.lazy.layout.LazyLayoutNearestRangeState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.setValue
-import androidx.compose.runtime.snapshots.Snapshot
/**
* Contains the current scroll position represented by the first visible page and the first
@@ -42,6 +42,12 @@
/** The last know key of the page at [firstVisiblePage] position. */
private var lastKnownFirstPageKey: Any? = null
+ val nearestRangeState = LazyLayoutNearestRangeState(
+ initialPage,
+ NearestItemsSlidingWindowSize,
+ NearestItemsExtraItemCount
+ )
+
/**
* Updates the current scroll position based on the results of the last measurement.
*/
@@ -55,16 +61,12 @@
val scrollOffset = measureResult.firstVisiblePageOffset
check(scrollOffset >= 0f) { "scrollOffset should be non-negative ($scrollOffset)" }
- Snapshot.withoutReadObservation {
- update(
- measureResult.firstVisiblePage?.index ?: 0,
- scrollOffset
- )
- measureResult.closestPageToSnapPosition?.index?.let {
- if (it != this.currentPage) {
- this.currentPage = it
- }
- }
+ update(
+ measureResult.firstVisiblePage?.index ?: 0,
+ scrollOffset
+ )
+ measureResult.closestPageToSnapPosition?.index?.let {
+ this.currentPage = it
}
}
}
@@ -89,11 +91,19 @@
private fun update(index: Int, scrollOffset: Int) {
require(index >= 0f) { "Index should be non-negative ($index)" }
- if (index != this.firstVisiblePage) {
- this.firstVisiblePage = index
- }
- if (scrollOffset != this.scrollOffset) {
- this.scrollOffset = scrollOffset
- }
+ this.firstVisiblePage = index
+ nearestRangeState.update(index)
+ this.scrollOffset = scrollOffset
}
-}
\ No newline at end of file
+}
+
+/**
+ * We use the idea of sliding window as an optimization, so user can scroll up to this number of
+ * items until we have to regenerate the key to index map.
+ */
+internal const val NearestItemsSlidingWindowSize = 30
+
+/**
+ * The minimum amount of items near the current first visible item we want to have mapping for.
+ */
+internal const val NearestItemsExtraItemCount = 100
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerSemantics.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerSemantics.kt
index 82d10fd..ed274f6 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerSemantics.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerSemantics.kt
@@ -17,7 +17,6 @@
package androidx.compose.foundation.pager
import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider
import androidx.compose.foundation.lazy.layout.LazyLayoutSemanticState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
@@ -26,11 +25,10 @@
@Composable
internal fun rememberPagerSemanticState(
state: PagerState,
- itemProvider: LazyLayoutItemProvider,
reverseScrolling: Boolean,
isVertical: Boolean
): LazyLayoutSemanticState {
- return remember(state, itemProvider, reverseScrolling, isVertical) {
+ return remember(state, reverseScrolling, isVertical) {
LazyLayoutSemanticState(state, isVertical)
}
}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerState.kt
index 9b466ea..37aafef0 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerState.kt
@@ -240,7 +240,7 @@
internal val pageSize: Int
get() = pagerLayoutInfoState.value.pageSize
- internal var density: Density by mutableStateOf(UnitDensity)
+ internal var density: Density = UnitDensity
private val visiblePages: List<PageInfo>
get() = pagerLayoutInfoState.value.visiblePagesInfo
@@ -397,13 +397,15 @@
/**
* Constraints passed to the prefetcher for premeasuring the prefetched items.
*/
- internal var premeasureConstraints by mutableStateOf(Constraints())
+ internal var premeasureConstraints = Constraints()
/**
* Stores currently pinned pages which are always composed, used by for beyond bound pages.
*/
internal val pinnedPages = LazyLayoutPinnedItemList()
+ internal val nearestRange: IntRange by scrollPosition.nearestRangeState
+
/**
* Scroll (jump immediately) to a given [page].
*
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PositionedPage.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PositionedPage.kt
deleted file mode 100644
index 57ce77f..0000000
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PositionedPage.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.compose.foundation.pager
-
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.layout.Placeable
-import androidx.compose.ui.unit.IntOffset
-
-@OptIn(ExperimentalFoundationApi::class)
-internal class PositionedPage(
- override val index: Int,
- override val offset: Int,
- val key: Any,
- val orientation: Orientation,
- val wrappers: MutableList<PagerPlaceableWrapper>,
- val visualOffset: IntOffset
-) : PageInfo {
- fun place(scope: Placeable.PlacementScope) = with(scope) {
- repeat(wrappers.size) { index ->
- val placeable = wrappers[index].placeable
- val offset = wrappers[index].offset
- if (orientation == Orientation.Vertical) {
- placeable.placeWithLayer(offset + visualOffset)
- } else {
- placeable.placeRelativeWithLayer(offset + visualOffset)
- }
- }
- }
-}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
index 6be6e4b..5a25fa6 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
@@ -18,6 +18,7 @@
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
@@ -83,10 +84,10 @@
import androidx.compose.ui.semantics.getTextLayoutResult
import androidx.compose.ui.semantics.insertTextAtCursor
import androidx.compose.ui.semantics.onClick
+import androidx.compose.ui.semantics.onImeAction
import androidx.compose.ui.semantics.onLongClick
import androidx.compose.ui.semantics.password
import androidx.compose.ui.semantics.pasteText
-import androidx.compose.ui.semantics.performImeAction
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.setSelection
import androidx.compose.ui.semantics.setText
@@ -113,6 +114,8 @@
import androidx.compose.ui.unit.dp
import kotlin.math.max
import kotlin.math.roundToInt
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
/**
@@ -501,7 +504,7 @@
false
}
}
- performImeAction(imeOptions.imeAction) {
+ onImeAction(imeOptions.imeAction) {
// This will perform the appropriate default action if no handler has been specified, so
// as far as the platform is concerned, we always handle the action and never want to
// defer to the default _platform_ implementation.
@@ -1081,7 +1084,16 @@
handlePosition = position,
modifier = Modifier
.pointerInput(observer) {
- detectDownAndDragGesturesWithObserver(observer)
+ coroutineScope {
+ // UNDISPATCHED because this runs upon first pointer event and
+ // without it the event would pass before the handler is ready
+ launch(start = CoroutineStart.UNDISPATCHED) {
+ detectDownAndDragGesturesWithObserver(observer)
+ }
+ launch(start = CoroutineStart.UNDISPATCHED) {
+ detectTapGestures { manager.showSelectionToolbar() }
+ }
+ }
}
.semantics {
this[SelectionHandleInfoKey] = SelectionHandleInfo(
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCache.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCache.kt
index 9f6655f..b0e8843 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCache.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCache.kt
@@ -330,7 +330,7 @@
*
* Exposed for semantics GetTextLayoutResult
*/
- fun slowCreateTextLayoutResultOrNull(): TextLayoutResult? {
+ fun slowCreateTextLayoutResultOrNull(style: TextStyle): TextLayoutResult? {
// make sure we're in a valid place
val localLayoutDirection = intrinsicsLayoutDirection ?: return null
val localDensity = density ?: return null
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt
index 54b93c4..6a52754 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt
@@ -17,6 +17,9 @@
package androidx.compose.foundation.text.modifiers
import androidx.compose.foundation.text.DefaultMinLines
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
@@ -44,10 +47,16 @@
import androidx.compose.ui.node.invalidateMeasurement
import androidx.compose.ui.node.invalidateSemantics
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
+import androidx.compose.ui.semantics.clearTextSubstitution
import androidx.compose.ui.semantics.getTextLayoutResult
+import androidx.compose.ui.semantics.isShowingTextSubstitution
+import androidx.compose.ui.semantics.originalText
+import androidx.compose.ui.semantics.setTextSubstitution
+import androidx.compose.ui.semantics.showTextSubstitution
import androidx.compose.ui.semantics.text
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.Placeholder
+import androidx.compose.ui.text.TextLayoutInput
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
@@ -95,6 +104,13 @@
}
private fun getLayoutCache(density: Density): MultiParagraphLayoutCache {
+ textSubstitution?.let { textSubstitutionValue ->
+ if (textSubstitutionValue.isShowingSubstitution) {
+ textSubstitutionValue.layoutCache?.let { cache ->
+ return cache.also { it.density = density }
+ }
+ }
+ }
return layoutCache.also { it.density = density }
}
@@ -117,6 +133,7 @@
fun updateText(text: AnnotatedString): Boolean {
if (this.text == text) return false
this.text = text
+ clearSubstitution()
return true
}
@@ -206,8 +223,10 @@
layoutChanged: Boolean,
callbacksChanged: Boolean
) {
- if (textChanged) {
- invalidateSemantics()
+ if (textChanged || (drawChanged && semanticsTextLayoutResult != null)) {
+ if (isAttached) {
+ invalidateSemantics()
+ }
}
if (textChanged || layoutChanged || callbacksChanged) {
@@ -221,7 +240,9 @@
minLines = minLines,
placeholders = placeholders
)
- invalidateMeasurement()
+ if (isAttached) {
+ invalidateMeasurement()
+ }
invalidateDraw()
}
if (drawChanged) {
@@ -231,18 +252,124 @@
private var semanticsTextLayoutResult: ((MutableList<TextLayoutResult>) -> Boolean)? = null
+ data class TextSubstitutionValue(
+ val original: AnnotatedString,
+ var substitution: AnnotatedString,
+ var isShowingSubstitution: Boolean = false,
+ var layoutCache: MultiParagraphLayoutCache? = null,
+ // TODO(klikli): add animation
+ )
+
+ private var textSubstitution: TextSubstitutionValue? by mutableStateOf(null)
+
+ private fun setSubstitution(updatedText: AnnotatedString): Boolean {
+ val currentTextSubstitution = textSubstitution
+ if (currentTextSubstitution != null) {
+ if (updatedText == currentTextSubstitution.substitution) {
+ return false
+ }
+ currentTextSubstitution.substitution = updatedText
+ currentTextSubstitution.layoutCache?.update(
+ updatedText,
+ style,
+ fontFamilyResolver,
+ overflow,
+ softWrap,
+ maxLines,
+ minLines,
+ placeholders
+ ) ?: return false
+ } else {
+ val newTextSubstitution = TextSubstitutionValue(text, updatedText)
+ val substitutionLayoutCache = MultiParagraphLayoutCache(
+ updatedText,
+ style,
+ fontFamilyResolver,
+ overflow,
+ softWrap,
+ maxLines,
+ minLines,
+ placeholders
+ )
+ substitutionLayoutCache.density = layoutCache.density
+ newTextSubstitution.layoutCache = substitutionLayoutCache
+ textSubstitution = newTextSubstitution
+ }
+ return true
+ }
+
+ private fun clearSubstitution() {
+ textSubstitution = null
+ }
+
override fun SemanticsPropertyReceiver.applySemantics() {
var localSemanticsTextLayoutResult = semanticsTextLayoutResult
if (localSemanticsTextLayoutResult == null) {
localSemanticsTextLayoutResult = { textLayoutResult ->
- val layout = layoutCache.layoutOrNull?.also {
+ val inputLayout = layoutCache.layoutOrNull
+ val layout = inputLayout?.copy(
+ layoutInput = TextLayoutInput(
+ text = inputLayout.layoutInput.text,
+ style = this@TextAnnotatedStringNode.style.merge(
+ color = overrideColor?.invoke() ?: Color.Unspecified
+ ),
+ placeholders = inputLayout.layoutInput.placeholders,
+ maxLines = inputLayout.layoutInput.maxLines,
+ softWrap = inputLayout.layoutInput.softWrap,
+ overflow = inputLayout.layoutInput.overflow,
+ density = inputLayout.layoutInput.density,
+ layoutDirection = inputLayout.layoutInput.layoutDirection,
+ fontFamilyResolver = inputLayout.layoutInput.fontFamilyResolver,
+ constraints = inputLayout.layoutInput.constraints
+ )
+ )?.also {
textLayoutResult.add(it)
}
layout != null
}
semanticsTextLayoutResult = localSemanticsTextLayoutResult
}
- text = this@TextAnnotatedStringNode.text
+
+ val currentTextSubstitution = textSubstitution
+ if (currentTextSubstitution == null) {
+ text = this@TextAnnotatedStringNode.text
+ } else {
+ isShowingTextSubstitution = currentTextSubstitution.isShowingSubstitution
+ if (currentTextSubstitution.isShowingSubstitution) {
+ text = currentTextSubstitution.substitution
+ originalText = currentTextSubstitution.original
+ } else {
+ text = currentTextSubstitution.original
+ }
+ }
+
+ setTextSubstitution { updatedText ->
+ setSubstitution(updatedText)
+
+ true
+ }
+ showTextSubstitution {
+ if (textSubstitution == null) {
+ return@showTextSubstitution false
+ }
+
+ textSubstitution?.isShowingSubstitution = it
+
+ invalidateSemantics()
+ invalidateMeasurement()
+ invalidateDraw()
+
+ true
+ }
+ clearTextSubstitution {
+ clearSubstitution()
+
+ invalidateSemantics()
+ invalidateMeasurement()
+ invalidateDraw()
+
+ true
+ }
getTextLayoutResult(action = localSemanticsTextLayoutResult)
}
@@ -358,6 +485,7 @@
override fun ContentDrawScope.draw() {
selectionController?.draw(this)
drawIntoCanvas { canvas ->
+ val layoutCache = getLayoutCache(this)
val textLayoutResult = layoutCache.textLayoutResult
val localParagraph = textLayoutResult.multiParagraph
val willClip = textLayoutResult.hasVisualOverflow && overflow != TextOverflow.Visible
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNode.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNode.kt
index 76386b2..4831670 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNode.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNode.kt
@@ -17,6 +17,9 @@
package androidx.compose.foundation.text.modifiers
import androidx.compose.foundation.text.DefaultMinLines
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
@@ -44,7 +47,12 @@
import androidx.compose.ui.node.invalidateMeasurement
import androidx.compose.ui.node.invalidateSemantics
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
+import androidx.compose.ui.semantics.clearTextSubstitution
import androidx.compose.ui.semantics.getTextLayoutResult
+import androidx.compose.ui.semantics.isShowingTextSubstitution
+import androidx.compose.ui.semantics.originalText
+import androidx.compose.ui.semantics.setTextSubstitution
+import androidx.compose.ui.semantics.showTextSubstitution
import androidx.compose.ui.semantics.text
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextLayoutResult
@@ -93,6 +101,13 @@
}
private fun getLayoutCache(density: Density): ParagraphLayoutCache {
+ textSubstitution?.let { textSubstitutionValue ->
+ if (textSubstitutionValue.isShowingSubstitution) {
+ textSubstitutionValue.layoutCache?.let { cache ->
+ return cache.also { it.density = density }
+ }
+ }
+ }
return layoutCache.also { it.density = density }
}
@@ -112,6 +127,7 @@
fun updateText(text: String): Boolean {
if (this.text == text) return false
this.text = text
+ clearSubstitution()
return true
}
@@ -167,8 +183,10 @@
textChanged: Boolean,
layoutChanged: Boolean
) {
- if (textChanged) {
- invalidateSemantics()
+ if (textChanged || (drawChanged && semanticsTextLayoutResult != null)) {
+ if (isAttached) {
+ invalidateSemantics()
+ }
}
if (textChanged || layoutChanged) {
@@ -181,7 +199,9 @@
maxLines = maxLines,
minLines = minLines
)
- invalidateMeasurement()
+ if (isAttached) {
+ invalidateMeasurement()
+ }
invalidateDraw()
}
if (drawChanged) {
@@ -191,19 +211,110 @@
private var semanticsTextLayoutResult: ((MutableList<TextLayoutResult>) -> Boolean)? = null
+ data class TextSubstitutionValue(
+ val original: String,
+ var substitution: String,
+ var isShowingSubstitution: Boolean = false,
+ var layoutCache: ParagraphLayoutCache? = null,
+ // TODO(klikli): add animation
+ )
+
+ private var textSubstitution: TextSubstitutionValue? by mutableStateOf(null)
+
+ private fun setSubstitution(updatedText: String): Boolean {
+ val currentTextSubstitution = textSubstitution
+ if (currentTextSubstitution != null) {
+ if (updatedText == currentTextSubstitution.substitution) {
+ return false
+ }
+ currentTextSubstitution.substitution = updatedText
+ currentTextSubstitution.layoutCache?.update(
+ updatedText,
+ style,
+ fontFamilyResolver,
+ overflow,
+ softWrap,
+ maxLines,
+ minLines,
+ ) ?: return false
+ } else {
+ val newTextSubstitution = TextSubstitutionValue(text, updatedText)
+ val substitutionLayoutCache = ParagraphLayoutCache(
+ updatedText,
+ style,
+ fontFamilyResolver,
+ overflow,
+ softWrap,
+ maxLines,
+ minLines,
+ )
+ substitutionLayoutCache.density = layoutCache.density
+ newTextSubstitution.layoutCache = substitutionLayoutCache
+ textSubstitution = newTextSubstitution
+ }
+ return true
+ }
+
+ private fun clearSubstitution() {
+ textSubstitution = null
+ }
+
override fun SemanticsPropertyReceiver.applySemantics() {
var localSemanticsTextLayoutResult = semanticsTextLayoutResult
if (localSemanticsTextLayoutResult == null) {
localSemanticsTextLayoutResult = { textLayoutResult ->
- val layout = layoutCache.slowCreateTextLayoutResultOrNull()?.also {
+ val layout = layoutCache.slowCreateTextLayoutResultOrNull(
+ style = style.merge(
+ color = overrideColor?.invoke() ?: Color.Unspecified
+ )
+ )?.also {
textLayoutResult.add(it)
}
layout != null
- false
}
semanticsTextLayoutResult = localSemanticsTextLayoutResult
}
- this.text = AnnotatedString(this@TextStringSimpleNode.text)
+
+ val currentTextSubstitution = textSubstitution
+ if (currentTextSubstitution == null) {
+ text = AnnotatedString(this@TextStringSimpleNode.text)
+ } else {
+ isShowingTextSubstitution = currentTextSubstitution.isShowingSubstitution
+ if (currentTextSubstitution.isShowingSubstitution) {
+ text = AnnotatedString(currentTextSubstitution.substitution)
+ originalText = AnnotatedString(currentTextSubstitution.original)
+ } else {
+ text = AnnotatedString(currentTextSubstitution.original)
+ }
+ }
+
+ setTextSubstitution { updatedText ->
+ setSubstitution(updatedText.text)
+
+ true
+ }
+ showTextSubstitution {
+ if (textSubstitution == null) {
+ return@showTextSubstitution false
+ }
+
+ textSubstitution?.isShowingSubstitution = it
+
+ invalidateSemantics()
+ invalidateMeasurement()
+ invalidateDraw()
+
+ true
+ }
+ clearTextSubstitution {
+ clearSubstitution()
+
+ invalidateSemantics()
+ invalidateMeasurement()
+ invalidateDraw()
+
+ true
+ }
getTextLayoutResult(action = localSemanticsTextLayoutResult)
}
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationStateTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationStateTest.kt
index 57c6bab..893b62c 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationStateTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationStateTest.kt
@@ -16,6 +16,7 @@
package androidx.compose.foundation.gestures
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.runtime.MonotonicFrameClock
import androidx.compose.ui.MotionDurationScale
import com.google.common.truth.Truth.assertThat
@@ -30,7 +31,9 @@
class UpdatableAnimationStateTest {
private val frameClock = TestFrameClock()
- private val state = UpdatableAnimationState()
+
+ @OptIn(ExperimentalFoundationApi::class)
+ private val state = UpdatableAnimationState(BringIntoViewScroller.DefaultScrollAnimationSpec)
@Test
fun animateToZero_doesNothing_whenValueIsZero() {
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextEditFilterTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextEditFilterTest.kt
new file mode 100644
index 0000000..b6fd7c1
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextEditFilterTest.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.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.ui.text.input.KeyboardType
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+@OptIn(ExperimentalFoundationApi::class)
+class TextEditFilterTest {
+
+ @Test
+ fun chainedFilters_areEqual() {
+ val filter1 = TextEditFilter { _, _ ->
+ // Noop
+ }
+ val filter2 = TextEditFilter { _, _ ->
+ // Noop
+ }
+
+ val chain1 = filter1.then(
+ filter2,
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email)
+ )
+ val chain2 = filter1.then(
+ filter2,
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email)
+ )
+
+ assertThat(chain1).isEqualTo(chain2)
+ }
+
+ @Test
+ fun chainedFilters_areNotEqual_whenKeyboardOptionsDifferent() {
+ val filter1 = TextEditFilter { _, _ ->
+ // Noop
+ }
+ val filter2 = TextEditFilter { _, _ ->
+ // Noop
+ }
+
+ val chain1 = filter1.then(
+ filter2,
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email)
+ )
+ val chain2 = filter1.then(
+ filter2,
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
+ )
+
+ assertThat(chain1).isNotEqualTo(chain2)
+ }
+
+ @Test
+ fun chainedFilters_areNotEqual_whenFiltersAreDifferent() {
+ val filter1 = TextEditFilter { _, _ ->
+ // Noop
+ }
+ val filter2 = TextEditFilter { _, _ ->
+ // Noop
+ }
+ val filter3 = TextEditFilter { _, _ ->
+ // Noop
+ }
+
+ val chain1 = filter1.then(filter2)
+ val chain2 = filter1.then(filter3)
+
+ assertThat(chain1).isNotEqualTo(chain2)
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelectionTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelectionTest.kt
new file mode 100644
index 0000000..f511c90
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelectionTest.kt
@@ -0,0 +1,243 @@
+/*
+ * 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.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.TextFieldValue
+import com.google.common.truth.Truth.assertThat
+import java.text.ParseException
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalFoundationApi::class)
+@RunWith(JUnit4::class)
+class TextFieldBufferWithSelectionTest {
+
+ @Test
+ fun initialSelection() {
+ val state = TextFieldBufferWithSelection(TextFieldCharSequence())
+ assertThat(state.selectionInChars).isEqualTo(TextRange(0))
+ assertThat(state.hasSelection).isFalse()
+ }
+
+ @Test
+ fun selectionAdjusted_empty_textInserted() {
+ testSelectionAdjustment("", { append("hello") }, "hello_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenCursorAtStart_textInsertedAtCursor() {
+ testSelectionAdjustment("_hello", { insert(0, "world") }, "world_hello")
+ }
+
+ @Test
+ fun selectionAdjusted_whenCursorAtStart_textInsertedAfterCursor() {
+ testSelectionAdjustment("_hello", { append("world") }, "_helloworld")
+ }
+
+ @Test
+ fun selectionAdjusted_whenCursorAtStart_textReplacedAroundCursor() {
+ testSelectionAdjustment("_hello", { replace(0, length, "foo") }, "_foo")
+ }
+
+ @Test
+ fun selectionAdjusted_whenCursorAtEnd_textInsertedAtCursor() {
+ testSelectionAdjustment("hello_", { append("world") }, "helloworld_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenCursorAtEnd_textInsertedBeforeCursor() {
+ testSelectionAdjustment("hello_", { insert(0, "world") }, "worldhello_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenCursorAtEnd_textReplacedAroundCursor() {
+ testSelectionAdjustment("hello_", { replace(0, length, "foo") }, "foo_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenCursorInMiddle_textInsertedAtCursor() {
+ testSelectionAdjustment("he_llo", { insert(2, "foo") }, "hefoo_llo")
+ }
+
+ @Test
+ fun selectionAdjusted_whenCursorInMiddle_textReplacedJustBeforeCursor() {
+ testSelectionAdjustment("he_llo", { replace(0, 2, "foo") }, "foo_llo")
+ }
+
+ @Test
+ fun selectionAdjusted_whenCursorInMiddle_textReplacedJustAfterCursor() {
+ testSelectionAdjustment("he_llo", { replace(2, 3, "foo") }, "he_foolo")
+ }
+
+ @Test
+ fun selectionAdjusted_whenCursorInMiddle_textReplacedAroundCursor() {
+ testSelectionAdjustment("he_llo", { replace(1, 3, "foo") }, "hfoo_lo")
+ }
+
+ @Test
+ fun selectionAdjusted_whenAllSelected_allReplacedWithShorter() {
+ testSelectionAdjustment("_hello_", { replace(0, length, "foo") }, "_foo_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenAllSelected_allReplacedWithLonger() {
+ testSelectionAdjustment("_hello_", { replace(0, length, "abracadabra") }, "_abracadabra_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenAllSelected_textReplacedInsideSelection_withLonger() {
+ testSelectionAdjustment("_hello_", { replace(1, 4, "world") }, "_hworldo_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenAllSelected_textReplacedInsideSelection_withShorter() {
+ testSelectionAdjustment("_hello_", { replace(1, 4, "w") }, "_hwo_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenAllSelected_textReplacedInsideFromStart_withLonger() {
+ testSelectionAdjustment("_hello_", { replace(0, 3, "world") }, "_worldlo_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenAllSelected_textReplacedInsideFromStart_withShorter() {
+ testSelectionAdjustment("_hello_", { replace(1, 3, "w") }, "_hwlo_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenAllSelected_textReplacedInsideToEnd_withLonger() {
+ testSelectionAdjustment("_hello_", { replace(length - 3, length, "world") }, "_heworld_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenAllSelected_textReplacedInsideToEnd_withShorter() {
+ testSelectionAdjustment("_hello_", { replace(length - 3, length, "w") }, "_hew_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenInsideSelected_textReplacedJustBeforeSelection() {
+ testSelectionAdjustment("hel_lo_", { replace(0, 3, "world") }, "world_lo_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenInsideSelected_textReplacedJustAfterSelection() {
+ testSelectionAdjustment("_he_llo", { replace(2, length, "world") }, "_he_world")
+ }
+
+ @Test
+ fun selectionAdjusted_whenInsideSelected_textReplacedAroundStart() {
+ testSelectionAdjustment("h_ello_", { replace(0, 3, "world") }, "world_lo_")
+ }
+
+ @Test
+ fun selectionAdjusted_whenInsideSelected_textReplacedAroundEnd() {
+ testSelectionAdjustment("_hell_o", { replace(2, length, "world") }, "_he_world")
+ }
+
+ @Test
+ fun resetTo_copiesTextAndSelection() {
+ val expectedValue = TextFieldCharSequence("world", TextRange(5))
+ val state = TextFieldBufferWithSelection(
+ value = TextFieldCharSequence("hello", TextRange(2)),
+ sourceValue = expectedValue
+ )
+ state.revertAllChanges()
+ assertThat(state.toTextFieldCharSequence()).isEqualTo(expectedValue)
+ assertThat(state.changes.changeCount).isEqualTo(0)
+ }
+
+ @Test
+ fun testConvertTextFieldValueToAndFromString() {
+ assertThat("".parseAsTextEditState()).isEqualTo(TextFieldCharSequence())
+ assertThat("hello".parseAsTextEditState()).isEqualTo(TextFieldCharSequence("hello"))
+ assertThat("_hello".parseAsTextEditState()).isEqualTo(TextFieldCharSequence("hello"))
+ assertThat("h_ello".parseAsTextEditState())
+ .isEqualTo(TextFieldCharSequence("hello", selection = TextRange(1)))
+ assertThat("hello_".parseAsTextEditState())
+ .isEqualTo(TextFieldCharSequence("hello", selection = TextRange(5)))
+ assertThat("_hello_".parseAsTextEditState())
+ .isEqualTo(TextFieldCharSequence("hello", selection = TextRange(0, 5)))
+ assertThat("he__llo".parseAsTextEditState())
+ .isEqualTo(TextFieldCharSequence("hello", selection = TextRange(2)))
+ assertThat("he_l_lo".parseAsTextEditState())
+ .isEqualTo(TextFieldCharSequence("hello", selection = TextRange(2, 3)))
+ assertFailsWith<ParseException> {
+ "_he_llo_".parseAsTextEditState()
+ }
+
+ listOf("", "_hello", "h_ello", "hello_", "_hello_", "he_ll_o").forEach {
+ val value = it.parseAsTextEditState()
+ assertThat(value.toParsableString()).isEqualTo(it)
+ }
+ }
+
+ private fun testSelectionAdjustment(
+ initial: String,
+ transform: TextFieldBufferWithSelection.() -> Unit,
+ expected: String
+ ) {
+ val state = TextFieldBufferWithSelection(initial.parseAsTextEditState())
+ state.transform()
+ assertThat(state.toTextFieldCharSequence().toParsableString()).isEqualTo(expected)
+ }
+
+ /**
+ * Parses this string into a [TextFieldValue], replacing a single underscore with the cursor, or
+ * two underscores with a selection.
+ */
+ private fun String.parseAsTextEditState(): TextFieldCharSequence {
+ var firstMark = -1
+ var secondMark = -1
+ val source = this
+ val text = buildString {
+ source.forEachIndexed { i, char ->
+ if (char == '_') {
+ when {
+ firstMark == -1 -> firstMark = i
+ secondMark == -1 -> secondMark = i - 1
+ else -> throw ParseException("Unexpected underscore in \"$this\"", i)
+ }
+ } else {
+ append(char)
+ }
+ }
+ }
+
+ return TextFieldCharSequence(
+ text = text,
+ selection = when {
+ firstMark == -1 -> TextRange.Zero
+ secondMark == -1 -> TextRange(firstMark)
+ else -> TextRange(firstMark, secondMark)
+ }
+ )
+ }
+
+ private fun TextFieldCharSequence.toParsableString(): String = buildString {
+ append(this@toParsableString)
+ if (isNotEmpty()) {
+ insert(selectionInChars.min, '_')
+ if (!selectionInChars.collapsed) {
+ insert(selectionInChars.max + 1, '_')
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequenceTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequenceTest.kt
new file mode 100644
index 0000000..aa490d8
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequenceTest.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.runtime.saveable.SaverScope
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalFoundationApi::class)
+@RunWith(JUnit4::class)
+class TextFieldCharSequenceTest {
+ private val defaultSaverScope = SaverScope { true }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun throws_exception_for_negative_selection() {
+ TextFieldCharSequence(text = "", selection = TextRange(-1))
+ }
+
+ @Test
+ fun aligns_selection_to_the_text_length() {
+ val text = "a"
+ val textFieldValue =
+ TextFieldCharSequence(text = text, selection = TextRange(text.length + 1))
+ assertThat(textFieldValue.selectionInChars.collapsed).isTrue()
+ assertThat(textFieldValue.selectionInChars.max).isEqualTo(textFieldValue.length)
+ }
+
+ @Test
+ fun keep_selection_that_is_less_than_text_length() {
+ val text = "a bc"
+ val selection = TextRange(0, "a".length)
+
+ val textFieldValue = TextFieldCharSequence(text = text, selection = selection)
+
+ assertThat(textFieldValue.toString()).isEqualTo(text)
+ assertThat(textFieldValue.selectionInChars).isEqualTo(selection)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun throws_exception_for_negative_composition() {
+ TextEditState(text = "", composition = TextRange(-1))
+ }
+
+ @Test
+ fun aligns_composition_to_text_length() {
+ val text = "a"
+ val textFieldValue = TextEditState(text = text, composition = TextRange(text.length + 1))
+ assertThat(textFieldValue.compositionInChars?.collapsed).isTrue()
+ assertThat(textFieldValue.compositionInChars?.max).isEqualTo(textFieldValue.length)
+ }
+
+ @Test
+ fun keep_composition_that_is_less_than_text_length() {
+ val text = "a bc"
+ val composition = TextRange(0, "a".length)
+
+ val textFieldValue = TextEditState(text = text, composition = composition)
+
+ assertThat(textFieldValue.toString()).isEqualTo(text)
+ assertThat(textFieldValue.compositionInChars).isEqualTo(composition)
+ }
+
+ @Test
+ fun equals_returns_true_for_same_instance() {
+ val textFieldValue = TextFieldCharSequence(
+ text = "a",
+ selection = TextRange(1),
+ composition = TextRange(2)
+ )
+
+ assertThat(textFieldValue).isEqualTo(textFieldValue)
+ }
+
+ @Test
+ fun equals_returns_true_for_equivalent_object() {
+ val textFieldValue = TextFieldCharSequence(
+ text = "a",
+ selection = TextRange(1),
+ composition = TextRange(2)
+ )
+
+ assertThat(
+ TextFieldCharSequence(
+ textFieldValue,
+ textFieldValue.selectionInChars,
+ textFieldValue.compositionInChars
+ )
+ ).isEqualTo(textFieldValue)
+ }
+
+ @Test
+ fun text_and_selection_parameter_constructor_has_null_composition() {
+ val textFieldValue = TextFieldCharSequence(
+ text = "a",
+ selection = TextRange(1)
+ )
+
+ assertThat(textFieldValue.compositionInChars).isNull()
+ }
+
+ private fun TextEditState(text: String, composition: TextRange) =
+ TextFieldCharSequence(text, selection = TextRange.Zero, composition = composition)
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateSaverTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateSaverTest.kt
new file mode 100644
index 0000000..4325a6a
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateSaverTest.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.runtime.saveable.SaverScope
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertNotNull
+import org.junit.Test
+
+@OptIn(ExperimentalFoundationApi::class)
+class TextFieldStateSaverTest {
+
+ @Test
+ fun savesAndRestoresTextAndSelection() {
+ val state = TextFieldState("hello, world", initialSelectionInChars = TextRange(0, 5))
+
+ val saved = with(TextFieldState.Saver) { TestSaverScope.save(state) }
+ assertNotNull(saved)
+ val restoredState = TextFieldState.Saver.restore(saved)
+
+ assertNotNull(restoredState)
+ assertThat(restoredState.text.toString()).isEqualTo("hello, world")
+ assertThat(restoredState.text.selectionInChars).isEqualTo(TextRange(0, 5))
+ }
+
+ private object TestSaverScope : SaverScope {
+ override fun canBeSaved(value: Any): Boolean = true
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateTest.kt
new file mode 100644
index 0000000..15de948
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateTest.kt
@@ -0,0 +1,514 @@
+/*
+ * 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.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.runtime.snapshots.Snapshot
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.cancelChildren
+import kotlinx.coroutines.job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalFoundationApi::class, ExperimentalCoroutinesApi::class)
+@RunWith(JUnit4::class)
+class TextFieldStateTest {
+
+ private val state = TextFieldState()
+
+ @Test
+ fun initialValue() {
+ assertThat(state.text.toString()).isEqualTo("")
+ }
+
+ @Test
+ fun edit_doesNotChange_whenThrows() {
+ class ExpectedException : RuntimeException()
+
+ assertFailsWith<ExpectedException> {
+ state.edit {
+ replace(0, 0, "hello")
+ throw ExpectedException()
+ }
+ }
+
+ assertThat(state.text.toString()).isEmpty()
+ }
+
+ @Test
+ fun edit_replace_changesValueInPlace() {
+ state.edit {
+ replace(0, 0, "hello")
+ assertThat(toString()).isEqualTo("hello")
+ assertThat(length).isEqualTo(5)
+ placeCursorAtEnd()
+ }
+ }
+
+ @Test
+ fun edit_replace_changesStateAfterReturn() {
+ state.edit {
+ replace(0, 0, "hello")
+ placeCursorAtEnd()
+ }
+ assertThat(state.text.toString()).isEqualTo("hello")
+ }
+
+ @Test
+ fun edit_replace_doesNotChangeStateUntilReturn() {
+ state.edit {
+ replace(0, 0, "hello")
+ assertThat(state.text.toString()).isEmpty()
+ placeCursorAtEnd()
+ }
+ }
+
+ @Test
+ fun edit_multipleOperations() {
+ state.edit {
+ replace(0, 0, "hello")
+ replace(5, 5, "world")
+ replace(5, 5, " ")
+ replace(6, 11, "Compose")
+ assertThat(toString()).isEqualTo("hello Compose")
+ assertThat(state.text.toString()).isEmpty()
+ placeCursorAtEnd()
+ }
+ assertThat(state.text.toString()).isEqualTo("hello Compose")
+ }
+
+ @Test
+ fun edit_placeCursorAtEnd() {
+ state.edit {
+ replace(0, 0, "hello")
+ placeCursorAtEnd()
+ }
+ assertThat(state.text.selectionInChars).isEqualTo(TextRange(5))
+ }
+
+ @Test
+ fun edit_placeCursorBeforeChar_simpleCase() {
+ state.edit {
+ replace(0, 0, "hello")
+ placeCursorBeforeCharAt(2)
+ }
+ assertThat(state.text.selectionInChars).isEqualTo(TextRange(2))
+ }
+
+ @Test
+ fun edit_placeCursorBeforeChar_throws_whenInvalid() {
+ state.edit {
+ assertFailsWith<IllegalArgumentException> {
+ placeCursorBeforeCharAt(500)
+ }
+ assertFailsWith<IllegalArgumentException> {
+ placeCursorBeforeCharAt(-1)
+ }
+ placeCursorAtEnd()
+ }
+ }
+
+ @Test
+ fun edit_placeCursorBeforeCodepoint_simpleCase() {
+ state.edit {
+ replace(0, 0, "hello")
+ placeCursorBeforeCodepointAt(2)
+ }
+ assertThat(state.text.selectionInChars).isEqualTo(TextRange(2))
+ }
+
+ @Test
+ fun edit_placeCursorBeforeCodepoint_throws_whenInvalid() {
+ state.edit {
+ assertFailsWith<IllegalArgumentException> {
+ placeCursorBeforeCodepointAt(500)
+ }
+ assertFailsWith<IllegalArgumentException> {
+ placeCursorBeforeCodepointAt(-1)
+ }
+ placeCursorAtEnd()
+ }
+ }
+
+ @Test
+ fun edit_selectAll() {
+ state.edit {
+ replace(0, 0, "hello")
+ selectAll()
+ }
+ assertThat(state.text.selectionInChars).isEqualTo(TextRange(0, 5))
+ }
+
+ @Test
+ fun edit_selectChars_simpleCase() {
+ state.edit {
+ replace(0, 0, "hello")
+ selectCharsIn(TextRange(1, 4))
+ }
+ assertThat(state.text.selectionInChars).isEqualTo(TextRange(1, 4))
+ }
+
+ @Test
+ fun edit_selectChars_throws_whenInvalid() {
+ state.edit {
+ assertFailsWith<IllegalArgumentException> {
+ selectCharsIn(TextRange(500, 501))
+ }
+ assertFailsWith<IllegalArgumentException> {
+ selectCharsIn(TextRange(-1, 500))
+ }
+ assertFailsWith<IllegalArgumentException> {
+ selectCharsIn(TextRange(500, -1))
+ }
+ assertFailsWith<IllegalArgumentException> {
+ selectCharsIn(TextRange(-500, -1))
+ }
+ placeCursorAtEnd()
+ }
+ }
+
+ @Test
+ fun edit_selectCodepoints_simpleCase() {
+ state.edit {
+ replace(0, 0, "hello")
+ selectCodepointsIn(TextRange(1, 4))
+ }
+ assertThat(state.text.selectionInChars).isEqualTo(TextRange(1, 4))
+ }
+
+ @Test
+ fun edit_selectCodepoints_throws_whenInvalid() {
+ state.edit {
+ assertFailsWith<IllegalArgumentException> {
+ selectCodepointsIn(TextRange(500, 501))
+ }
+ assertFailsWith<IllegalArgumentException> {
+ selectCodepointsIn(TextRange(-1, 500))
+ }
+ assertFailsWith<IllegalArgumentException> {
+ selectCodepointsIn(TextRange(500, -1))
+ }
+ assertFailsWith<IllegalArgumentException> {
+ selectCodepointsIn(TextRange(-500, -1))
+ }
+ placeCursorAtEnd()
+ }
+ }
+
+ @Test
+ fun edit_afterEdit() {
+ state.edit {
+ replace(0, 0, "hello")
+ placeCursorAtEnd()
+ }
+ state.edit {
+ assertThat(toString()).isEqualTo("hello")
+ replace(5, 5, " world")
+ assertThat(toString()).isEqualTo("hello world")
+ placeCursorAtEnd()
+ }
+ assertThat(state.text.toString()).isEqualTo("hello world")
+ }
+
+ @Test
+ fun append_char() {
+ state.edit {
+ append('c')
+ placeCursorAtEnd()
+ }
+ assertThat(state.text.toString()).isEqualTo("c")
+ }
+
+ @Test
+ fun append_charSequence() {
+ state.edit {
+ append("hello")
+ placeCursorAtEnd()
+ }
+ assertThat(state.text.toString()).isEqualTo("hello")
+ }
+
+ @Test
+ fun append_charSequence_range() {
+ state.edit {
+ append("hello world", 0, 5)
+ placeCursorAtEnd()
+ }
+ assertThat(state.text.toString()).isEqualTo("hello")
+ }
+
+ @Test
+ fun setTextAndPlaceCursorAtEnd_works() {
+ state.setTextAndPlaceCursorAtEnd("Hello")
+ assertThat(state.text.toString()).isEqualTo("Hello")
+ assertThat(state.text.selectionInChars).isEqualTo(TextRange(5))
+ }
+
+ @Test
+ fun setTextAndSelectAll_works() {
+ state.setTextAndSelectAll("Hello")
+ assertThat(state.text.toString()).isEqualTo("Hello")
+ assertThat(state.text.selectionInChars).isEqualTo(TextRange(0, 5))
+ }
+
+ @Test
+ fun replace_changesAreTracked() {
+ val state = TextFieldState("hello world")
+ state.edit {
+ replace(6, 11, "Compose")
+ assertThat(toString()).isEqualTo("hello Compose")
+ assertThat(changes.changeCount).isEqualTo(1)
+ assertThat(changes.getRange(0)).isEqualTo(TextRange(6, 13))
+ assertThat(changes.getOriginalRange(0)).isEqualTo(TextRange(6, 11))
+ placeCursorAtEnd()
+ }
+ }
+
+ @Test
+ fun appendChar_changesAreTracked() {
+ val state = TextFieldState("hello ")
+ state.edit {
+ append('c')
+ assertThat(toString()).isEqualTo("hello c")
+ assertThat(changes.changeCount).isEqualTo(1)
+ assertThat(changes.getRange(0)).isEqualTo(TextRange(6, 7))
+ assertThat(changes.getOriginalRange(0)).isEqualTo(TextRange(6))
+ placeCursorAtEnd()
+ }
+ }
+
+ @Test
+ fun appendCharSequence_changesAreTracked() {
+ val state = TextFieldState("hello ")
+ state.edit {
+ append("world")
+ assertThat(toString()).isEqualTo("hello world")
+ assertThat(changes.changeCount).isEqualTo(1)
+ assertThat(changes.getRange(0)).isEqualTo(TextRange(6, 11))
+ assertThat(changes.getOriginalRange(0)).isEqualTo(TextRange(6))
+ placeCursorAtEnd()
+ }
+ }
+
+ @Test
+ fun appendCharSequenceRange_changesAreTracked() {
+ val state = TextFieldState("hello ")
+ state.edit {
+ append("hello world", 6, 11)
+ assertThat(toString()).isEqualTo("hello world")
+ assertThat(changes.changeCount).isEqualTo(1)
+ assertThat(changes.getRange(0)).isEqualTo(TextRange(6, 11))
+ assertThat(changes.getOriginalRange(0)).isEqualTo(TextRange(6))
+ placeCursorAtEnd()
+ }
+ }
+
+ @Test
+ fun forEachValues_fires_immediately() = runTestWithSnapshotsThenCancelChildren {
+ val state = TextFieldState("hello", initialSelectionInChars = TextRange(5))
+ val texts = mutableListOf<TextFieldCharSequence>()
+
+ launch(Dispatchers.Unconfined) {
+ state.forEachTextValue { texts += it }
+ }
+
+ assertThat(texts).hasSize(1)
+ assertThat(texts.single()).isSameInstanceAs(state.text)
+ assertThat(texts.single().toString()).isEqualTo("hello")
+ assertThat(texts.single().selectionInChars).isEqualTo(TextRange(5))
+ }
+
+ @Test
+ fun forEachValue_fires_whenTextChanged() = runTestWithSnapshotsThenCancelChildren {
+ val state = TextFieldState(initialSelectionInChars = TextRange(0))
+ val texts = mutableListOf<TextFieldCharSequence>()
+ val initialText = state.text
+
+ launch(Dispatchers.Unconfined) {
+ state.forEachTextValue { texts += it }
+ }
+
+ state.edit {
+ append("hello")
+ placeCursorBeforeCharAt(0)
+ }
+
+ assertThat(texts).hasSize(2)
+ assertThat(texts.last()).isSameInstanceAs(state.text)
+ assertThat(texts.last().toString()).isEqualTo("hello")
+ assertThat(texts.last().selectionInChars).isEqualTo(initialText.selectionInChars)
+ }
+
+ @Test
+ fun forEachValue_fires_whenSelectionChanged() = runTestWithSnapshotsThenCancelChildren {
+ val state = TextFieldState("hello", initialSelectionInChars = TextRange(0))
+ val texts = mutableListOf<TextFieldCharSequence>()
+
+ launch(Dispatchers.Unconfined) {
+ state.forEachTextValue { texts += it }
+ }
+
+ state.edit {
+ placeCursorAtEnd()
+ }
+
+ assertThat(texts).hasSize(2)
+ assertThat(texts.last()).isSameInstanceAs(state.text)
+ assertThat(texts.last().toString()).isEqualTo("hello")
+ assertThat(texts.last().selectionInChars).isEqualTo(TextRange(5))
+ }
+
+ @Test
+ fun forEachValue_firesTwice_whenEditCalledTwice() = runTestWithSnapshotsThenCancelChildren {
+ val state = TextFieldState()
+ val texts = mutableListOf<TextFieldCharSequence>()
+
+ launch(Dispatchers.Unconfined) {
+ state.forEachTextValue { texts += it }
+ }
+
+ state.edit {
+ append("hello")
+ placeCursorAtEnd()
+ }
+
+ state.edit {
+ append(" world")
+ placeCursorAtEnd()
+ }
+
+ assertThat(texts).hasSize(3)
+ assertThat(texts[1].toString()).isEqualTo("hello")
+ assertThat(texts[2]).isSameInstanceAs(state.text)
+ assertThat(texts[2].toString()).isEqualTo("hello world")
+ }
+
+ @Test
+ fun forEachValue_firesOnce_whenMultipleChangesMadeInSingleEdit() =
+ runTestWithSnapshotsThenCancelChildren {
+ val state = TextFieldState()
+ val texts = mutableListOf<TextFieldCharSequence>()
+
+ launch(Dispatchers.Unconfined) {
+ state.forEachTextValue { texts += it }
+ }
+
+ state.edit {
+ append("hello")
+ append(" world")
+ placeCursorAtEnd()
+ }
+
+ assertThat(texts.last()).isSameInstanceAs(state.text)
+ assertThat(texts.last().toString()).isEqualTo("hello world")
+ }
+
+ @Test
+ fun forEachValue_fires_whenChangeMadeInSnapshotIsApplied() =
+ runTestWithSnapshotsThenCancelChildren {
+ val state = TextFieldState()
+ val texts = mutableListOf<TextFieldCharSequence>()
+
+ launch(Dispatchers.Unconfined) {
+ state.forEachTextValue { texts += it }
+ }
+
+ val snapshot = Snapshot.takeMutableSnapshot()
+ snapshot.enter {
+ state.edit {
+ append("hello")
+ placeCursorAtEnd()
+ }
+ assertThat(texts.isEmpty())
+ }
+ assertThat(texts.isEmpty())
+
+ snapshot.apply()
+ snapshot.dispose()
+
+ assertThat(texts.last()).isSameInstanceAs(state.text)
+ }
+
+ @Test
+ fun forEachValue_notFired_whenChangeMadeInSnapshotThenDisposed() =
+ runTestWithSnapshotsThenCancelChildren {
+ val state = TextFieldState()
+ val texts = mutableListOf<TextFieldCharSequence>()
+
+ launch(Dispatchers.Unconfined) {
+ state.forEachTextValue { texts += it }
+ }
+
+ val snapshot = Snapshot.takeMutableSnapshot()
+ snapshot.enter {
+ state.edit {
+ append("hello")
+ placeCursorAtEnd()
+ }
+ }
+ snapshot.dispose()
+
+ // Only contains initial value.
+ assertThat(texts).hasSize(1)
+ assertThat(texts.single().toString()).isEmpty()
+ }
+
+ @Test
+ fun forEachValue_cancelsPreviousHandler_whenChangeMadeWhileSuspended() =
+ runTestWithSnapshotsThenCancelChildren {
+ val state = TextFieldState()
+ val texts = mutableListOf<TextFieldCharSequence>()
+
+ launch(Dispatchers.Unconfined) {
+ state.forEachTextValue {
+ texts += it
+ awaitCancellation()
+ }
+ }
+
+ state.setTextAndPlaceCursorAtEnd("hello")
+ state.setTextAndPlaceCursorAtEnd("world")
+
+ assertThat(texts.map { it.toString() })
+ .containsExactly("", "hello", "world")
+ .inOrder()
+ }
+
+ private fun runTestWithSnapshotsThenCancelChildren(testBody: suspend TestScope.() -> Unit) {
+ val globalWriteObserverHandle = Snapshot.registerGlobalWriteObserver {
+ // This is normally done by the compose runtime.
+ Snapshot.sendApplyNotifications()
+ }
+ try {
+ runTest {
+ testBody()
+ coroutineContext.job.cancelChildren()
+ }
+ } finally {
+ globalWriteObserverHandle.dispose()
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTrackerTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTrackerTest.kt
new file mode 100644
index 0000000..b53c2b7
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTrackerTest.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.compose.foundation.text2.input.internal
+
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ChangeTrackerTest {
+
+ @Test
+ fun initialInsert() {
+ val buffer = SimpleBuffer()
+
+ buffer.append("hello")
+
+ assertThat(buffer.toString()).isEqualTo("hello")
+ assertThat(buffer.changes.changeCount).isEqualTo(1)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(0, 5))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(0))
+ }
+
+ @Test
+ fun deleteAll() {
+ val buffer = SimpleBuffer("hello")
+
+ buffer.replace("hello", "")
+
+ assertThat(buffer.toString()).isEqualTo("")
+ assertThat(buffer.changes.changeCount).isEqualTo(1)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(0, 0))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(0, 5))
+ }
+
+ @Test
+ fun multipleDiscontinuousChanges() {
+ val buffer = SimpleBuffer("hello world")
+
+ buffer.replace("world", "Compose")
+ buffer.replace("hello", "goodbye")
+
+ assertThat(buffer.toString()).isEqualTo("goodbye Compose")
+ assertThat(buffer.changes.changeCount).isEqualTo(2)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(0, 7))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(0, 5))
+ assertThat(buffer.changes.getRange(1)).isEqualTo(TextRange(8, 15))
+ assertThat(buffer.changes.getOriginalRange(1)).isEqualTo(TextRange(6, 11))
+ }
+
+ @Test
+ fun twoAppends() {
+ val buffer = SimpleBuffer()
+
+ buffer.append("foo")
+ buffer.append("bar")
+
+ assertThat(buffer.toString()).isEqualTo("foobar")
+ assertThat(buffer.changes.changeCount).isEqualTo(1)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(0, 6))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(0))
+ }
+
+ @Test
+ fun threeAppends() {
+ val buffer = SimpleBuffer()
+
+ buffer.append("foo")
+ buffer.append("bar")
+ buffer.append("baz")
+
+ assertThat(buffer.toString()).isEqualTo("foobarbaz")
+ assertThat(buffer.changes.changeCount).isEqualTo(1)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(0, 9))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(0))
+ }
+
+ @Test
+ fun multipleAdjacentReplaces_whenPerformedInOrder_replacementsShorter() {
+ val buffer = SimpleBuffer("abcd")
+
+ buffer.replace("ab", "e") // ecd
+ buffer.replace("cd", "f")
+
+ assertThat(buffer.toString()).isEqualTo("ef")
+ assertThat(buffer.changes.changeCount).isEqualTo(1)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(0, 2))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(0, 4))
+ }
+
+ @Test
+ fun multipleAdjacentReplaces_whenPerformedInOrder_replacementsLonger() {
+ val buffer = SimpleBuffer("abcd")
+
+ buffer.replace("ab", "efg") // efgcd
+ buffer.replace("cd", "hij")
+
+ assertThat(buffer.toString()).isEqualTo("efghij")
+ assertThat(buffer.changes.changeCount).isEqualTo(1)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(0, 6))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(0, 4))
+ }
+
+ @Test
+ fun multipleAdjacentReplaces_whenPerformedInReverseOrder_replacementsShorter() {
+ val buffer = SimpleBuffer("abcd")
+
+ buffer.replace("cd", "f") // abf
+ buffer.replace("ab", "e")
+
+ assertThat(buffer.toString()).isEqualTo("ef")
+ assertThat(buffer.changes.changeCount).isEqualTo(1)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(0, 2))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(0, 4))
+ }
+
+ @Test
+ fun multipleAdjacentReplaces_whenPerformedInReverseOrder_replacementsLonger() {
+ val buffer = SimpleBuffer("abcd")
+
+ buffer.replace("cd", "efg") // abhij
+ buffer.replace("ab", "hij")
+
+ assertThat(buffer.toString()).isEqualTo("hijefg")
+ assertThat(buffer.changes.changeCount).isEqualTo(1)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(0, 6))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(0, 4))
+ }
+
+ @Test
+ fun multiplePartiallyOverlappingChanges_atStart() {
+ val buffer = SimpleBuffer("abcd")
+
+ buffer.replace("bc", "ef") // aefd
+ buffer.replace("ae", "gh")
+
+ assertThat(buffer.toString()).isEqualTo("ghfd")
+ // Overlapping changes are merged.
+ assertThat(buffer.changes.changeCount).isEqualTo(1)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(0, 3))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(0, 3))
+ }
+
+ @Test
+ fun multiplePartiallyOverlappingChanges_atEnd() {
+ val buffer = SimpleBuffer("abcd")
+
+ buffer.replace("bc", "ef") // aefd
+ buffer.replace("fd", "gh")
+
+ assertThat(buffer.toString()).isEqualTo("aegh")
+ // Overlapping changes are merged.
+ assertThat(buffer.changes.changeCount).isEqualTo(1)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(1, 4))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(1, 4))
+ }
+
+ @Test
+ fun multipleFullyOverlappingChanges() {
+ val buffer = SimpleBuffer("abcd")
+
+ buffer.replace("bc", "ef") // aefd
+ buffer.replace("ef", "gh")
+
+ assertThat(buffer.toString()).isEqualTo("aghd")
+ // Overlapping changes are merged.
+ assertThat(buffer.changes.changeCount).isEqualTo(1)
+ assertThat(buffer.changes.getRange(0)).isEqualTo(TextRange(1, 3))
+ assertThat(buffer.changes.getOriginalRange(0)).isEqualTo(TextRange(1, 3))
+ }
+
+ private class SimpleBuffer(initialText: String = "") {
+ private val builder = StringBuilder(initialText)
+ val changes = ChangeTracker()
+
+ fun append(text: String) {
+ changes.trackChange(TextRange(builder.length), text.length)
+ builder.append(text)
+ }
+
+ fun replace(substring: String, text: String) {
+ val start = builder.indexOf(substring)
+ if (start != -1) {
+ val end = start + substring.length
+ changes.trackChange(TextRange(start, end), text.length)
+ builder.replace(start, end, text)
+ }
+ }
+
+ override fun toString(): String = builder.toString()
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/CommitTextCommandTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/CommitTextCommandTest.kt
new file mode 100644
index 0000000..08dd724
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/CommitTextCommandTest.kt
@@ -0,0 +1,185 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class CommitTextCommandTest {
+
+ @Test
+ fun test_insert_empty() {
+ val eb = EditingBuffer("", TextRange.Zero)
+
+ eb.update(CommitTextCommand("X", 1))
+
+ assertThat(eb.toString()).isEqualTo("X")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_insert_cursor_tail() {
+ val eb = EditingBuffer("A", TextRange(1))
+
+ eb.update(CommitTextCommand("X", 1))
+
+ assertThat(eb.toString()).isEqualTo("AX")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_insert_cursor_head() {
+ val eb = EditingBuffer("A", TextRange(1))
+
+ eb.update(CommitTextCommand("X", 0))
+
+ assertThat(eb.toString()).isEqualTo("AX")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_insert_cursor_far_tail() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+
+ eb.update(CommitTextCommand("X", 2))
+
+ assertThat(eb.toString()).isEqualTo("AXBCDE")
+ assertThat(eb.cursor).isEqualTo(3)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_insert_cursor_far_head() {
+ val eb = EditingBuffer("ABCDE", TextRange(4))
+
+ eb.update(CommitTextCommand("X", -2))
+
+ assertThat(eb.toString()).isEqualTo("ABCDXE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_insert_empty_text_cursor_head() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+
+ eb.update(CommitTextCommand("", 0))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_insert_empty_text_cursor_tail() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+
+ eb.update(CommitTextCommand("", 1))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_insert_empty_text_cursor_far_tail() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+
+ eb.update(CommitTextCommand("", 2))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_insert_empty_text_cursor_far_head() {
+ val eb = EditingBuffer("ABCDE", TextRange(4))
+
+ eb.update(CommitTextCommand("", -2))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_cancel_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(1, 4) // Mark "BCD" as composition
+ eb.update(CommitTextCommand("X", 1))
+
+ assertThat(eb.toString()).isEqualTo("AXE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_replace_selection() {
+ val eb = EditingBuffer("ABCDE", TextRange(1, 4)) // select "BCD"
+
+ eb.update(CommitTextCommand("X", 1))
+
+ assertThat(eb.toString()).isEqualTo("AXE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_composition_and_selection() {
+ val eb = EditingBuffer("ABCDE", TextRange(1, 3)) // select "BC"
+
+ eb.setComposition(2, 4) // Mark "CD" as composition
+ eb.update(CommitTextCommand("X", 1))
+
+ // If composition and selection exists at the same time, replace composition and cancel
+ // selection and place cursor.
+ assertThat(eb.toString()).isEqualTo("ABXE")
+ assertThat(eb.cursor).isEqualTo(3)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_cursor_position_too_small() {
+ val eb = EditingBuffer("ABCDE", TextRange(5))
+
+ eb.update(CommitTextCommand("X", -1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDEX")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_cursor_position_too_large() {
+ val eb = EditingBuffer("ABCDE", TextRange(5))
+
+ eb.update(CommitTextCommand("X", 1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDEX")
+ assertThat(eb.cursor).isEqualTo(6)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/DeleteSurroundingTextCommandTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/DeleteSurroundingTextCommandTest.kt
new file mode 100644
index 0000000..368b1d0
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/DeleteSurroundingTextCommandTest.kt
@@ -0,0 +1,238 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class DeleteSurroundingTextCommandTest {
+
+ @Test
+ fun test_delete_after() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+
+ eb.update(DeleteSurroundingTextCommand(0, 1))
+
+ assertThat(eb.toString()).isEqualTo("ACDE")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_before() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+
+ eb.update(DeleteSurroundingTextCommand(1, 0))
+
+ assertThat(eb.toString()).isEqualTo("BCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_both() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.update(DeleteSurroundingTextCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("ABE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_after_multiple() {
+ val eb = EditingBuffer("ABCDE", TextRange(2))
+
+ eb.update(DeleteSurroundingTextCommand(0, 2))
+
+ assertThat(eb.toString()).isEqualTo("ABE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_before_multiple() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.update(DeleteSurroundingTextCommand(2, 0))
+
+ assertThat(eb.toString()).isEqualTo("ADE")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_both_multiple() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.update(DeleteSurroundingTextCommand(2, 2))
+
+ assertThat(eb.toString()).isEqualTo("A")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_selection_preserve() {
+ val eb = EditingBuffer("ABCDE", TextRange(2, 4))
+
+ eb.update(DeleteSurroundingTextCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("ACD")
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(3)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_before_too_many() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.update(DeleteSurroundingTextCommand(1000, 0))
+
+ assertThat(eb.toString()).isEqualTo("DE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_after_too_many() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.update(DeleteSurroundingTextCommand(0, 1000))
+
+ assertThat(eb.toString()).isEqualTo("ABC")
+ assertThat(eb.cursor).isEqualTo(3)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_both_too_many() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.update(DeleteSurroundingTextCommand(1000, 1000))
+
+ assertThat(eb.toString()).isEqualTo("")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_composition_no_intersection_preceding_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.setComposition(0, 1)
+
+ eb.update(DeleteSurroundingTextCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("ABE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.compositionStart).isEqualTo(0)
+ assertThat(eb.compositionEnd).isEqualTo(1)
+ }
+
+ @Test
+ fun test_delete_composition_no_intersection_trailing_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.setComposition(4, 5)
+
+ eb.update(DeleteSurroundingTextCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("ABE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.compositionStart).isEqualTo(2)
+ assertThat(eb.compositionEnd).isEqualTo(3)
+ }
+
+ @Test
+ fun test_delete_composition_intersection_preceding_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.setComposition(0, 3)
+
+ eb.update(DeleteSurroundingTextCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("ABE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.compositionStart).isEqualTo(0)
+ assertThat(eb.compositionEnd).isEqualTo(2)
+ }
+
+ @Test
+ fun test_delete_composition_intersection_trailing_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.setComposition(3, 5)
+
+ eb.update(DeleteSurroundingTextCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("ABE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.compositionStart).isEqualTo(2)
+ assertThat(eb.compositionEnd).isEqualTo(3)
+ }
+
+ @Test
+ fun test_delete_covered_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.setComposition(2, 3)
+
+ eb.update(DeleteSurroundingTextCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("ABE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_composition_covered() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.setComposition(0, 5)
+
+ eb.update(DeleteSurroundingTextCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("ABE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.compositionStart).isEqualTo(0)
+ assertThat(eb.compositionEnd).isEqualTo(3)
+ }
+
+ @Test
+ fun throws_whenLengthBeforeInvalid() {
+ val error = assertFailsWith<IllegalArgumentException> {
+ DeleteSurroundingTextCommand(lengthBeforeCursor = -42, lengthAfterCursor = 0)
+ }
+ assertThat(error).hasMessageThat().contains("-42")
+ }
+
+ @Test
+ fun throws_whenLengthAfterInvalid() {
+ val error = assertFailsWith<IllegalArgumentException> {
+ DeleteSurroundingTextCommand(lengthBeforeCursor = 0, lengthAfterCursor = -42)
+ }
+ assertThat(error).hasMessageThat().contains("-42")
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/DeleteSurroundingTextInCodePointsCommandTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/DeleteSurroundingTextInCodePointsCommandTest.kt
new file mode 100644
index 0000000..14ee7f5
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/DeleteSurroundingTextInCodePointsCommandTest.kt
@@ -0,0 +1,249 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class DeleteSurroundingTextInCodePointsCommandTest {
+ val CH1 = "\uD83D\uDE00" // U+1F600
+ val CH2 = "\uD83D\uDE01" // U+1F601
+ val CH3 = "\uD83D\uDE02" // U+1F602
+ val CH4 = "\uD83D\uDE03" // U+1F603
+ val CH5 = "\uD83D\uDE04" // U+1F604
+
+ @Test
+ fun test_delete_after() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(2))
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(0, 1))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH3$CH4$CH5")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_before() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(2))
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(1, 0))
+
+ assertThat(eb.toString()).isEqualTo("$CH2$CH3$CH4$CH5")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_both() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH5")
+ assertThat(eb.cursor).isEqualTo(4)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_after_multiple() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(4))
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(0, 2))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH5")
+ assertThat(eb.cursor).isEqualTo(4)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_before_multiple() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(2, 0))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH4$CH5")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_both_multiple() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(2, 2))
+
+ assertThat(eb.toString()).isEqualTo(CH1)
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_selection_preserve() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(4, 8))
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH3$CH4")
+ assertThat(eb.selectionStart).isEqualTo(2)
+ assertThat(eb.selectionEnd).isEqualTo(6)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_before_too_many() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(1000, 0))
+
+ assertThat(eb.toString()).isEqualTo("$CH4$CH5")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_after_too_many() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(0, 1000))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH3")
+ assertThat(eb.cursor).isEqualTo(6)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_both_too_many() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(1000, 1000))
+
+ assertThat(eb.toString()).isEqualTo("")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_composition_no_intersection_preceding_composition() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.setComposition(0, 2)
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH5")
+ assertThat(eb.cursor).isEqualTo(4)
+ assertThat(eb.compositionStart).isEqualTo(0)
+ assertThat(eb.compositionEnd).isEqualTo(2)
+ }
+
+ @Test
+ fun test_delete_composition_no_intersection_trailing_composition() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.setComposition(8, 10)
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH5")
+ assertThat(eb.cursor).isEqualTo(4)
+ assertThat(eb.compositionStart).isEqualTo(4)
+ assertThat(eb.compositionEnd).isEqualTo(6)
+ }
+
+ @Test
+ fun test_delete_composition_intersection_preceding_composition() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.setComposition(0, 6)
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH5")
+ assertThat(eb.cursor).isEqualTo(4)
+ assertThat(eb.compositionStart).isEqualTo(0)
+ assertThat(eb.compositionEnd).isEqualTo(4)
+ }
+
+ @Test
+ fun test_delete_composition_intersection_trailing_composition() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.setComposition(6, 10)
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH5")
+ assertThat(eb.cursor).isEqualTo(4)
+ assertThat(eb.compositionStart).isEqualTo(4)
+ assertThat(eb.compositionEnd).isEqualTo(6)
+ }
+
+ @Test
+ fun test_delete_covered_composition() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.setComposition(4, 6)
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH5")
+ assertThat(eb.cursor).isEqualTo(4)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_delete_composition_covered() {
+ val eb = EditingBuffer("$CH1$CH2$CH3$CH4$CH5", TextRange(6))
+
+ eb.setComposition(0, 10)
+
+ eb.update(DeleteSurroundingTextInCodePointsCommand(1, 1))
+
+ assertThat(eb.toString()).isEqualTo("$CH1$CH2$CH5")
+ assertThat(eb.cursor).isEqualTo(4)
+ assertThat(eb.compositionStart).isEqualTo(0)
+ assertThat(eb.compositionEnd).isEqualTo(6)
+ }
+
+ @Test
+ fun throws_whenLengthBeforeInvalid() {
+ val error = assertFailsWith<IllegalArgumentException> {
+ DeleteSurroundingTextInCodePointsCommand(
+ lengthBeforeCursor = -42,
+ lengthAfterCursor = 0
+ )
+ }
+ assertThat(error).hasMessageThat().contains("-42")
+ }
+
+ @Test
+ fun throws_whenLengthAfterInvalid() {
+ val error = assertFailsWith<IllegalArgumentException> {
+ DeleteSurroundingTextInCodePointsCommand(
+ lengthBeforeCursor = 0,
+ lengthAfterCursor = -42
+ )
+ }
+ assertThat(error).hasMessageThat().contains("-42")
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessorTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessorTest.kt
new file mode 100644
index 0000000..837a3a3
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessorTest.kt
@@ -0,0 +1,378 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalFoundationApi::class)
+@RunWith(JUnit4::class)
+class EditProcessorTest {
+
+ @Test
+ fun initializeValue() {
+ val firstValue = TextFieldCharSequence("ABCDE", TextRange.Zero)
+ val processor = EditProcessor(firstValue)
+
+ assertThat(processor.value).isEqualTo(firstValue)
+ }
+
+ @Test
+ fun apply_commitTextCommand_changesValue() {
+ val firstValue = TextFieldCharSequence("ABCDE", TextRange.Zero)
+ val processor = EditProcessor(firstValue)
+
+ var resetCalled = 0
+ processor.addResetListener { _, _ -> resetCalled++ }
+
+ processor.update(CommitTextCommand("X", 1))
+ val newState = processor.value
+
+ assertThat(newState.toString()).isEqualTo("XABCDE")
+ assertThat(newState.selectionInChars.min).isEqualTo(1)
+ assertThat(newState.selectionInChars.max).isEqualTo(1)
+ // edit command updates should not trigger reset listeners.
+ assertThat(resetCalled).isEqualTo(0)
+ }
+
+ @Test
+ fun apply_setSelectionCommand_changesValue() {
+ val firstValue = TextFieldCharSequence("ABCDE", TextRange.Zero)
+ val processor = EditProcessor(firstValue)
+
+ var resetCalled = 0
+ processor.addResetListener { _, _ -> resetCalled++ }
+
+ processor.update(SetSelectionCommand(0, 2))
+ val newState = processor.value
+
+ assertThat(newState.toString()).isEqualTo("ABCDE")
+ assertThat(newState.selectionInChars.min).isEqualTo(0)
+ assertThat(newState.selectionInChars.max).isEqualTo(2)
+ // edit command updates should not trigger reset listeners.
+ assertThat(resetCalled).isEqualTo(0)
+ }
+
+ @Test
+ fun testNewState_bufferNotUpdated_ifSameModelStructurally() {
+ val processor = EditProcessor()
+ var resetCalled = 0
+ processor.addResetListener { _, _ -> resetCalled++ }
+
+ val initialBuffer = processor.mBuffer
+ processor.reset(TextFieldCharSequence("qwerty", TextRange.Zero, TextRange.Zero))
+ assertThat(processor.mBuffer).isNotSameInstanceAs(initialBuffer)
+
+ val updatedBuffer = processor.mBuffer
+ processor.reset(TextFieldCharSequence("qwerty", TextRange.Zero, TextRange.Zero))
+ assertThat(processor.mBuffer).isSameInstanceAs(updatedBuffer)
+
+ assertThat(resetCalled).isEqualTo(2)
+ }
+
+ @Test
+ fun testNewState_new_buffer_created_if_text_is_different() {
+ val processor = EditProcessor()
+ var resetCalled = 0
+ processor.addResetListener { _, _ -> resetCalled++ }
+
+ val textFieldValue = TextFieldCharSequence("qwerty", TextRange.Zero, TextRange.Zero)
+ processor.reset(textFieldValue)
+ val initialBuffer = processor.mBuffer
+
+ val newTextFieldValue = TextFieldCharSequence("abc")
+ processor.reset(newTextFieldValue)
+
+ assertThat(processor.mBuffer).isNotSameInstanceAs(initialBuffer)
+ assertThat(resetCalled).isEqualTo(2)
+ }
+
+ @Test
+ fun testNewState_buffer_not_recreated_if_selection_is_different() {
+ val processor = EditProcessor()
+ var resetCalled = 0
+ processor.addResetListener { _, _ -> resetCalled++ }
+
+ val textFieldValue = TextFieldCharSequence("qwerty", TextRange.Zero, TextRange.Zero)
+ processor.reset(textFieldValue)
+ val initialBuffer = processor.mBuffer
+
+ val newTextFieldValue = TextFieldCharSequence(textFieldValue, selection = TextRange(1))
+ processor.reset(newTextFieldValue)
+
+ assertThat(processor.mBuffer).isSameInstanceAs(initialBuffer)
+ assertThat(newTextFieldValue.selectionInChars.start)
+ .isEqualTo(processor.mBuffer.selectionStart)
+ assertThat(newTextFieldValue.selectionInChars.end).isEqualTo(processor.mBuffer.selectionEnd)
+ assertThat(resetCalled).isEqualTo(2)
+ }
+
+ @Test
+ fun testNewState_buffer_not_recreated_if_composition_is_different() {
+ val processor = EditProcessor()
+ var resetCalled = 0
+ processor.addResetListener { _, _ -> resetCalled++ }
+
+ val textFieldValue = TextFieldCharSequence("qwerty", TextRange.Zero, TextRange(1))
+ processor.reset(textFieldValue)
+ val initialBuffer = processor.mBuffer
+
+ // composition can not be set from app, IME owns it.
+ assertThat(EditingBuffer.NOWHERE).isEqualTo(initialBuffer.compositionStart)
+ assertThat(EditingBuffer.NOWHERE).isEqualTo(initialBuffer.compositionEnd)
+
+ val newTextFieldValue = TextFieldCharSequence(
+ textFieldValue,
+ textFieldValue.selectionInChars,
+ composition = null
+ )
+ processor.reset(newTextFieldValue)
+
+ assertThat(processor.mBuffer).isSameInstanceAs(initialBuffer)
+ assertThat(EditingBuffer.NOWHERE).isEqualTo(processor.mBuffer.compositionStart)
+ assertThat(EditingBuffer.NOWHERE).isEqualTo(processor.mBuffer.compositionEnd)
+ assertThat(resetCalled).isEqualTo(2)
+ }
+
+ @Test
+ fun testNewState_reversedSelection_setsTheSelection() {
+ val initialSelection = TextRange(2, 1)
+ val textFieldValue = TextFieldCharSequence("qwerty", initialSelection, TextRange(1))
+ val processor = EditProcessor(textFieldValue)
+ var resetCalled = 0
+ processor.addResetListener { _, _ -> resetCalled++ }
+
+ val initialBuffer = processor.mBuffer
+
+ assertThat(initialSelection.min).isEqualTo(initialBuffer.selectionStart)
+ assertThat(initialSelection.max).isEqualTo(initialBuffer.selectionEnd)
+
+ val updatedSelection = TextRange(3, 0)
+ val newTextFieldValue = TextFieldCharSequence(textFieldValue, selection = updatedSelection)
+ // set the new selection
+ processor.reset(newTextFieldValue)
+
+ assertThat(processor.mBuffer).isSameInstanceAs(initialBuffer)
+ assertThat(updatedSelection.min).isEqualTo(initialBuffer.selectionStart)
+ assertThat(updatedSelection.max).isEqualTo(initialBuffer.selectionEnd)
+ assertThat(resetCalled).isEqualTo(1)
+ }
+
+ @Test
+ fun compositionIsCleared_when_textChanged() {
+ val processor = EditProcessor()
+ var resetCalled = 0
+ processor.addResetListener { _, _ -> resetCalled++ }
+
+ // set the initial value
+ processor.update(
+ CommitTextCommand("ab", 0),
+ SetComposingRegionCommand(0, 2)
+ )
+
+ // change the text
+ val newValue =
+ TextFieldCharSequence(
+ "cd",
+ processor.value.selectionInChars,
+ processor.value.compositionInChars
+ )
+ processor.reset(newValue)
+
+ assertThat(processor.value.toString()).isEqualTo(newValue.toString())
+ assertThat(processor.value.compositionInChars).isNull()
+ }
+
+ @Test
+ fun compositionIsNotCleared_when_textIsSame() {
+ val processor = EditProcessor()
+ val composition = TextRange(0, 2)
+
+ // set the initial value
+ processor.update(
+ CommitTextCommand("ab", 0),
+ SetComposingRegionCommand(composition.start, composition.end)
+ )
+
+ // use the same TextFieldValue
+ val newValue =
+ TextFieldCharSequence(
+ processor.value,
+ processor.value.selectionInChars,
+ processor.value.compositionInChars
+ )
+ processor.reset(newValue)
+
+ assertThat(processor.value.toString()).isEqualTo(newValue.toString())
+ assertThat(processor.value.compositionInChars).isEqualTo(composition)
+ }
+
+ @Test
+ fun compositionIsCleared_when_compositionReset() {
+ val processor = EditProcessor()
+
+ // set the initial value
+ processor.update(
+ CommitTextCommand("ab", 0),
+ SetComposingRegionCommand(-1, -1)
+ )
+
+ // change the composition
+ val newValue =
+ TextFieldCharSequence(
+ processor.value,
+ processor.value.selectionInChars,
+ composition = TextRange(0, 2)
+ )
+ processor.reset(newValue)
+
+ assertThat(processor.value.toString()).isEqualTo(newValue.toString())
+ assertThat(processor.value.compositionInChars).isNull()
+ }
+
+ @Test
+ fun compositionIsCleared_when_compositionChanged() {
+ val processor = EditProcessor()
+
+ // set the initial value
+ processor.update(
+ CommitTextCommand("ab", 0),
+ SetComposingRegionCommand(0, 2)
+ )
+
+ // change the composition
+ val newValue = TextFieldCharSequence(
+ processor.value,
+ processor.value.selectionInChars,
+ composition = TextRange(0, 1)
+ )
+ processor.reset(newValue)
+
+ assertThat(processor.value.toString()).isEqualTo(newValue.toString())
+ assertThat(processor.value.compositionInChars).isNull()
+ }
+
+ @Test
+ fun compositionIsNotCleared_when_onlySelectionChanged() {
+ val processor = EditProcessor()
+
+ val composition = TextRange(0, 2)
+ val selection = TextRange(0, 2)
+
+ // set the initial value
+ processor.update(
+ CommitTextCommand("ab", 0),
+ SetComposingRegionCommand(composition.start, composition.end),
+ SetSelectionCommand(selection.start, selection.end)
+ )
+
+ // change selection
+ val newSelection = TextRange(1)
+ val newValue = TextFieldCharSequence(
+ processor.value,
+ selection = newSelection,
+ composition = processor.value.compositionInChars
+ )
+ processor.reset(newValue)
+
+ assertThat(processor.value.toString()).isEqualTo(newValue.toString())
+ assertThat(processor.value.compositionInChars).isEqualTo(composition)
+ assertThat(processor.value.selectionInChars).isEqualTo(newSelection)
+ }
+
+ @Test
+ fun filterThatDoesNothing_doesNotResetBuffer() {
+ val processor = EditProcessor(
+ TextFieldCharSequence(
+ "abc",
+ selection = TextRange(3),
+ composition = TextRange(0, 3)
+ )
+ )
+
+ val initialBuffer = processor.mBuffer
+
+ processor.update(CommitTextCommand("d", 4)) { _, _ -> }
+
+ val value = processor.value
+
+ assertThat(value.toString()).isEqualTo("abcd")
+ assertThat(processor.mBuffer).isSameInstanceAs(initialBuffer)
+ }
+
+ @Test
+ fun returningTheEquivalentValueFromFilter_doesNotResetBuffer() {
+ val processor = EditProcessor(
+ TextFieldCharSequence(
+ "abc",
+ selection = TextRange(3),
+ composition = TextRange(0, 3)
+ )
+ )
+
+ val initialBuffer = processor.mBuffer
+
+ processor.update(CommitTextCommand("d", 4)) { _, _ -> /* Noop */ }
+
+ val value = processor.value
+
+ assertThat(value.toString()).isEqualTo("abcd")
+ assertThat(processor.mBuffer).isSameInstanceAs(initialBuffer)
+ }
+
+ @Test
+ fun returningOldValueFromFilter_resetsTheBuffer() {
+ val processor = EditProcessor(
+ TextFieldCharSequence(
+ "abc",
+ selection = TextRange(3),
+ composition = TextRange(0, 3)
+ )
+ )
+
+ var resetCalledOld: TextFieldCharSequence? = null
+ var resetCalledNew: TextFieldCharSequence? = null
+ processor.addResetListener { old, new ->
+ resetCalledOld = old
+ resetCalledNew = new
+ }
+
+ val initialBuffer = processor.mBuffer
+
+ processor.update(CommitTextCommand("d", 4)) { _, new -> new.revertAllChanges() }
+
+ val value = processor.value
+
+ assertThat(value.toString()).isEqualTo("abc")
+ assertThat(processor.mBuffer).isNotSameInstanceAs(initialBuffer)
+ assertThat(resetCalledOld?.toString()).isEqualTo("abcd") // what IME applied
+ assertThat(resetCalledNew?.toString()).isEqualTo("abc") // what is decided by filter
+ }
+
+ private fun EditProcessor.update(
+ vararg editCommand: EditCommand,
+ filter: TextEditFilter? = null
+ ) {
+ update(editCommand.toList(), filter)
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditingBufferDeleteRangeTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditingBufferDeleteRangeTest.kt
new file mode 100644
index 0000000..5dd95b8
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditingBufferDeleteRangeTest.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class EditingBufferDeleteRangeTest {
+
+ @Test
+ fun test_does_not_intersect_deleted_is_after_the_target() {
+ val target = TextRange(0, 1)
+ val deleted = TextRange(2, 3)
+ assertThat(updateRangeAfterDelete(target, deleted))
+ .isEqualTo(TextRange(target.start, target.end))
+ }
+
+ @Test
+ fun test_does_not_intersect_deleted_is_before_the_target() {
+ val target = TextRange(4, 5)
+ val deleted = TextRange(0, 2)
+ assertThat(updateRangeAfterDelete(target, deleted)).isEqualTo(TextRange(2, 3))
+ }
+
+ @Test
+ fun test_deleted_covers_target() {
+ val target = TextRange(1, 2)
+ val deleted = TextRange(0, 3)
+ assertThat(updateRangeAfterDelete(target, deleted)).isEqualTo(TextRange(0, 0))
+ }
+
+ @Test
+ fun test_target_covers_deleted() {
+ val target = TextRange(0, 3)
+ val deleted = TextRange(1, 2)
+ assertThat(updateRangeAfterDelete(target, deleted)).isEqualTo(TextRange(0, 2))
+ }
+
+ @Test
+ fun test_deleted_same_as_target() {
+ val target = TextRange(1, 2)
+ val deleted = TextRange(1, 2)
+ assertThat(updateRangeAfterDelete(target, deleted)).isEqualTo(TextRange(1, 1))
+ }
+
+ @Test
+ fun test_deleted_covers_first_half_of_target() {
+ val target = TextRange(1, 4)
+ val deleted = TextRange(0, 2)
+ assertThat(updateRangeAfterDelete(target, deleted)).isEqualTo(TextRange(0, 2))
+ }
+
+ @Test
+ fun test_deleted_covers_second_half_of_target() {
+ val target = TextRange(1, 4)
+ val deleted = TextRange(3, 5)
+ assertThat(updateRangeAfterDelete(target, deleted)).isEqualTo(TextRange(1, 3))
+ }
+
+ @Test
+ fun test_delete_trailing_cursor() {
+ val target = TextRange(3, 3)
+ val deleted = TextRange(1, 2)
+ assertThat(updateRangeAfterDelete(target, deleted)).isEqualTo(TextRange(2, 2))
+ }
+}
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditingBufferTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditingBufferTest.kt
new file mode 100644
index 0000000..90d5cb5
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditingBufferTest.kt
@@ -0,0 +1,436 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.foundation.text2.input.internal.matchers.assertThat
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class EditingBufferTest {
+
+ @Test
+ fun insert() {
+ val eb = EditingBuffer("", TextRange.Zero)
+
+ eb.replace(0, 0, "A")
+
+ assertThat(eb).hasChars("A")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+
+ // Keep inserting text to the end of string. Cursor should follow.
+ eb.replace(1, 1, "BC")
+ assertThat(eb).hasChars("ABC")
+ assertThat(eb.cursor).isEqualTo(3)
+ assertThat(eb.selectionStart).isEqualTo(3)
+ assertThat(eb.selectionEnd).isEqualTo(3)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+
+ // Insert into middle position. Cursor should be end of inserted text.
+ eb.replace(1, 1, "D")
+ assertThat(eb).hasChars("ADBC")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.selectionStart).isEqualTo(2)
+ assertThat(eb.selectionEnd).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+ }
+
+ @Test
+ fun delete() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.replace(0, 1, "")
+
+ // Delete the left character at the cursor.
+ assertThat(eb).hasChars("BCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.selectionStart).isEqualTo(0)
+ assertThat(eb.selectionEnd).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+
+ // Delete the text before the cursor
+ eb.replace(0, 2, "")
+ assertThat(eb).hasChars("DE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.selectionStart).isEqualTo(0)
+ assertThat(eb.selectionEnd).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+
+ // Delete end of the text.
+ eb.replace(1, 2, "")
+ assertThat(eb).hasChars("D")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+ }
+
+ @Test
+ fun setSelection() {
+ val eb = EditingBuffer("ABCDE", TextRange(0, 3))
+ assertThat(eb).hasChars("ABCDE")
+ assertThat(eb.cursor).isEqualTo(-1)
+ assertThat(eb.selectionStart).isEqualTo(0)
+ assertThat(eb.selectionEnd).isEqualTo(3)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+
+ eb.setSelection(0, 5) // Change the selection
+ assertThat(eb).hasChars("ABCDE")
+ assertThat(eb.cursor).isEqualTo(-1)
+ assertThat(eb.selectionStart).isEqualTo(0)
+ assertThat(eb.selectionEnd).isEqualTo(5)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+
+ eb.replace(0, 3, "X") // replace function cancel the selection and place cursor.
+ assertThat(eb).hasChars("XDE")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+
+ eb.setSelection(0, 2) // Set the selection again
+ assertThat(eb).hasChars("XDE")
+ assertThat(eb.cursor).isEqualTo(-1)
+ assertThat(eb.selectionStart).isEqualTo(0)
+ assertThat(eb.selectionEnd).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+ }
+
+ @Test fun setSelection_throws_whenNegativeStart() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ assertFailsWith<IndexOutOfBoundsException> {
+ eb.setSelection(-1, 0)
+ }
+ }
+
+ @Test fun setSelection_throws_whenNegativeEnd() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ assertFailsWith<IndexOutOfBoundsException> {
+ eb.setSelection(0, -1)
+ }
+ }
+
+ @Test
+ fun setCompostion_and_cancelComposition() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(0, 5) // Make all text as composition
+ assertThat(eb).hasChars("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.selectionStart).isEqualTo(0)
+ assertThat(eb.selectionEnd).isEqualTo(0)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(0)
+ assertThat(eb.compositionEnd).isEqualTo(5)
+
+ eb.replace(2, 3, "X") // replace function cancel the composition text.
+ assertThat(eb).hasChars("ABXDE")
+ assertThat(eb.cursor).isEqualTo(3)
+ assertThat(eb.selectionStart).isEqualTo(3)
+ assertThat(eb.selectionEnd).isEqualTo(3)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+
+ eb.setComposition(2, 4) // set composition again
+ assertThat(eb).hasChars("ABXDE")
+ assertThat(eb.cursor).isEqualTo(3)
+ assertThat(eb.selectionStart).isEqualTo(3)
+ assertThat(eb.selectionEnd).isEqualTo(3)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(2)
+ assertThat(eb.compositionEnd).isEqualTo(4)
+
+ eb.cancelComposition() // cancel the composition
+ assertThat(eb).hasChars("ABE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.selectionStart).isEqualTo(2)
+ assertThat(eb.selectionEnd).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+ }
+
+ @Test
+ fun setCompostion_and_commitComposition() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(0, 5) // Make all text as composition
+ assertThat(eb).hasChars("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.selectionStart).isEqualTo(0)
+ assertThat(eb.selectionEnd).isEqualTo(0)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(0)
+ assertThat(eb.compositionEnd).isEqualTo(5)
+
+ eb.replace(2, 3, "X") // replace function cancel the composition text.
+ assertThat(eb).hasChars("ABXDE")
+ assertThat(eb.cursor).isEqualTo(3)
+ assertThat(eb.selectionStart).isEqualTo(3)
+ assertThat(eb.selectionEnd).isEqualTo(3)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+
+ eb.setComposition(2, 4) // set composition again
+ assertThat(eb).hasChars("ABXDE")
+ assertThat(eb.cursor).isEqualTo(3)
+ assertThat(eb.selectionStart).isEqualTo(3)
+ assertThat(eb.selectionEnd).isEqualTo(3)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(2)
+ assertThat(eb.compositionEnd).isEqualTo(4)
+
+ eb.commitComposition() // commit the composition
+ assertThat(eb).hasChars("ABXDE")
+ assertThat(eb.cursor).isEqualTo(3)
+ assertThat(eb.selectionStart).isEqualTo(3)
+ assertThat(eb.selectionEnd).isEqualTo(3)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+ }
+
+ @Test
+ fun setCursor_and_get_cursor() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.cursor = 1
+ assertThat(eb).hasChars("ABCDE")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+
+ eb.cursor = 2
+ assertThat(eb).hasChars("ABCDE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.selectionStart).isEqualTo(2)
+ assertThat(eb.selectionEnd).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+
+ eb.cursor = 5
+ assertThat(eb).hasChars("ABCDE")
+ assertThat(eb.cursor).isEqualTo(5)
+ assertThat(eb.selectionStart).isEqualTo(5)
+ assertThat(eb.selectionEnd).isEqualTo(5)
+ assertThat(eb.hasComposition()).isFalse()
+ assertThat(eb.compositionStart).isEqualTo(-1)
+ assertThat(eb.compositionEnd).isEqualTo(-1)
+ }
+
+ @Test
+ fun delete_preceding_cursor_no_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.delete(1, 2)
+ assertThat(eb).hasChars("ACDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun delete_trailing_cursor_no_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange(3))
+
+ eb.delete(1, 2)
+ assertThat(eb).hasChars("ACDE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun delete_preceding_selection_no_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange(0, 1))
+
+ eb.delete(1, 2)
+ assertThat(eb).hasChars("ACDE")
+ assertThat(eb.selectionStart).isEqualTo(0)
+ assertThat(eb.selectionEnd).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun delete_trailing_selection_no_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange(4, 5))
+
+ eb.delete(1, 2)
+ assertThat(eb).hasChars("ACDE")
+ assertThat(eb.selectionStart).isEqualTo(3)
+ assertThat(eb.selectionEnd).isEqualTo(4)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun delete_covered_cursor() {
+ // AB[]CDE
+ val eb = EditingBuffer("ABCDE", TextRange(2, 2))
+
+ eb.delete(1, 3)
+ // A[]DE
+ assertThat(eb).hasChars("ADE")
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(1)
+ }
+
+ @Test
+ fun delete_covered_selection() {
+ // A[BC]DE
+ val eb = EditingBuffer("ABCDE", TextRange(1, 3))
+
+ eb.delete(0, 4)
+ // []E
+ assertThat(eb).hasChars("E")
+ assertThat(eb.selectionStart).isEqualTo(0)
+ assertThat(eb.selectionEnd).isEqualTo(0)
+ }
+
+ @Test
+ fun delete_intersects_first_half_of_selection() {
+ // AB[CD]E
+ val eb = EditingBuffer("ABCDE", TextRange(2, 4))
+
+ eb.delete(1, 3)
+ // A[D]E
+ assertThat(eb).hasChars("ADE")
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(2)
+ }
+
+ @Test
+ fun delete_intersects_second_half_of_selection() {
+ // A[BCD]EFG
+ val eb = EditingBuffer("ABCDEFG", TextRange(1, 4))
+
+ eb.delete(3, 5)
+ // A[BC]FG
+ assertThat(eb).hasChars("ABCFG")
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(3)
+ }
+
+ @Test
+ fun delete_preceding_composition_no_intersection() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(1, 2)
+ eb.delete(2, 3)
+
+ assertThat(eb).hasChars("ABDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.compositionStart).isEqualTo(1)
+ assertThat(eb.compositionEnd).isEqualTo(2)
+ }
+
+ @Test
+ fun delete_trailing_composition_no_intersection() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(3, 4)
+ eb.delete(2, 3)
+
+ assertThat(eb).hasChars("ABDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.compositionStart).isEqualTo(2)
+ assertThat(eb.compositionEnd).isEqualTo(3)
+ }
+
+ @Test
+ fun delete_preceding_composition_intersection() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(1, 3)
+ eb.delete(2, 4)
+
+ assertThat(eb).hasChars("ABE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.compositionStart).isEqualTo(1)
+ assertThat(eb.compositionEnd).isEqualTo(2)
+ }
+
+ @Test
+ fun delete_trailing_composition_intersection() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(3, 5)
+ eb.delete(2, 4)
+
+ assertThat(eb).hasChars("ABE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.compositionStart).isEqualTo(2)
+ assertThat(eb.compositionEnd).isEqualTo(3)
+ }
+
+ @Test
+ fun delete_composition_contains_delrange() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(2, 5)
+ eb.delete(3, 4)
+
+ assertThat(eb).hasChars("ABCE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.compositionStart).isEqualTo(2)
+ assertThat(eb.compositionEnd).isEqualTo(4)
+ }
+
+ @Test
+ fun delete_delrange_contains_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(3, 4)
+ eb.delete(2, 5)
+
+ assertThat(eb).hasChars("AB")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/FinishComposingTextCommandTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/FinishComposingTextCommandTest.kt
new file mode 100644
index 0000000..fa67d4c
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/FinishComposingTextCommandTest.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class FinishComposingTextCommandTest {
+
+ @Test
+ fun test_set() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(1, 4)
+ eb.update(FinishComposingTextCommand)
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_preserve_selection() {
+ val eb = EditingBuffer("ABCDE", TextRange(1, 4))
+
+ eb.setComposition(2, 5)
+ eb.update(FinishComposingTextCommand)
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(4)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/GapBufferTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/GapBufferTest.kt
new file mode 100644
index 0000000..b54e5ad
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/GapBufferTest.kt
@@ -0,0 +1,685 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.foundation.text.InternalFoundationTextApi
+import androidx.compose.foundation.text2.input.internal.matchers.assertThat
+import com.google.common.truth.Truth.assertThat
+import kotlin.random.Random
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(InternalFoundationTextApi::class)
+@RunWith(JUnit4::class)
+class GapBufferTest {
+
+ @Test
+ fun insertTest_insert_to_empty_string() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "A")
+ }
+ ).hasChars("A")
+ }
+
+ @Test
+ fun insertTest_insert_and_append() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "A")
+ replace(0, 0, "B")
+ }
+ ).hasChars("BA")
+ }
+
+ @Test
+ fun insertTest_insert_and_prepend() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "A")
+ replace(1, 1, "B")
+ }
+ ).hasChars("AB")
+ }
+
+ @Test
+ fun insertTest_insert_and_insert_into_middle() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "AA")
+ replace(1, 1, "B")
+ }
+ ).hasChars("ABA")
+ }
+
+ @Test
+ fun insertTest_intoExistingText_prepend() {
+ assertThat(
+ PartialGapBuffer("XX").apply {
+ replace(0, 0, "A")
+ }
+ ).hasChars("AXX")
+ }
+
+ @Test
+ fun insertTest_intoExistingText_insert_into_middle() {
+ assertThat(
+ PartialGapBuffer("XX").apply {
+ replace(1, 1, "A")
+ }
+ ).hasChars("XAX")
+ }
+
+ @Test
+ fun insertTest_intoExistingText_append() {
+ assertThat(
+ PartialGapBuffer("XX").apply {
+ replace(2, 2, "A")
+ }
+ ).hasChars("XXA")
+ }
+
+ @Test
+ fun insertTest_intoExistingText_prepend_and_prepend() {
+ assertThat(
+ PartialGapBuffer("XX").apply {
+ replace(0, 0, "A")
+ replace(0, 0, "B")
+ }
+ ).hasChars("BAXX")
+ }
+
+ @Test
+ fun insertTest_intoExistingText_prepend_and_append() {
+ assertThat(
+ PartialGapBuffer("XX").apply {
+ replace(0, 0, "A")
+ replace(1, 1, "B")
+ }
+ ).hasChars("ABXX")
+ }
+
+ @Test
+ fun insertTest_intoExistingText_prepend_and_insert_middle() {
+ assertThat(
+ PartialGapBuffer("XX").apply {
+ replace(0, 0, "A")
+ replace(2, 2, "B")
+ }
+ ).hasChars("AXBX")
+ }
+
+ @Test
+ fun insertTest_intoExistingText_insert_two_chars_and_append() {
+ assertThat(
+ PartialGapBuffer("XX").apply {
+ replace(0, 0, "AA")
+ replace(1, 1, "B")
+ }
+ ).hasChars("ABAXX")
+ }
+
+ @Test
+ fun deleteTest_insert_and_delete_from_head() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 1, "")
+ }
+ ).hasChars("BC")
+ }
+
+ @Test
+ fun deleteTest_insert_and_delete_middle() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(1, 2, "")
+ }
+ ).hasChars("AC")
+ }
+
+ @Test
+ fun deleteTest_insert_and_delete_tail() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(2, 3, "")
+ }
+ ).hasChars("AB")
+ }
+
+ @Test
+ fun deleteTest_insert_and_delete_two_head() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 2, "")
+ }
+ ).hasChars("C")
+ }
+
+ @Test
+ fun deleteTest_insert_and_delete_two_tail() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(1, 3, "")
+ }
+ ).hasChars("A")
+ }
+
+ @Test
+ fun deleteTest_insert_and_delete_with_two_instruction_from_haed() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 1, "")
+ replace(0, 1, "")
+ }
+ ).hasChars("C")
+ }
+
+ @Test
+ fun deleteTest_insert_and_delet_with_two_instruction_from_head_and_tail() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 1, "")
+ replace(1, 2, "")
+ }
+ ).hasChars("B")
+ }
+
+ @Test
+ fun deleteTest_insert_and_delet_with_two_instruction_from_tail() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(1, 2, "")
+ replace(1, 2, "")
+ }
+ ).hasChars("A")
+ }
+
+ @Test
+ fun deleteTest_insert_and_delete_three_chars() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 3, "")
+ }
+ ).hasChars("")
+ }
+
+ @Test
+ fun deleteTest_insert_and_delete_three_chars_with_three_instructions() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 1, "")
+ replace(0, 1, "")
+ replace(0, 1, "")
+ }
+ ).hasChars("")
+ }
+
+ @Test
+ fun deleteTest_fromExistingText_from_head() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 1, "")
+ }
+ ).hasChars("BC")
+ }
+
+ @Test
+ fun deleteTest_fromExistingText_from_middle() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(1, 2, "")
+ }
+ ).hasChars("AC")
+ }
+
+ @Test
+ fun deleteTest_fromExistingText_from_tail() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(2, 3, "")
+ }
+ ).hasChars("AB")
+ }
+
+ @Test
+ fun deleteTest_fromExistingText_delete_two_chars_from_head() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 2, "")
+ }
+ ).hasChars("C")
+ }
+
+ @Test
+ fun deleteTest_fromExistingText_delete_two_chars_from_tail() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(1, 3, "")
+ }
+ ).hasChars("A")
+ }
+
+ @Test
+ fun deleteTest_fromExistingText_delete_two_chars_with_two_instruction_from_head() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 1, "")
+ replace(0, 1, "")
+ }
+ ).hasChars("C")
+ }
+
+ @Test
+ fun deleteTest_fromExistingText_delete_two_chars_with_two_instruction_from_head_and_tail() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 1, "")
+ replace(1, 2, "")
+ }
+ ).hasChars("B")
+ }
+
+ @Test
+ fun deleteTest_fromExistingText_delete_two_chars_with_two_instruction_from_tail() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(1, 2, "")
+ replace(1, 2, "")
+ }
+ ).hasChars("A")
+ }
+
+ @Test
+ fun deleteTest_fromExistingText_delete_three_chars() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 3, "")
+ }
+ ).hasChars("")
+ }
+
+ @Test
+ fun deleteTest_fromExistingText_delete_three_chars_with_three_instructions() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 1, "")
+ replace(0, 1, "")
+ replace(0, 1, "")
+ }
+ ).hasChars("")
+ }
+
+ @Test
+ fun replaceTest_head() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 1, "X")
+ }
+ ).hasChars("XBC")
+ }
+
+ @Test
+ fun replaceTest_middle() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(1, 2, "X")
+ }
+ ).hasChars("AXC")
+ }
+
+ @Test
+ fun replaceTest_tail() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(2, 3, "X")
+ }
+ ).hasChars("ABX")
+ }
+
+ @Test
+ fun replaceTest_head_two_chars() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 2, "X")
+ }
+ ).hasChars("XC")
+ }
+
+ @Test
+ fun replaceTest_middle_two_chars() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(1, 3, "X")
+ }
+ ).hasChars("AX")
+ }
+
+ @Test
+ fun replaceTest_three_chars() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 3, "X")
+ }
+ ).hasChars("X")
+ }
+
+ @Test
+ fun replaceTest_one_char_with_two_chars_from_head() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 1, "XY")
+ }
+ ).hasChars("XYBC")
+ }
+
+ @Test
+ fun replaceTest_one_char_with_two_chars_from_middle() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(1, 2, "XY")
+ }
+ ).hasChars("AXYC")
+ }
+
+ @Test
+ fun replaceTest_one_char_with_two_chars_from_tail() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(2, 3, "XY")
+ }
+ ).hasChars("ABXY")
+ }
+
+ @Test
+ fun replaceTest_two_chars_with_two_chars_from_head() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 2, "XY")
+ }
+ ).hasChars("XYC")
+ }
+
+ @Test
+ fun replaceTest_two_chars_with_two_chars_from_tail() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(1, 3, "XY")
+ }
+ ).hasChars("AXY")
+ }
+
+ @Test
+ fun replaceTest_three_chars_with_two_char() {
+ assertThat(
+ PartialGapBuffer("").apply {
+ replace(0, 0, "ABC")
+ replace(0, 3, "XY")
+ }
+ ).hasChars("XY")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_head() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 1, "X")
+ }
+ ).hasChars("XBC")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_middle() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(1, 2, "X")
+ }
+ ).hasChars("AXC")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_tail() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(2, 3, "X")
+ }
+ ).hasChars("ABX")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_two_chars_with_one_char_from_head() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 2, "X")
+ }
+ ).hasChars("XC")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_two_chars_with_one_char_from_tail() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(1, 3, "X")
+ }
+ ).hasChars("AX")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_three_chars() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 3, "X")
+ }
+ ).hasChars("X")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_one_char_with_two_chars_from_head() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 1, "XY")
+ }
+ ).hasChars("XYBC")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_one_char_with_two_chars_from_middle() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(1, 2, "XY")
+ }
+ ).hasChars("AXYC")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_one_char_with_two_chars_from_tail() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(2, 3, "XY")
+ }
+ ).hasChars("ABXY")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_two_chars_with_two_chars_from_head() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 2, "XY")
+ }
+ ).hasChars("XYC")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_two_chars_with_two_chars_from_tail() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(1, 3, "XY")
+ }
+ ).hasChars("AXY")
+ }
+
+ @Test
+ fun replaceTest_fromExistingText_three_chars_with_three_chars() {
+ assertThat(
+ PartialGapBuffer("ABC").apply {
+ replace(0, 3, "XY")
+ }
+ ).hasChars("XY")
+ }
+
+ @Test
+ fun replace_throws_whenStartGreaterThanEnd() {
+ val buffer = PartialGapBuffer("ABCD")
+
+ val error = assertFailsWith<IllegalArgumentException> {
+ buffer.replace(3, 2, "")
+ }
+ assertThat(error).hasMessageThat().contains("3 > 2")
+ }
+
+ @Test
+ fun replace_throws_whenStartNegative() {
+ val buffer = PartialGapBuffer("ABCD")
+
+ val error = assertFailsWith<IllegalArgumentException> {
+ buffer.replace(-1, 2, "XY")
+ }
+ assertThat(error).hasMessageThat().contains("-1")
+ }
+
+ // Compare with the result of StringBuffer. We trust the StringBuffer works correctly
+ private fun assertReplace(
+ start: Int,
+ end: Int,
+ str: String,
+ sb: StringBuffer,
+ gb: PartialGapBuffer
+ ) {
+ sb.replace(start, end, str)
+ gb.replace(start, end, str)
+ assertThat(gb).hasChars(sb.toString())
+ }
+
+ private val LONG_INIT_TEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".repeat(256)
+ private val SHORT_TEXT = "A"
+ private val MEDIUM_TEXT = "Hello, World"
+ private val LONG_TEXT = "abcdefghijklmnopqrstuvwxyz".repeat(16)
+
+ @Test
+ fun longTextTest_keep_insertion() {
+ val sb = StringBuffer(LONG_INIT_TEXT)
+ val gb = PartialGapBuffer(LONG_INIT_TEXT)
+
+ var c = 256 // cursor
+ assertReplace(c, c, SHORT_TEXT, sb, gb)
+ c += SHORT_TEXT.length
+ assertReplace(c, c, MEDIUM_TEXT, sb, gb)
+ c += MEDIUM_TEXT.length
+ assertReplace(c, c, LONG_TEXT, sb, gb)
+ c += LONG_TEXT.length
+ assertReplace(c, c, MEDIUM_TEXT, sb, gb)
+ c += MEDIUM_TEXT.length
+ assertReplace(c, c, SHORT_TEXT, sb, gb)
+ }
+
+ @Test
+ fun longTextTest_keep_deletion() {
+ val sb = StringBuffer(LONG_INIT_TEXT)
+ val gb = PartialGapBuffer(LONG_INIT_TEXT)
+
+ var c = 2048 // cursor
+ // Forward deletion
+ assertReplace(c, c + 10, "", sb, gb)
+ assertReplace(c, c + 100, "", sb, gb)
+ assertReplace(c, c + 1000, "", sb, gb)
+
+ // Backspacing
+ assertReplace(c - 10, c, "", sb, gb)
+ c -= 10
+ assertReplace(c - 100, c, "", sb, gb)
+ c -= 100
+ assertReplace(c - 1000, c, "", sb, gb)
+ }
+
+ @Test
+ fun longTextTest_farInput() {
+ val sb = StringBuffer(LONG_INIT_TEXT)
+ val gb = PartialGapBuffer(LONG_INIT_TEXT)
+
+ assertReplace(1024, 1024, "Hello, World", sb, gb)
+ assertReplace(128, 128, LONG_TEXT, sb, gb)
+ }
+
+ @Test
+ fun randomInsertDeleteStressTest() {
+ val sb = StringBuffer(LONG_INIT_TEXT)
+ val gb = PartialGapBuffer(LONG_INIT_TEXT)
+
+ val r = Random(10 /* fix the seed for reproduction */)
+
+ val insertTexts = arrayOf(SHORT_TEXT, MEDIUM_TEXT, LONG_TEXT)
+ val delLengths = arrayOf(1, 10, 100)
+
+ var c = LONG_INIT_TEXT.length / 2
+
+ for (i in 0..100) {
+ when (r.nextInt() % 4) {
+ 0 -> { // insert
+ val txt = insertTexts.random(r)
+ assertReplace(c, c, txt, sb, gb)
+ c += txt.length
+ }
+ 1 -> { // forward delete
+ assertReplace(c, c + delLengths.random(r), "", sb, gb)
+ }
+ 2 -> { // backspacing
+ val len = delLengths.random(r)
+ assertReplace(c - len, c, "", sb, gb)
+ c -= len
+ }
+ 3 -> { // replacing
+ val txt = insertTexts.random(r)
+ val len = delLengths.random(r)
+
+ assertReplace(c, c + len, txt, sb, gb)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/SetComposingRegionCommandTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/SetComposingRegionCommandTest.kt
new file mode 100644
index 0000000..e78f64f
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/SetComposingRegionCommandTest.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class SetComposingRegionCommandTest {
+
+ @Test
+ fun test_set() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetComposingRegionCommand(1, 4))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(1)
+ assertThat(eb.compositionEnd).isEqualTo(4)
+ }
+
+ @Test
+ fun test_preserve_ongoing_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(1, 3)
+
+ eb.update(SetComposingRegionCommand(2, 4))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(2)
+ assertThat(eb.compositionEnd).isEqualTo(4)
+ }
+
+ @Test
+ fun test_preserve_selection() {
+ val eb = EditingBuffer("ABCDE", TextRange(1, 4))
+
+ eb.update(SetComposingRegionCommand(2, 4))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(4)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(2)
+ assertThat(eb.compositionEnd).isEqualTo(4)
+ }
+
+ @Test
+ fun test_set_reversed() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetComposingRegionCommand(4, 1))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(1)
+ assertThat(eb.compositionEnd).isEqualTo(4)
+ }
+
+ @Test
+ fun test_set_too_small() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetComposingRegionCommand(-1000, -1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_set_too_large() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetComposingRegionCommand(1000, 1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_set_too_small_and_too_large() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetComposingRegionCommand(-1000, 1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(0)
+ assertThat(eb.compositionEnd).isEqualTo(5)
+ }
+
+ @Test
+ fun test_set_too_small_and_too_large_reversed() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetComposingRegionCommand(1000, -1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(0)
+ assertThat(eb.compositionEnd).isEqualTo(5)
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/SetComposingTextCommandTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/SetComposingTextCommandTest.kt
new file mode 100644
index 0000000..98d388e
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/SetComposingTextCommandTest.kt
@@ -0,0 +1,205 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class SetComposingTextCommandTest {
+
+ @Test
+ fun test_insert_empty() {
+ val eb = EditingBuffer("", TextRange.Zero)
+
+ eb.update(SetComposingTextCommand("X", 1))
+
+ assertThat(eb.toString()).isEqualTo("X")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(0)
+ assertThat(eb.compositionEnd).isEqualTo(1)
+ }
+
+ @Test
+ fun test_insert_cursor_tail() {
+ val eb = EditingBuffer("A", TextRange(1))
+
+ eb.update(SetComposingTextCommand("X", 1))
+
+ assertThat(eb.toString()).isEqualTo("AX")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(1)
+ assertThat(eb.compositionEnd).isEqualTo(2)
+ }
+
+ @Test
+ fun test_insert_cursor_head() {
+ val eb = EditingBuffer("A", TextRange(1))
+
+ eb.update(SetComposingTextCommand("X", 0))
+
+ assertThat(eb.toString()).isEqualTo("AX")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(1)
+ assertThat(eb.compositionEnd).isEqualTo(2)
+ }
+
+ @Test
+ fun test_insert_cursor_far_tail() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+
+ eb.update(SetComposingTextCommand("X", 2))
+
+ assertThat(eb.toString()).isEqualTo("AXBCDE")
+ assertThat(eb.cursor).isEqualTo(3)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(1)
+ assertThat(eb.compositionEnd).isEqualTo(2)
+ }
+
+ @Test
+ fun test_insert_cursor_far_head() {
+ val eb = EditingBuffer("ABCDE", TextRange(4))
+
+ eb.update(SetComposingTextCommand("X", -2))
+
+ assertThat(eb.toString()).isEqualTo("ABCDXE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(4)
+ assertThat(eb.compositionEnd).isEqualTo(5)
+ }
+
+ @Test
+ fun test_insert_empty_text_cursor_head() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+
+ eb.update(SetComposingTextCommand("", 0))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_insert_empty_text_cursor_tail() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+
+ eb.update(SetComposingTextCommand("", 1))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(1)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_insert_empty_text_cursor_far_tail() {
+ val eb = EditingBuffer("ABCDE", TextRange(1))
+
+ eb.update(SetComposingTextCommand("", 2))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_insert_empty_text_cursor_far_head() {
+ val eb = EditingBuffer("ABCDE", TextRange(4))
+
+ eb.update(SetComposingTextCommand("", -2))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_cancel_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(1, 4) // Mark "BCD" as composition
+ eb.update(SetComposingTextCommand("X", 1))
+
+ assertThat(eb.toString()).isEqualTo("AXE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(1)
+ assertThat(eb.compositionEnd).isEqualTo(2)
+ }
+
+ @Test
+ fun test_replace_selection() {
+ val eb = EditingBuffer("ABCDE", TextRange(1, 4)) // select "BCD"
+
+ eb.update(SetComposingTextCommand("X", 1))
+
+ assertThat(eb.toString()).isEqualTo("AXE")
+ assertThat(eb.cursor).isEqualTo(2)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(1)
+ assertThat(eb.compositionEnd).isEqualTo(2)
+ }
+
+ @Test
+ fun test_composition_and_selection() {
+ val eb = EditingBuffer("ABCDE", TextRange(1, 3)) // select "BC"
+
+ eb.setComposition(2, 4) // Mark "CD" as composition
+ eb.update(SetComposingTextCommand("X", 1))
+
+ // If composition and selection exists at the same time, replace composition and cancel
+ // selection and place cursor.
+ assertThat(eb.toString()).isEqualTo("ABXE")
+ assertThat(eb.cursor).isEqualTo(3)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(2)
+ assertThat(eb.compositionEnd).isEqualTo(3)
+ }
+
+ @Test
+ fun test_cursor_position_too_small() {
+ val eb = EditingBuffer("ABCDE", TextRange(5))
+
+ eb.update(SetComposingTextCommand("X", -1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDEX")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(5)
+ assertThat(eb.compositionEnd).isEqualTo(6)
+ }
+
+ @Test
+ fun test_cursor_position_too_large() {
+ val eb = EditingBuffer("ABCDE", TextRange(5))
+
+ eb.update(SetComposingTextCommand("X", 1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDEX")
+ assertThat(eb.cursor).isEqualTo(6)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(5)
+ assertThat(eb.compositionEnd).isEqualTo(6)
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/SetSelectionCommandTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/SetSelectionCommandTest.kt
new file mode 100644
index 0000000..fb6877d
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/SetSelectionCommandTest.kt
@@ -0,0 +1,125 @@
+/*
+ * 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.input.internal
+
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class SetSelectionCommandTest {
+
+ @Test
+ fun test_set() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetSelectionCommand(1, 4))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(4)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_preserve_ongoing_composition() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.setComposition(1, 3)
+
+ eb.update(SetSelectionCommand(2, 4))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.selectionStart).isEqualTo(2)
+ assertThat(eb.selectionEnd).isEqualTo(4)
+ assertThat(eb.hasComposition()).isTrue()
+ assertThat(eb.compositionStart).isEqualTo(1)
+ assertThat(eb.compositionEnd).isEqualTo(3)
+ }
+
+ @Test
+ fun test_cancel_ongoing_selection() {
+ val eb = EditingBuffer("ABCDE", TextRange(1, 4))
+
+ eb.update(SetSelectionCommand(2, 5))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.selectionStart).isEqualTo(2)
+ assertThat(eb.selectionEnd).isEqualTo(5)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_set_reversed() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetSelectionCommand(4, 1))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.selectionStart).isEqualTo(1)
+ assertThat(eb.selectionEnd).isEqualTo(4)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_set_too_small() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetSelectionCommand(-1000, -1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(0)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_set_too_large() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetSelectionCommand(1000, 1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.cursor).isEqualTo(5)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_set_too_small_too_large() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetSelectionCommand(-1000, 1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.selectionStart).isEqualTo(0)
+ assertThat(eb.selectionEnd).isEqualTo(5)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+
+ @Test
+ fun test_set_too_small_too_large_reversed() {
+ val eb = EditingBuffer("ABCDE", TextRange.Zero)
+
+ eb.update(SetSelectionCommand(1000, -1000))
+
+ assertThat(eb.toString()).isEqualTo("ABCDE")
+ assertThat(eb.selectionStart).isEqualTo(0)
+ assertThat(eb.selectionEnd).isEqualTo(5)
+ assertThat(eb.hasComposition()).isFalse()
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/matchers/EditBufferSubject.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/matchers/EditBufferSubject.kt
new file mode 100644
index 0000000..1c751811
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/matchers/EditBufferSubject.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.
+ */
+
+@file:OptIn(InternalFoundationTextApi::class)
+
+package androidx.compose.foundation.text2.input.internal.matchers
+
+import androidx.compose.foundation.text.InternalFoundationTextApi
+import androidx.compose.foundation.text2.input.internal.EditingBuffer
+import androidx.compose.foundation.text2.input.internal.PartialGapBuffer
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.Subject
+import com.google.common.truth.Subject.Factory
+import com.google.common.truth.Truth.assertAbout
+import com.google.common.truth.Truth.assertThat
+
+@OptIn(InternalFoundationTextApi::class)
+internal fun assertThat(buffer: PartialGapBuffer): EditBufferSubject {
+ return assertAbout(EditBufferSubject.SUBJECT_FACTORY)
+ .that(GapBufferWrapper(buffer))!!
+}
+
+internal fun assertThat(buffer: EditingBuffer): EditBufferSubject {
+ return assertAbout(EditBufferSubject.SUBJECT_FACTORY)
+ .that(EditingBufferWrapper(buffer))!!
+}
+
+internal abstract class GetOperatorWrapper(val buffer: Any) {
+ abstract operator fun get(index: Int): Char
+ override fun toString(): String = buffer.toString()
+}
+
+private class EditingBufferWrapper(buffer: EditingBuffer) : GetOperatorWrapper(buffer) {
+ override fun get(index: Int): Char = (buffer as EditingBuffer)[index]
+}
+
+@OptIn(InternalFoundationTextApi::class)
+private class GapBufferWrapper(buffer: PartialGapBuffer) : GetOperatorWrapper(buffer) {
+ override fun get(index: Int): Char = (buffer as PartialGapBuffer)[index]
+}
+
+/**
+ * Truth extension for Editing Buffers.
+ */
+internal class EditBufferSubject private constructor(
+ failureMetadata: FailureMetadata?,
+ private val subject: GetOperatorWrapper
+) : Subject(failureMetadata, subject) {
+
+ companion object {
+ internal val SUBJECT_FACTORY: Factory<EditBufferSubject, GetOperatorWrapper> =
+ Factory { failureMetadata, subject -> EditBufferSubject(failureMetadata, subject) }
+ }
+
+ fun hasChars(expected: String) {
+ assertThat(subject.buffer.toString()).isEqualTo(expected)
+ for (i in expected.indices) {
+ assertThat(subject[i]).isEqualTo(expected[i])
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/Demos.kt b/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/Demos.kt
index a987eda..1b24f7e 100644
--- a/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/Demos.kt
+++ b/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/Demos.kt
@@ -18,6 +18,7 @@
import androidx.compose.animation.demos.AnimationDemos
import androidx.compose.foundation.demos.FoundationDemos
+import androidx.compose.foundation.demos.performance.PerformanceDemos
import androidx.compose.foundation.demos.text.TextDemos
import androidx.compose.foundation.layout.demos.LayoutDemos
import androidx.compose.integration.demos.common.DemoCategory
@@ -43,6 +44,7 @@
NavigationDemos,
PagingFoundationDemos,
TextDemos,
- AccessibilityDemos
+ AccessibilityDemos,
+ PerformanceDemos
)
)
\ No newline at end of file
diff --git a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
index 34632df..74aea66 100644
--- a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
+++ b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
@@ -29,7 +29,9 @@
override val issues get(): List<Issue> {
return listOf(
ListIteratorDetector.ISSUE,
+ SteppedForLoopDetector.ISSUE,
UnnecessaryLambdaCreationDetector.ISSUE,
+ PlatformImportInCommonModuleDetector.ISSUE,
)
}
override val vendor = Vendor(
diff --git a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/PlatformImportInCommonModuleDetector.kt b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/PlatformImportInCommonModuleDetector.kt
new file mode 100644
index 0000000..0e73ca6
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/PlatformImportInCommonModuleDetector.kt
@@ -0,0 +1,90 @@
+/*
+ * 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.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import org.jetbrains.uast.UImportStatement
+import org.jetbrains.uast.getContainingUFile
+import org.jetbrains.uast.getIoFile
+
+/**
+ * Lint [Detector] that catches platform-dependent imports in a common module.
+ */
+class PlatformImportInCommonModuleDetector : Detector(), SourceCodeScanner {
+
+ override fun getApplicableUastTypes() =
+ listOf(UImportStatement::class.java)
+
+ override fun createUastHandler(context: JavaContext): UElementHandler =
+ object : UElementHandler() {
+ // this only verifies imports and not fqname references
+ // potentially we want to make sure to search for those too
+
+ override fun visitImportStatement(node: UImportStatement) {
+ val reference = node.importReference?.asRenderString() ?: return
+ val isPlatformImport = PLATFORM_PACKAGES.any { platformPackage ->
+ (platformPackage == reference && node.isOnDemand) ||
+ reference.startsWith("$platformPackage.")
+ }
+ if (!isPlatformImport) return
+
+ val file = node.getContainingUFile()?.getIoFile() ?: return
+ val isInCommonModule = file.absolutePath.contains(COMMON_MAIN_PATH_PREFIX)
+ if (!isInCommonModule) return
+
+ val target = node.importReference!!
+ context.report(
+ ISSUE,
+ target,
+ context.getLocation(target),
+ "Platform-dependent import in a common module"
+ )
+ }
+ }
+
+ companion object {
+ val ISSUE = Issue.create(
+ id = "PlatformImportInCommonModule",
+ briefDescription = "Platform-dependent import in a common module",
+ explanation = "Common Kotlin module cannot contain references to JVM or Android " +
+ "classes, as it reduces future portability to other Kotlin targets. Instead of " +
+ "referencing them directly, use expect/actual declarations.",
+ category = Category.CORRECTNESS,
+ priority = 5,
+ severity = Severity.ERROR,
+ implementation = Implementation(
+ PlatformImportInCommonModuleDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
+ )
+
+ private const val COMMON_MAIN_PATH_PREFIX = "src/commonMain"
+ private val PLATFORM_PACKAGES = listOf(
+ "java",
+ "javax",
+ "android"
+ )
+ }
+}
\ No newline at end of file
diff --git a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/SteppedForLoopDetector.kt b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/SteppedForLoopDetector.kt
new file mode 100644
index 0000000..d3a4b34
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/SteppedForLoopDetector.kt
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package androidx.compose.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiType
+import com.intellij.psi.impl.source.PsiClassReferenceType
+import org.jetbrains.uast.UBinaryExpression
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UExpression
+import org.jetbrains.uast.UForEachExpression
+import org.jetbrains.uast.UQualifiedReferenceExpression
+import org.jetbrains.uast.isIntegralLiteral
+import org.jetbrains.uast.kotlin.isKotlin
+import org.jetbrains.uast.skipParenthesizedExprDown
+import org.jetbrains.uast.util.isMethodCall
+
+/**
+ * Lint [Detector] to prevent allocating ranges and progression when using `step()` in a
+ * for loops. For instance: `for (i in a..b step 2)` .
+ */
+class SteppedForLoopDetector : Detector(), SourceCodeScanner {
+ override fun getApplicableUastTypes() = listOf(
+ UForEachExpression::class.java
+ )
+
+ override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
+ override fun visitForEachExpression(node: UForEachExpression) {
+ if (!isKotlin(node.lang)) return
+
+ when (val type = node.iteratedValue.skipParenthesizedExprDown()) {
+ is UBinaryExpression -> {
+ // Check the expression is of the form a step b, where a is a Progression type
+ if (
+ isIntegerProgression(type.leftOperand.getExpressionType()) &&
+ !isLiteralProgression(type.leftOperand.skipParenthesizedExprDown()) &&
+ type.operatorIdentifier?.name == "step" &&
+ isInteger(type.rightOperand.getExpressionType())
+ ) {
+ report(context, node, type, type.rightOperand.asRenderString())
+ }
+ }
+ is UQualifiedReferenceExpression -> {
+ if (type.selector.isMethodCall()) {
+ val method = type.selector as UCallExpression
+ // Check we invoke step(x) on a Progression type
+ if (
+ isIntegerProgression(method.receiverType) &&
+ !isLiteralProgression(method.receiver?.skipParenthesizedExprDown()) &&
+ method.methodName == "step" &&
+ method.valueArgumentCount == 1 &&
+ isInteger(method.valueArguments[0].getExpressionType())
+ ) {
+ report(
+ context,
+ node,
+ method,
+ method.valueArguments[0].asRenderString()
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private fun isIntegerProgression(type: PsiType?): Boolean {
+ if (type == null) return false
+
+ if (type is PsiClassReferenceType) {
+ val cls = type.resolve()
+ return cls != null &&
+ (
+ IntegerProgressionTypes.contains(cls.qualifiedName) ||
+ cls.superTypes.any {
+ IntegerProgressionTypes.contains(it.resolve()?.qualifiedName)
+ }
+ )
+ }
+
+ return false
+ }
+
+ private fun isLiteralProgression(expression: UExpression?) =
+ expression is UBinaryExpression &&
+ expression.operator.text == ".." &&
+ expression.leftOperand.skipParenthesizedExprDown().isIntegralLiteral() &&
+ expression.rightOperand.skipParenthesizedExprDown().isIntegralLiteral()
+
+ private fun isInteger(type: PsiType?) = type == PsiType.INT || type == PsiType.LONG
+
+ private fun report(context: JavaContext, node: UElement, target: Any?, messageContext: String) {
+ context.report(
+ issue = ISSUE,
+ scope = node,
+ location = context.getLocation(target),
+ message = "stepping the integer range by $messageContext."
+ )
+ }
+
+ companion object {
+ val ISSUE = Issue.create(
+ "SteppedForLoop",
+ "A loop over a primitive range (Int/Long/ULong/Char) creates " +
+ "unnecessary allocations",
+ "Using the step function when iterating over a range of integer types " +
+ "causes the allocation of a Range and of a Progression. To avoid the " +
+ "allocations, consider using a while loop and manual loop counter.",
+ Category.PERFORMANCE, 5, Severity.ERROR,
+ Implementation(
+ SteppedForLoopDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
+ )
+ val IntegerProgressionTypes = listOf(
+ "kotlin.ranges.IntProgression",
+ "kotlin.ranges.LongProgression",
+ "kotlin.ranges.CharProgression",
+ "kotlin.ranges.UIntProgression",
+ "kotlin.ranges.ULongProgression"
+ )
+ }
+}
diff --git a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/PlatformImportInCommonModuleDetectorTest.kt b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/PlatformImportInCommonModuleDetectorTest.kt
new file mode 100644
index 0000000..e716456
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/PlatformImportInCommonModuleDetectorTest.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package androidx.compose.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/* ktlint-disable max-line-length */
+@RunWith(JUnit4::class)
+class PlatformImportInCommonModuleDetectorTest : LintDetectorTest() {
+ override fun getDetector(): Detector = PlatformImportInCommonModuleDetector()
+
+ override fun getIssues(): MutableList<Issue> = mutableListOf(
+ PlatformImportInCommonModuleDetector.ISSUE
+ )
+
+ @Test
+ fun detectsImportInCommonMain() {
+ val file = kotlin(
+ "commonMain/test/TestFile.kt",
+ """
+ package test
+
+ import java.util.ArrayList as MyList
+ import java.util.*
+ import java.*
+ import android.os.Bundle
+ import android.*
+ """
+ ).within("src")
+
+ lint().files(
+ file
+ )
+ .run()
+ .expect(
+ """
+src/commonMain/test/TestFile.kt:4: Error: Platform-dependent import in a common module [PlatformImportInCommonModule]
+ import java.util.ArrayList as MyList
+ ~~~~~~~~~~~~~~~~~~~
+src/commonMain/test/TestFile.kt:5: Error: Platform-dependent import in a common module [PlatformImportInCommonModule]
+ import java.util.*
+ ~~~~~~~~~
+src/commonMain/test/TestFile.kt:6: Error: Platform-dependent import in a common module [PlatformImportInCommonModule]
+ import java.*
+ ~~~~
+src/commonMain/test/TestFile.kt:7: Error: Platform-dependent import in a common module [PlatformImportInCommonModule]
+ import android.os.Bundle
+ ~~~~~~~~~~~~~~~~~
+src/commonMain/test/TestFile.kt:8: Error: Platform-dependent import in a common module [PlatformImportInCommonModule]
+ import android.*
+ ~~~~~~~
+5 errors, 0 warnings
+ """.trimIndent()
+ )
+ }
+
+ @Test
+ fun ignoresImportInOtherModules() {
+ val jvmFile = kotlin(
+ "jvmMain/test/TestFile.kt",
+ """
+ package test
+
+ import java.util.ArrayList as MyList
+ import java.util.*
+ import java.*
+ import android.os.Bundle
+ import android.*
+ """
+ ).within("src")
+
+ val androidFile = kotlin(
+ "androidMain/test/TestFile.kt",
+ """
+ package test
+
+ import java.util.*
+ import java.*
+ import android.os.Bundle
+ import android.*
+ """
+ ).within("src")
+
+ val file = kotlin(
+ "main/test/TestFile.kt",
+ """
+ package test
+
+ import java.util.*
+ import java.*
+ import android.os.Bundle
+ import android.*
+ """
+ ).within("src")
+
+ lint().files(
+ file,
+ androidFile,
+ jvmFile
+ )
+ .run()
+ .expectClean()
+ }
+}
+/* ktlint-enable max-line-length */
diff --git a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/SteppedForLoopDetectorTest.kt b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/SteppedForLoopDetectorTest.kt
new file mode 100644
index 0000000..47f2175
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/SteppedForLoopDetectorTest.kt
@@ -0,0 +1,362 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package androidx.compose.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/* ktlint-disable max-line-length */
+@RunWith(JUnit4::class)
+class SteppedForLoopDetectorTest : LintDetectorTest() {
+ override fun getDetector(): Detector = SteppedForLoopDetector()
+
+ override fun getIssues(): MutableList<Issue> = mutableListOf(
+ SteppedForLoopDetector.ISSUE
+ )
+
+ @Test
+ fun skippedOnRegularLoops() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ fun test(a: Int, b: Int) {
+ for (i in a..b) {
+ println(i)
+ }
+ for (i in a until b) {
+ println(i)
+ }
+ for (i in a downTo b) {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun calledOnSteppedLoop() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ fun test(a: Int, b: Int) {
+ for (i in a..b step 2) {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expect(
+ """
+src/test/test.kt:5: Error: stepping the integer range by 2. [SteppedForLoop]
+ for (i in a..b step 2) {
+ ~~~~~~~~~~~
+1 errors, 0 warnings
+ """
+ )
+ }
+
+ @Test
+ fun skippedOnConstantSteppedLoop() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ fun test() {
+ for (i in 0..10 step 2) {
+ println(i)
+ }
+ for (i in (0..10).step(2)) {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun calledOnUnitSteppedLoop() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ fun test(a: Int, b: Int) {
+ for (i in a..b step 1) {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expect(
+ """
+src/test/test.kt:5: Error: stepping the integer range by 1. [SteppedForLoop]
+ for (i in a..b step 1) {
+ ~~~~~~~~~~~
+1 errors, 0 warnings
+ """
+ )
+ }
+
+ @Test
+ fun calledOnExpressionSteppedLoop() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ fun test(a: Int, b: Int, c: Int) {
+ for (i in a..b step (c / 2)) {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expect(
+ """
+src/test/test.kt:5: Error: stepping the integer range by (c / 2). [SteppedForLoop]
+ for (i in a..b step (c / 2)) {
+ ~~~~~~~~~~~~~~~~~
+1 errors, 0 warnings
+ """
+ )
+ }
+
+ @Test
+ fun calledOnSteppedUntilLoop() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ fun test(a: Int, b: Int) {
+ for (i in a until b step 2) {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expect(
+ """
+src/test/test.kt:5: Error: stepping the integer range by 2. [SteppedForLoop]
+ for (i in a until b step 2) {
+ ~~~~~~~~~~~~~~~~
+1 errors, 0 warnings
+ """
+ )
+ }
+
+ @Test
+ fun calledOnSteppedDownToLoop() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ fun test(a: Int, b: Int) {
+ for (i in a downTo b step 2) {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expect(
+ """
+src/test/test.kt:5: Error: stepping the integer range by 2. [SteppedForLoop]
+ for (i in a downTo b step 2) {
+ ~~~~~~~~~~~~~~~~~
+1 errors, 0 warnings
+ """
+ )
+ }
+
+ @Test
+ fun calledOnStepAsFunctionLoop() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ fun test(a: Int, b: Int) {
+ for (i in (a..b).step(2)) {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expect(
+ """
+src/test/test.kt:5: Error: stepping the integer range by 2. [SteppedForLoop]
+ for (i in (a..b).step(2)) {
+ ~~~~~~~~~~~~~~
+1 errors, 0 warnings
+ """
+ )
+ }
+
+ @Test
+ fun calledOnNonIntSteppedLoop() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ fun test(a: UInt, b: UInt) {
+ for (i in a..b step 2) {
+ println(i)
+ }
+ }
+ fun test(a: Char, b: Char) {
+ for (i in a..b step 2) {
+ println(i)
+ }
+ }
+ fun test(a: Long, b: Long) {
+ for (i in a..b step 2L) {
+ println(i)
+ }
+ }
+ fun test(a: ULong, b: ULong) {
+ for (i in a..b step 2L) {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expect(
+ """
+src/test/test.kt:5: Error: stepping the integer range by 2. [SteppedForLoop]
+ for (i in a..b step 2) {
+ ~~~~~~~~~~~
+src/test/test.kt:10: Error: stepping the integer range by 2. [SteppedForLoop]
+ for (i in a..b step 2) {
+ ~~~~~~~~~~~
+src/test/test.kt:15: Error: stepping the integer range by 2. [SteppedForLoop]
+ for (i in a..b step 2L) {
+ ~~~~~~~~~~~~
+src/test/test.kt:20: Error: stepping the integer range by 2. [SteppedForLoop]
+ for (i in a..b step 2L) {
+ ~~~~~~~~~~~~
+4 errors, 0 warnings
+ """
+ )
+ }
+
+ @Test
+ fun skippedOnStepMethodOnUnknownTypes() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ class RangeProducerForTest(val start: Int, val end: Int) {
+ fun step(i: Int) = start..end step i
+ }
+
+ fun step(i: Int) = 0..10 step i
+
+ fun test(a: Int, b: Int) {
+ for (i in RangeProducerForTest(a, b).step(2)) {
+ println(i)
+ }
+ for (i in step(2)) {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun skippedOnStepWithNonIntegerArgumentsTypes() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ fun IntProgression.step(s: String) =
+ IntProgression.fromClosedRange(first, last, s.length)
+
+ fun test(a: Int, b: Int) {
+ for (i in 0..10 step "abc") {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun skippedOnStepWithMoreThanOneArgument() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ fun IntProgression.step(a: Int, b: Int) =
+ IntProgression.fromClosedRange(first, last, a + b)
+
+ fun test(a: Int, b: Int) {
+ for (i in (0..10).step(1, 3)) {
+ println(i)
+ }
+ }
+ """
+ )
+ )
+ .run()
+ .expectClean()
+ }
+}
+/* ktlint-enable max-line-length */
diff --git a/compose/material/material/api/current.txt b/compose/material/material/api/current.txt
index 3ce6f1ce..f364bc2 100644
--- a/compose/material/material/api/current.txt
+++ b/compose/material/material/api/current.txt
@@ -82,6 +82,7 @@
method public suspend Object? expand(kotlin.coroutines.Continuation<? super kotlin.Unit>);
method public androidx.compose.material.BottomDrawerValue getCurrentValue();
method public float getOffset();
+ method public float getProgress();
method public androidx.compose.material.BottomDrawerValue getTargetValue();
method public boolean isClosed();
method public boolean isExpanded();
@@ -92,6 +93,7 @@
property public final boolean isExpanded;
property public final boolean isOpen;
property public final float offset;
+ property @androidx.compose.material.ExperimentalMaterialApi public final float progress;
property public final androidx.compose.material.BottomDrawerValue targetValue;
field public static final androidx.compose.material.BottomDrawerState.Companion Companion;
}
@@ -153,6 +155,7 @@
method public androidx.compose.material.BottomSheetValue getCurrentValue();
method @Deprecated public float getOffset();
method public float getProgress();
+ method public androidx.compose.material.BottomSheetValue getTargetValue();
method public boolean isCollapsed();
method public boolean isExpanded();
method public float requireOffset();
@@ -160,7 +163,8 @@
property public final boolean isCollapsed;
property public final boolean isExpanded;
property @Deprecated public final float offset;
- property public final float progress;
+ property @androidx.compose.material.ExperimentalMaterialApi public final float progress;
+ property public final androidx.compose.material.BottomSheetValue targetValue;
field public static final androidx.compose.material.BottomSheetState.Companion Companion;
}
@@ -544,12 +548,14 @@
ctor @Deprecated public ModalBottomSheetState(androidx.compose.material.ModalBottomSheetValue initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional boolean isSkipHalfExpanded, kotlin.jvm.functions.Function1<? super androidx.compose.material.ModalBottomSheetValue,java.lang.Boolean> confirmStateChange);
ctor @Deprecated public ModalBottomSheetState(androidx.compose.material.ModalBottomSheetValue initialValue, androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function1<? super androidx.compose.material.ModalBottomSheetValue,java.lang.Boolean> confirmStateChange);
method public androidx.compose.material.ModalBottomSheetValue getCurrentValue();
+ method public float getProgress();
method public androidx.compose.material.ModalBottomSheetValue getTargetValue();
method public suspend Object? hide(kotlin.coroutines.Continuation<? super kotlin.Unit>);
method public boolean isVisible();
method public suspend Object? show(kotlin.coroutines.Continuation<? super kotlin.Unit>);
property public final androidx.compose.material.ModalBottomSheetValue currentValue;
property public final boolean isVisible;
+ property @androidx.compose.material.ExperimentalMaterialApi public final float progress;
property public final androidx.compose.material.ModalBottomSheetValue targetValue;
field public static final androidx.compose.material.ModalBottomSheetState.Companion Companion;
}
diff --git a/compose/material/material/api/restricted_current.txt b/compose/material/material/api/restricted_current.txt
index 3ce6f1ce..f364bc2 100644
--- a/compose/material/material/api/restricted_current.txt
+++ b/compose/material/material/api/restricted_current.txt
@@ -82,6 +82,7 @@
method public suspend Object? expand(kotlin.coroutines.Continuation<? super kotlin.Unit>);
method public androidx.compose.material.BottomDrawerValue getCurrentValue();
method public float getOffset();
+ method public float getProgress();
method public androidx.compose.material.BottomDrawerValue getTargetValue();
method public boolean isClosed();
method public boolean isExpanded();
@@ -92,6 +93,7 @@
property public final boolean isExpanded;
property public final boolean isOpen;
property public final float offset;
+ property @androidx.compose.material.ExperimentalMaterialApi public final float progress;
property public final androidx.compose.material.BottomDrawerValue targetValue;
field public static final androidx.compose.material.BottomDrawerState.Companion Companion;
}
@@ -153,6 +155,7 @@
method public androidx.compose.material.BottomSheetValue getCurrentValue();
method @Deprecated public float getOffset();
method public float getProgress();
+ method public androidx.compose.material.BottomSheetValue getTargetValue();
method public boolean isCollapsed();
method public boolean isExpanded();
method public float requireOffset();
@@ -160,7 +163,8 @@
property public final boolean isCollapsed;
property public final boolean isExpanded;
property @Deprecated public final float offset;
- property public final float progress;
+ property @androidx.compose.material.ExperimentalMaterialApi public final float progress;
+ property public final androidx.compose.material.BottomSheetValue targetValue;
field public static final androidx.compose.material.BottomSheetState.Companion Companion;
}
@@ -544,12 +548,14 @@
ctor @Deprecated public ModalBottomSheetState(androidx.compose.material.ModalBottomSheetValue initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional boolean isSkipHalfExpanded, kotlin.jvm.functions.Function1<? super androidx.compose.material.ModalBottomSheetValue,java.lang.Boolean> confirmStateChange);
ctor @Deprecated public ModalBottomSheetState(androidx.compose.material.ModalBottomSheetValue initialValue, androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function1<? super androidx.compose.material.ModalBottomSheetValue,java.lang.Boolean> confirmStateChange);
method public androidx.compose.material.ModalBottomSheetValue getCurrentValue();
+ method public float getProgress();
method public androidx.compose.material.ModalBottomSheetValue getTargetValue();
method public suspend Object? hide(kotlin.coroutines.Continuation<? super kotlin.Unit>);
method public boolean isVisible();
method public suspend Object? show(kotlin.coroutines.Continuation<? super kotlin.Unit>);
property public final androidx.compose.material.ModalBottomSheetValue currentValue;
property public final boolean isVisible;
+ property @androidx.compose.material.ExperimentalMaterialApi public final float progress;
property public final androidx.compose.material.ModalBottomSheetValue targetValue;
field public static final androidx.compose.material.ModalBottomSheetState.Companion Companion;
}
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/DrawerTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/DrawerTest.kt
index 1405786..8cd376a 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/DrawerTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/DrawerTest.kt
@@ -976,7 +976,6 @@
@Test
@LargeTest
fun bottomDrawer_respectsConfirmStateChange(): Unit = runBlocking(AutoTestFrameClock()) {
- val contentTag = "contentTestTag"
lateinit var drawerState: BottomDrawerState
rule.setMaterialContent {
drawerState = rememberBottomDrawerState(
@@ -998,7 +997,6 @@
Box(
Modifier
.fillMaxSize()
- .testTag(contentTag)
)
}
)
@@ -1008,7 +1006,7 @@
assertThat(drawerState.currentValue).isEqualTo(BottomDrawerValue.Expanded)
}
- rule.onNodeWithTag(contentTag)
+ rule.onNodeWithTag(bottomDrawerTag)
.performTouchInput { swipeDown() }
advanceClock()
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ExposedDropdownMenuTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ExposedDropdownMenuTest.kt
index 246125e..025a3ba 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ExposedDropdownMenuTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ExposedDropdownMenuTest.kt
@@ -43,6 +43,7 @@
import androidx.compose.ui.test.assertIsFocused
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertTextContains
+import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
@@ -157,7 +158,10 @@
rule.waitForIdle()
}
- rule.onNodeWithTag(TFTag).assertTextContains("zzz")
+ val matcher = hasText("zzz")
+ rule.waitUntil {
+ matcher.matches(rule.onNodeWithTag(TFTag).fetchSemanticsNode())
+ }
rule.onNodeWithTag(MenuItemTag).assertIsDisplayed()
}
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/TextTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/TextTest.kt
index 5fea47d..c88d6a5 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/TextTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/TextTest.kt
@@ -35,7 +35,7 @@
import androidx.compose.ui.unit.sp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
-import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -58,6 +58,25 @@
private val TestText = "TestText"
@Test
+ fun testDefaultIncludeFontPadding() {
+ var localTextStyle: TextStyle? = null
+ var display1TextStyle: TextStyle? = null
+ rule.setContent {
+ MaterialTheme {
+ localTextStyle = LocalTextStyle.current
+ display1TextStyle = LocalTypography.current.body1
+ }
+ }
+
+ assertThat(
+ localTextStyle?.platformStyle?.paragraphStyle?.includeFontPadding
+ ).isEqualTo(false)
+ assertThat(
+ display1TextStyle?.platformStyle?.paragraphStyle?.includeFontPadding
+ ).isEqualTo(false)
+ }
+
+ @Test
fun inheritsThemeTextStyle() {
var textColor: Color? = null
var textAlign: TextAlign? = null
@@ -82,11 +101,11 @@
}
rule.runOnIdle {
- Truth.assertThat(textColor).isEqualTo(ExpectedTextStyle.color)
- Truth.assertThat(textAlign).isEqualTo(ExpectedTextStyle.textAlign)
- Truth.assertThat(fontSize).isEqualTo(ExpectedTextStyle.fontSize)
- Truth.assertThat(fontStyle).isEqualTo(ExpectedTextStyle.fontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(ExpectedTextStyle.letterSpacing)
+ assertThat(textColor).isEqualTo(ExpectedTextStyle.color)
+ assertThat(textAlign).isEqualTo(ExpectedTextStyle.textAlign)
+ assertThat(fontSize).isEqualTo(ExpectedTextStyle.fontSize)
+ assertThat(fontStyle).isEqualTo(ExpectedTextStyle.fontStyle)
+ assertThat(letterSpacing).isEqualTo(ExpectedTextStyle.letterSpacing)
}
}
@@ -123,11 +142,11 @@
}
rule.runOnIdle {
- Truth.assertThat(textColor).isEqualTo(testStyle.color)
- Truth.assertThat(textAlign).isEqualTo(testStyle.textAlign)
- Truth.assertThat(fontSize).isEqualTo(testStyle.fontSize)
- Truth.assertThat(fontStyle).isEqualTo(testStyle.fontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(testStyle.letterSpacing)
+ assertThat(textColor).isEqualTo(testStyle.color)
+ assertThat(textAlign).isEqualTo(testStyle.textAlign)
+ assertThat(fontSize).isEqualTo(testStyle.fontSize)
+ assertThat(fontStyle).isEqualTo(testStyle.fontStyle)
+ assertThat(letterSpacing).isEqualTo(testStyle.letterSpacing)
}
}
@@ -166,10 +185,10 @@
rule.runOnIdle {
// explicit parameters should override values from the style.
- Truth.assertThat(textAlign).isEqualTo(expectedTextAlign)
- Truth.assertThat(fontSize).isEqualTo(expectedFontSize)
- Truth.assertThat(fontStyle).isEqualTo(expectedFontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
+ assertThat(textAlign).isEqualTo(expectedTextAlign)
+ assertThat(fontSize).isEqualTo(expectedFontSize)
+ assertThat(fontStyle).isEqualTo(expectedFontStyle)
+ assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
}
}
@@ -210,10 +229,10 @@
rule.runOnIdle {
// explicit parameters should override values from the style.
- Truth.assertThat(textAlign).isEqualTo(expectedTextAlign)
- Truth.assertThat(fontSize).isEqualTo(expectedFontSize)
- Truth.assertThat(fontStyle).isEqualTo(expectedFontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
+ assertThat(textAlign).isEqualTo(expectedTextAlign)
+ assertThat(fontSize).isEqualTo(expectedFontSize)
+ assertThat(fontStyle).isEqualTo(expectedFontStyle)
+ assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
}
}
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableStateTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableStateTest.kt
index d95fcb5..1a7dfc5 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableStateTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableStateTest.kt
@@ -266,6 +266,40 @@
}
@Test
+ fun anchoredDraggable_closestValue() {
+ val initialValue = A
+ val initialValueOffset = 0f
+ val state = AnchoredDraggableState(
+ initialValue = initialValue,
+ positionalThreshold = defaultPositionalThreshold,
+ velocityThreshold = defaultVelocityThreshold
+ )
+ val anchors = mapOf(
+ initialValue to initialValueOffset,
+ B to 200f,
+ C to 400f
+ )
+ state.updateAnchors(anchors)
+
+ assertThat(state.offset).isEqualTo(initialValueOffset)
+ assertThat(state.currentValue).isEqualTo(A)
+ assertThat(state.closestValue).isEqualTo(A)
+
+ val aToBDistance = 200f
+ val firstTargetOffset = aToBDistance * 0.4f
+ state.dispatchRawDelta(firstTargetOffset)
+ assertThat(state.offset).isEqualTo(firstTargetOffset)
+ assertThat(state.currentValue).isEqualTo(A)
+ assertThat(state.closestValue).isEqualTo(B)
+
+ val secondTargetOffset = aToBDistance * 0.6f
+ state.dispatchRawDelta(secondTargetOffset - state.offset)
+ assertThat(state.offset).isEqualTo(secondTargetOffset)
+ assertThat(state.currentValue).isEqualTo(A)
+ assertThat(state.closestValue).isEqualTo(B)
+ }
+
+ @Test
fun anchoredDraggable_progress_matchesSwipePosition() {
lateinit var state: AnchoredDraggableState<AnchoredDraggableTestValue>
rule.setContent {
@@ -806,6 +840,53 @@
}
@Test
+ fun anchoredDraggable_customDrag_doesntCallConfirm() = runBlocking {
+
+ var counter: Int = 0
+
+ val state = AnchoredDraggableState(
+ initialValue = A,
+ positionalThreshold = defaultPositionalThreshold,
+ velocityThreshold = defaultVelocityThreshold,
+ confirmValueChange = {
+ counter++
+ false
+ }
+ )
+ state.updateAnchors(mapOf(A to 0f, B to 200f, C to 300f))
+ state.anchoredDrag {
+ // should be B
+ dragTo(200f)
+ }
+
+ assertThat(counter).isEqualTo(0)
+ assertThat(state.currentValue).isEqualTo(B)
+ }
+
+ @Test
+ fun anchoredDraggable_customDrag_noAnchor_doesntCallConfirm() = runBlocking {
+
+ var counter: Int = 0
+
+ val state = AnchoredDraggableState(
+ initialValue = A,
+ positionalThreshold = defaultPositionalThreshold,
+ velocityThreshold = defaultVelocityThreshold,
+ confirmValueChange = {
+ counter++
+ false
+ }
+ )
+ state.updateAnchors(mapOf(A to 0f, B to 200f))
+ state.anchoredDrag(targetValue = C) {
+ // no op, doesn't matter
+ }
+
+ assertThat(counter).isEqualTo(0)
+ assertThat(state.currentValue).isEqualTo(C)
+ }
+
+ @Test
fun anchoredDraggable_updateAnchors_ongoingOffsetMutation_shouldNotUpdate() = runBlocking {
val clock = HandPumpTestFrameClock()
val animationScope = CoroutineScope(clock)
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldScreenshotTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldScreenshotTest.kt
index 5909fc2..e9d4389 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldScreenshotTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldScreenshotTest.kt
@@ -27,6 +27,7 @@
import androidx.compose.material.LocalContentColor
import androidx.compose.material.Text
import androidx.compose.material.TextField
+import androidx.compose.material.defaultPlatformTextStyle
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Call
import androidx.compose.material.icons.filled.Clear
@@ -74,6 +75,8 @@
@get:Rule
val rule = createComposeRule()
+ private val platformTextStyle = defaultPlatformTextStyle()
+
@get:Rule
val screenshotRule = AndroidXScreenshotTestRule(GOLDEN_MATERIAL)
@@ -367,7 +370,7 @@
@Test
fun textField_disabled() {
- rule.setContent {
+ rule.setMaterialContent {
TextField(
value = TextFieldValue("Text"),
onValueChange = {},
@@ -382,7 +385,7 @@
@Test
fun textField_disabled_notFocusable() {
- rule.setContent {
+ rule.setMaterialContent {
TextField(
value = TextFieldValue("Text"),
onValueChange = {},
@@ -399,7 +402,7 @@
@Test
fun textField_disabled_notScrolled() {
- rule.setContent {
+ rule.setMaterialContent {
TextField(
value = longText,
onValueChange = { },
@@ -422,7 +425,7 @@
@Test
fun textField_readOnly() {
- rule.setContent {
+ rule.setMaterialContent {
TextField(
value = TextFieldValue("Text"),
onValueChange = {},
@@ -437,7 +440,7 @@
@Test
fun textField_readOnly_focused() {
- rule.setContent {
+ rule.setMaterialContent {
TextField(
value = TextFieldValue("Text"),
onValueChange = {},
@@ -454,7 +457,7 @@
@Test
fun textField_readOnly_scrolled() {
- rule.setContent {
+ rule.setMaterialContent {
TextField(
value = longText,
onValueChange = { },
@@ -483,7 +486,10 @@
value = TextFieldValue(text = text, selection = TextRange(text.length)),
onValueChange = {},
modifier = Modifier.width(300.dp).testTag(TextFieldTag),
- textStyle = TextStyle(textAlign = TextAlign.Center),
+ textStyle = TextStyle(
+ textAlign = TextAlign.Center,
+ platformStyle = platformTextStyle
+ ),
singleLine = true
)
}
@@ -499,7 +505,7 @@
value = TextFieldValue(text = text, selection = TextRange(text.length)),
onValueChange = {},
modifier = Modifier.fillMaxWidth().testTag(TextFieldTag),
- textStyle = TextStyle(textAlign = TextAlign.End),
+ textStyle = TextStyle(textAlign = TextAlign.End, platformStyle = platformTextStyle),
singleLine = true
)
}
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
index 214cfb7..7cb2fca 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
@@ -140,7 +140,7 @@
private val ExpectedPadding = 16.dp
private val IconPadding = 12.dp
private val ExpectedBaselineOffset = 20.dp
- private val TopPaddingFilledTextfield = 4.dp
+ private val TopPaddingFilledTextfield = 2.dp
private val IconColorAlpha = 0.54f
private val TextfieldTag = "textField"
@@ -374,12 +374,11 @@
assertThat(labelSize.value?.height).isGreaterThan(0)
assertThat(labelSize.value?.width).isGreaterThan(0)
// centered position
- assertThat(labelPosition.value?.x).isEqualTo(
- ExpectedPadding.roundToPx().toFloat()
+ assertThat(labelPosition.value?.x).isWithin(1f).of(
+ ExpectedPadding.toPx()
)
- assertThat(labelPosition.value?.y).isEqualTo(
- ((ExpectedDefaultTextFieldHeight.roundToPx() - labelSize.value!!.height) / 2f)
- .roundToInt().toFloat()
+ assertThat(labelPosition.value?.y).isWithin(1f).of(
+ (ExpectedDefaultTextFieldHeight.toPx() - labelSize.value!!.height) / 2f
)
}
}
diff --git a/compose/material/material/src/androidMain/kotlin/androidx/compose/material/DefaultPlatformTextStyle.android.kt b/compose/material/material/src/androidMain/kotlin/androidx/compose/material/DefaultPlatformTextStyle.android.kt
index 2e65f0c..46cae05 100644
--- a/compose/material/material/src/androidMain/kotlin/androidx/compose/material/DefaultPlatformTextStyle.android.kt
+++ b/compose/material/material/src/androidMain/kotlin/androidx/compose/material/DefaultPlatformTextStyle.android.kt
@@ -18,7 +18,7 @@
import androidx.compose.ui.text.PlatformTextStyle
-private const val DefaultIncludeFontPadding = true
+private const val DefaultIncludeFontPadding = false
@Suppress("DEPRECATION")
private val DefaultPlatformTextStyle = PlatformTextStyle(
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
index c93036a..ae45958 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
@@ -36,6 +36,7 @@
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.structuralEqualityPolicy
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
@@ -162,8 +163,8 @@
private set
/**
- * The target value. This is the closest value to the current offset (taking into account
- * positional thresholds). If no interactions like animations or drags are in progress, this
+ * The target value. This is the closest value to the current offset, taking into account
+ * positional thresholds. If no interactions like animations or drags are in progress, this
* will be the current value.
*/
val targetValue: T by derivedStateOf {
@@ -176,6 +177,20 @@
}
/**
+ * The closest value in the swipe direction from the current offset, not considering thresholds.
+ * If an [anchoredDrag] is in progress, this will be the target of that anchoredDrag (if
+ * specified).
+ */
+ internal val closestValue: T by derivedStateOf {
+ animationTarget ?: run {
+ val currentOffset = offset
+ if (!currentOffset.isNaN()) {
+ computeTargetWithoutThresholds(currentOffset, currentValue)
+ } else currentValue
+ }
+ }
+
+ /**
* The current offset, or [Float.NaN] if it has not been initialized yet.
*
* The offset will be initialized when the anchors are first set through [updateAnchors].
@@ -183,9 +198,7 @@
* Strongly consider using [requireOffset] which will throw if the offset is read before it is
* initialized. This helps catch issues early in your workflow.
*/
- // Todo: Use primitive state when b/281205384 is fixed
- @Suppress("AutoboxingStateCreation")
- var offset: Float by mutableStateOf(Float.NaN)
+ var offset: Float by mutableFloatStateOf(Float.NaN)
private set
/**
@@ -209,20 +222,20 @@
val isAnimationRunning: Boolean get() = animationTarget != null
/**
- * The fraction of the progress going from [currentValue] to [targetValue], within [0f..1f]
- * bounds.
+ * The fraction of the progress going from [currentValue] to [closestValue], within [0f..1f]
+ * bounds, or 1f if the [AnchoredDraggableState] is in a settled state.
*/
/*@FloatRange(from = 0f, to = 1f)*/
- val progress: Float by derivedStateOf {
- val a = anchors[currentValue] ?: 0f
- val b = anchors[targetValue] ?: 0f
- val distance = abs(b - a)
- if (distance > 1e-6f) {
- val progress = (this.requireOffset() - a) / (b - a)
- // If we are very close to 0f or 1f, we round to the closest
- if (progress < 1e-6f) 0f else if (progress > 1 - 1e-6f) 1f else progress
- } else 1f
- }
+ val progress: Float by derivedStateOf(structuralEqualityPolicy()) {
+ val a = anchors[currentValue] ?: 0f
+ val b = anchors[closestValue] ?: 0f
+ val distance = abs(b - a)
+ if (distance > 1e-6f) {
+ val progress = (this.requireOffset() - a) / (b - a)
+ // If we are very close to 0f or 1f, we round to the closest
+ if (progress < 1e-6f) 0f else if (progress > 1 - 1e-6f) 1f else progress
+ } else 1f
+ }
/**
* The velocity of the last known animation. Gets reset to 0f when an animation completes
@@ -352,6 +365,21 @@
}
}
+ private fun computeTargetWithoutThresholds(
+ offset: Float,
+ currentValue: T,
+ ): T {
+ val currentAnchors = anchors
+ val currentAnchor = currentAnchors[currentValue]
+ return if (currentAnchor == offset || currentAnchor == null) {
+ currentValue
+ } else if (currentAnchor < offset) {
+ currentAnchors.closestAnchor(offset, true)
+ } else {
+ currentAnchors.closestAnchor(offset, false)
+ }
+ }
+
private val anchoredDragScope: AnchoredDragScope = object : AnchoredDragScope {
override fun dragTo(newOffset: Float, lastKnownVelocity: Float) {
offset = newOffset
@@ -420,11 +448,11 @@
.firstOrNull { (_, anchorOffset) -> abs(anchorOffset - offset) < 0.5f }
?.key
- if (endState != null && confirmValueChange.invoke(endState)) {
+ if (endState != null) {
currentValue = endState
}
}
- } else if (confirmValueChange(targetValue)) {
+ } else {
currentValue = targetValue
}
}
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt
index a8f712b..56566d4 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt
@@ -158,10 +158,20 @@
}
)
+ /**
+ * The current value of the [BottomSheetState].
+ */
val currentValue: BottomSheetValue
get() = anchoredDraggableState.currentValue
/**
+ * The target value the state will settle at once the current interaction ends, or the
+ * [currentValue] if there is no interaction in progress.
+ */
+ val targetValue: BottomSheetValue
+ get() = anchoredDraggableState.targetValue
+
+ /**
* Whether the bottom sheet is expanded.
*/
val isExpanded: Boolean
@@ -174,10 +184,11 @@
get() = anchoredDraggableState.currentValue == Collapsed
/**
- * The fraction of the progress going from [currentValue] to the targetValue, within [0f..1f]
- * bounds, or 1f if the sheet is in a settled state.
+ * The fraction of the progress, within [0f..1f] bounds, or 1f if the [AnchoredDraggableState]
+ * is in a settled state.
*/
/*@FloatRange(from = 0f, to = 1f)*/
+ @ExperimentalMaterialApi
val progress: Float
get() = anchoredDraggableState.progress
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Button.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Button.kt
index b27bb71..3cc822a 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Button.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Button.kt
@@ -53,7 +53,6 @@
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import kotlinx.coroutines.flow.collect
/**
* <a href="https://material.io/components/buttons#contained-button" class="external" target="_blank">Material Design contained button</a>.
@@ -548,24 +547,24 @@
val animatable = remember { Animatable(target, Dp.VectorConverter) }
- if (!enabled) {
- // No transition when moving to a disabled state
- LaunchedEffect(target) {
- animatable.snapTo(target)
- }
- } else {
- LaunchedEffect(target) {
- val lastInteraction = when (animatable.targetValue) {
- pressedElevation -> PressInteraction.Press(Offset.Zero)
- hoveredElevation -> HoverInteraction.Enter()
- focusedElevation -> FocusInteraction.Focus()
- else -> null
+ LaunchedEffect(target) {
+ if (animatable.targetValue != target) {
+ if (!enabled) {
+ // No transition when moving to a disabled state
+ animatable.snapTo(target)
+ } else {
+ val lastInteraction = when (animatable.targetValue) {
+ pressedElevation -> PressInteraction.Press(Offset.Zero)
+ hoveredElevation -> HoverInteraction.Enter()
+ focusedElevation -> FocusInteraction.Focus()
+ else -> null
+ }
+ animatable.animateElevation(
+ from = lastInteraction,
+ to = interaction,
+ target = target
+ )
}
- animatable.animateElevation(
- from = lastInteraction,
- to = interaction,
- target = target
- )
}
}
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt
index d7162a6..717e730 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt
@@ -326,6 +326,15 @@
val currentValue: BottomDrawerValue get() = anchoredDraggableState.currentValue
/**
+ * The fraction of the progress, within [0f..1f] bounds, or 1f if the [AnchoredDraggableState]
+ * is in a settled state.
+ */
+ /*@FloatRange(from = 0f, to = 1f)*/
+ @ExperimentalMaterialApi
+ val progress: Float
+ get() = anchoredDraggableState.progress
+
+ /**
* Whether the drawer is open, either in opened or expanded state.
*/
val isOpen: Boolean
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/FloatingActionButton.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/FloatingActionButton.kt
index 8995a68..59add59 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/FloatingActionButton.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/FloatingActionButton.kt
@@ -37,11 +37,9 @@
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
-import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.semantics.Role
@@ -49,7 +47,9 @@
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.launch
/**
* <a href="https://material.io/components/buttons-floating-action-button" class="external" target="_blank">Material Design floating action button</a>.
@@ -271,8 +271,15 @@
) : FloatingActionButtonElevation {
@Composable
override fun elevation(interactionSource: InteractionSource): State<Dp> {
- val interactions = remember { mutableStateListOf<Interaction>() }
+ val animatable = remember(interactionSource) {
+ Animatable(defaultElevation, Dp.VectorConverter)
+ }
+
LaunchedEffect(interactionSource) {
+ var animation: Job? = null
+ var lastTargetInteraction: Interaction? = null
+ var lastTarget: Dp? = null
+ val interactions = mutableListOf<Interaction>()
interactionSource.interactions.collect { interaction ->
when (interaction) {
is HoverInteraction.Enter -> {
@@ -297,34 +304,38 @@
interactions.remove(interaction.press)
}
}
+ val targetInteraction = interactions.lastOrNull()
+ val target = when (targetInteraction) {
+ is PressInteraction.Press -> pressedElevation
+ is HoverInteraction.Enter -> hoveredElevation
+ is FocusInteraction.Focus -> focusedElevation
+ else -> defaultElevation
+ }
+ if (lastTarget != target) {
+ lastTarget = target
+ // Cancel any existing animations if we change target
+ animation?.cancelAndJoin()
+ // We need to handle the case where the target has changed, but the animation
+ // was cancelled so quickly that its internal target never got changed - if
+ // this happened and we are back at the same target before the cancelled
+ // animation, we don't want to do anything.
+ if (animatable.targetValue != target) {
+ animation = launch {
+ try {
+ animatable.animateElevation(
+ from = lastTargetInteraction,
+ to = targetInteraction,
+ target = target
+ )
+ } finally {
+ lastTargetInteraction = targetInteraction
+ }
+ }
+ }
+ }
}
}
- val interaction = interactions.lastOrNull()
-
- val target = when (interaction) {
- is PressInteraction.Press -> pressedElevation
- is HoverInteraction.Enter -> hoveredElevation
- is FocusInteraction.Focus -> focusedElevation
- else -> defaultElevation
- }
-
- val animatable = remember { Animatable(target, Dp.VectorConverter) }
-
- LaunchedEffect(target) {
- val lastInteraction = when (animatable.targetValue) {
- pressedElevation -> PressInteraction.Press(Offset.Zero)
- hoveredElevation -> HoverInteraction.Enter()
- focusedElevation -> FocusInteraction.Focus()
- else -> null
- }
- animatable.animateElevation(
- from = lastInteraction,
- to = interaction,
- target = target
- )
- }
-
return animatable.asState()
}
}
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ListItem.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ListItem.kt
index d3b5ef5..4d8e6aa 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ListItem.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ListItem.kt
@@ -32,6 +32,7 @@
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.style.LineHeightStyle
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntSize
@@ -420,9 +421,13 @@
icon: @Composable (() -> Unit)?
): @Composable (() -> Unit)? {
if (icon == null) return null
+ val lineHeightStyle = LineHeightStyle(
+ alignment = LineHeightStyle.Alignment.Proportional,
+ trim = LineHeightStyle.Trim.Both,
+ )
return {
CompositionLocalProvider(LocalContentAlpha provides contentAlpha) {
- ProvideTextStyle(textStyle, icon)
+ ProvideTextStyle(textStyle.copy(lineHeightStyle = lineHeightStyle), icon)
}
}
}
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt
index 8b9eef6..e1e32fc 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt
@@ -211,13 +211,29 @@
velocityThreshold = { with(requireDensity()) { ModalBottomSheetVelocityThreshold.toPx() } }
)
+ /**
+ * The current value of the [ModalBottomSheetState].
+ */
val currentValue: ModalBottomSheetValue
get() = anchoredDraggableState.currentValue
+ /**
+ * The target value the state will settle at once the current interaction ends, or the
+ * [currentValue] if there is no interaction in progress.
+ */
val targetValue: ModalBottomSheetValue
get() = anchoredDraggableState.targetValue
/**
+ * The fraction of the progress, within [0f..1f] bounds, or 1f if the [AnchoredDraggableState]
+ * is in a settled state.
+ */
+ /*@FloatRange(from = 0f, to = 1f)*/
+ @ExperimentalMaterialApi
+ val progress: Float
+ get() = anchoredDraggableState.progress
+
+ /**
* Whether the bottom sheet is visible.
*/
val isVisible: Boolean
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
index 984e496..66b4ad1 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
@@ -928,4 +928,4 @@
/** Padding from label's baseline (or FirstBaselineOffset) to the input field */
/*@VisibleForTesting*/
-internal val TextFieldTopPadding = 4.dp
\ No newline at end of file
+internal val TextFieldTopPadding = 2.dp
\ No newline at end of file
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Typography.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Typography.kt
index 492072d..ee273d1 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Typography.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Typography.kt
@@ -22,6 +22,7 @@
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.LineHeightStyle
import androidx.compose.ui.unit.sp
/**
@@ -121,66 +122,79 @@
h1: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Light,
fontSize = 96.sp,
+ lineHeight = 112.sp,
letterSpacing = (-1.5).sp
),
h2: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Light,
fontSize = 60.sp,
+ lineHeight = 72.sp,
letterSpacing = (-0.5).sp
),
h3: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Normal,
fontSize = 48.sp,
+ lineHeight = 56.sp,
letterSpacing = 0.sp
),
h4: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Normal,
fontSize = 34.sp,
+ lineHeight = 36.sp,
letterSpacing = 0.25.sp
),
h5: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Normal,
fontSize = 24.sp,
+ lineHeight = 24.sp,
letterSpacing = 0.sp
),
h6: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Medium,
fontSize = 20.sp,
+ lineHeight = 24.sp,
letterSpacing = 0.15.sp
),
subtitle1: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
+ lineHeight = 24.sp,
letterSpacing = 0.15.sp
),
subtitle2: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
+ lineHeight = 24.sp,
letterSpacing = 0.1.sp
),
body1: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
+ lineHeight = 24.sp,
letterSpacing = 0.5.sp
),
body2: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Normal,
fontSize = 14.sp,
+ lineHeight = 20.sp,
letterSpacing = 0.25.sp
),
button: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
+ lineHeight = 16.sp,
letterSpacing = 1.25.sp
),
caption: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Normal,
fontSize = 12.sp,
+ lineHeight = 16.sp,
letterSpacing = 0.4.sp
),
overline: TextStyle = DefaultTextStyle.copy(
fontWeight = FontWeight.Normal,
fontSize = 10.sp,
+ lineHeight = 16.sp,
letterSpacing = 1.5.sp
)
) : this(
@@ -285,8 +299,14 @@
return if (fontFamily != null) this else copy(fontFamily = default)
}
+internal val DefaultLineHeightStyle = LineHeightStyle(
+ alignment = LineHeightStyle.Alignment.Proportional,
+ trim = LineHeightStyle.Trim.None,
+)
+
internal val DefaultTextStyle = TextStyle.Default.copy(
- platformStyle = defaultPlatformTextStyle()
+ platformStyle = defaultPlatformTextStyle(),
+ lineHeightStyle = DefaultLineHeightStyle,
)
/**
diff --git a/compose/material3/material3-adaptive/api/current.txt b/compose/material3/material3-adaptive/api/current.txt
index 8ae70d9..0b43e4a 100644
--- a/compose/material3/material3-adaptive/api/current.txt
+++ b/compose/material3/material3-adaptive/api/current.txt
@@ -1,8 +1,85 @@
// Signature format: 4.0
package androidx.compose.material3.adaptive {
+ public final class AdaptiveLayoutDirective {
+ ctor public AdaptiveLayoutDirective(int maxHorizontalPartitions, androidx.compose.material3.adaptive.GutterSizes gutterSizes, optional int maxVerticalPartitions);
+ method public androidx.compose.material3.adaptive.GutterSizes getGutterSizes();
+ method public int getMaxHorizontalPartitions();
+ method public int getMaxVerticalPartitions();
+ property public final androidx.compose.material3.adaptive.GutterSizes gutterSizes;
+ property public final int maxHorizontalPartitions;
+ property public final int maxVerticalPartitions;
+ }
+
+ public final class AdaptiveLayoutDirectiveKt {
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.AdaptiveLayoutDirective calculateDenseAdaptiveLayoutDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo);
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.AdaptiveLayoutDirective calculateStandardAdaptiveLayoutDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo);
+ }
+
+ public final class AndroidPosture_androidKt {
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.Posture calculatePosture(java.util.List<? extends androidx.window.layout.FoldingFeature> foldingFeatures);
+ }
+
+ public final class AndroidWindowInfo_androidKt {
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.WindowAdaptiveInfo calculateWindowAdaptiveInfo(optional @UiContext android.content.Context context);
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.util.List<androidx.window.layout.FoldingFeature>> foldingFeaturesAsState(optional @UiContext android.content.Context context);
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<androidx.compose.ui.unit.IntSize> windowSizeAsState(optional @UiContext android.content.Context context);
+ }
+
@kotlin.RequiresOptIn(message="This material3-adaptive API is experimental and is likely to change or to be" + "removed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3AdaptiveApi {
}
+ public final class GutterSizes {
+ ctor public GutterSizes(float outerVertical, float innerVertical, optional float outerHorizontal, optional float innerHorizontal);
+ method public float getInnerHorizontal();
+ method public float getInnerVertical();
+ method public float getOuterHorizontal();
+ method public float getOuterVertical();
+ property public final float innerHorizontal;
+ property public final float innerVertical;
+ property public final float outerHorizontal;
+ property public final float outerVertical;
+ }
+
+ @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface PaneScaffoldScope {
+ method public androidx.compose.ui.Modifier preferredWidth(androidx.compose.ui.Modifier, float width);
+ }
+
+ @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class Posture {
+ ctor public Posture(optional boolean hasVerticalHinge, optional boolean isTabletop, optional boolean hasSeparatingHinge);
+ method public boolean getHasSeparatingHinge();
+ method public boolean getHasVerticalHinge();
+ method public boolean isTabletop();
+ property public final boolean hasSeparatingHinge;
+ property public final boolean hasVerticalHinge;
+ property public final boolean isTabletop;
+ }
+
+ @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public final class ThreePaneScaffoldArrangement {
+ ctor public ThreePaneScaffoldArrangement(androidx.compose.material3.adaptive.ThreePaneScaffoldRole firstPane, androidx.compose.material3.adaptive.ThreePaneScaffoldRole secondPane, androidx.compose.material3.adaptive.ThreePaneScaffoldRole thirdPane);
+ method public androidx.compose.material3.adaptive.ThreePaneScaffoldRole getFirstPane();
+ method public androidx.compose.material3.adaptive.ThreePaneScaffoldRole getSecondPane();
+ method public androidx.compose.material3.adaptive.ThreePaneScaffoldRole getThirdPane();
+ property public final androidx.compose.material3.adaptive.ThreePaneScaffoldRole firstPane;
+ property public final androidx.compose.material3.adaptive.ThreePaneScaffoldRole secondPane;
+ property public final androidx.compose.material3.adaptive.ThreePaneScaffoldRole thirdPane;
+ }
+
+ @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum ThreePaneScaffoldRole {
+ method public static androidx.compose.material3.adaptive.ThreePaneScaffoldRole valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.adaptive.ThreePaneScaffoldRole[] values();
+ enum_constant public static final androidx.compose.material3.adaptive.ThreePaneScaffoldRole Primary;
+ enum_constant public static final androidx.compose.material3.adaptive.ThreePaneScaffoldRole Secondary;
+ enum_constant public static final androidx.compose.material3.adaptive.ThreePaneScaffoldRole Tertiary;
+ }
+
+ @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class WindowAdaptiveInfo {
+ ctor public WindowAdaptiveInfo(androidx.compose.material3.windowsizeclass.WindowSizeClass windowSizeClass, androidx.compose.material3.adaptive.Posture posture);
+ method public androidx.compose.material3.adaptive.Posture getPosture();
+ method public androidx.compose.material3.windowsizeclass.WindowSizeClass getWindowSizeClass();
+ property public final androidx.compose.material3.adaptive.Posture posture;
+ property public final androidx.compose.material3.windowsizeclass.WindowSizeClass windowSizeClass;
+ }
+
}
diff --git a/compose/material3/material3-adaptive/api/restricted_current.txt b/compose/material3/material3-adaptive/api/restricted_current.txt
index 8ae70d9..0b43e4a 100644
--- a/compose/material3/material3-adaptive/api/restricted_current.txt
+++ b/compose/material3/material3-adaptive/api/restricted_current.txt
@@ -1,8 +1,85 @@
// Signature format: 4.0
package androidx.compose.material3.adaptive {
+ public final class AdaptiveLayoutDirective {
+ ctor public AdaptiveLayoutDirective(int maxHorizontalPartitions, androidx.compose.material3.adaptive.GutterSizes gutterSizes, optional int maxVerticalPartitions);
+ method public androidx.compose.material3.adaptive.GutterSizes getGutterSizes();
+ method public int getMaxHorizontalPartitions();
+ method public int getMaxVerticalPartitions();
+ property public final androidx.compose.material3.adaptive.GutterSizes gutterSizes;
+ property public final int maxHorizontalPartitions;
+ property public final int maxVerticalPartitions;
+ }
+
+ public final class AdaptiveLayoutDirectiveKt {
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.AdaptiveLayoutDirective calculateDenseAdaptiveLayoutDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo);
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.AdaptiveLayoutDirective calculateStandardAdaptiveLayoutDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo);
+ }
+
+ public final class AndroidPosture_androidKt {
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.Posture calculatePosture(java.util.List<? extends androidx.window.layout.FoldingFeature> foldingFeatures);
+ }
+
+ public final class AndroidWindowInfo_androidKt {
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.WindowAdaptiveInfo calculateWindowAdaptiveInfo(optional @UiContext android.content.Context context);
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.util.List<androidx.window.layout.FoldingFeature>> foldingFeaturesAsState(optional @UiContext android.content.Context context);
+ method @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<androidx.compose.ui.unit.IntSize> windowSizeAsState(optional @UiContext android.content.Context context);
+ }
+
@kotlin.RequiresOptIn(message="This material3-adaptive API is experimental and is likely to change or to be" + "removed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3AdaptiveApi {
}
+ public final class GutterSizes {
+ ctor public GutterSizes(float outerVertical, float innerVertical, optional float outerHorizontal, optional float innerHorizontal);
+ method public float getInnerHorizontal();
+ method public float getInnerVertical();
+ method public float getOuterHorizontal();
+ method public float getOuterVertical();
+ property public final float innerHorizontal;
+ property public final float innerVertical;
+ property public final float outerHorizontal;
+ property public final float outerVertical;
+ }
+
+ @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface PaneScaffoldScope {
+ method public androidx.compose.ui.Modifier preferredWidth(androidx.compose.ui.Modifier, float width);
+ }
+
+ @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class Posture {
+ ctor public Posture(optional boolean hasVerticalHinge, optional boolean isTabletop, optional boolean hasSeparatingHinge);
+ method public boolean getHasSeparatingHinge();
+ method public boolean getHasVerticalHinge();
+ method public boolean isTabletop();
+ property public final boolean hasSeparatingHinge;
+ property public final boolean hasVerticalHinge;
+ property public final boolean isTabletop;
+ }
+
+ @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public final class ThreePaneScaffoldArrangement {
+ ctor public ThreePaneScaffoldArrangement(androidx.compose.material3.adaptive.ThreePaneScaffoldRole firstPane, androidx.compose.material3.adaptive.ThreePaneScaffoldRole secondPane, androidx.compose.material3.adaptive.ThreePaneScaffoldRole thirdPane);
+ method public androidx.compose.material3.adaptive.ThreePaneScaffoldRole getFirstPane();
+ method public androidx.compose.material3.adaptive.ThreePaneScaffoldRole getSecondPane();
+ method public androidx.compose.material3.adaptive.ThreePaneScaffoldRole getThirdPane();
+ property public final androidx.compose.material3.adaptive.ThreePaneScaffoldRole firstPane;
+ property public final androidx.compose.material3.adaptive.ThreePaneScaffoldRole secondPane;
+ property public final androidx.compose.material3.adaptive.ThreePaneScaffoldRole thirdPane;
+ }
+
+ @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum ThreePaneScaffoldRole {
+ method public static androidx.compose.material3.adaptive.ThreePaneScaffoldRole valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.adaptive.ThreePaneScaffoldRole[] values();
+ enum_constant public static final androidx.compose.material3.adaptive.ThreePaneScaffoldRole Primary;
+ enum_constant public static final androidx.compose.material3.adaptive.ThreePaneScaffoldRole Secondary;
+ enum_constant public static final androidx.compose.material3.adaptive.ThreePaneScaffoldRole Tertiary;
+ }
+
+ @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class WindowAdaptiveInfo {
+ ctor public WindowAdaptiveInfo(androidx.compose.material3.windowsizeclass.WindowSizeClass windowSizeClass, androidx.compose.material3.adaptive.Posture posture);
+ method public androidx.compose.material3.adaptive.Posture getPosture();
+ method public androidx.compose.material3.windowsizeclass.WindowSizeClass getWindowSizeClass();
+ property public final androidx.compose.material3.adaptive.Posture posture;
+ property public final androidx.compose.material3.windowsizeclass.WindowSizeClass windowSizeClass;
+ }
+
}
diff --git a/compose/material3/material3-adaptive/build.gradle b/compose/material3/material3-adaptive/build.gradle
index 57252de..c7aaf75 100644
--- a/compose/material3/material3-adaptive/build.gradle
+++ b/compose/material3/material3-adaptive/build.gradle
@@ -36,7 +36,9 @@
dependencies {
implementation(libs.kotlinStdlibCommon)
api(project(":compose:foundation:foundation"))
+ implementation(project(":compose:foundation:foundation-layout"))
implementation(project(":compose:material3:material3"))
+ implementation(project(":compose:material3:material3-window-size-class"))
}
}
@@ -56,6 +58,8 @@
dependsOn(jvmMain)
dependencies {
api("androidx.annotation:annotation:1.1.0")
+ implementation(project(":lifecycle:lifecycle-runtime-compose"))
+ implementation(project(":window:window"))
}
}
@@ -78,8 +82,16 @@
}
}
- androidTest {
+ androidAndroidTest {
dependsOn(jvmTest)
+ dependsOn(androidMain)
+ dependencies {
+ implementation(project(":compose:test-utils"))
+ implementation(project(":window:window-testing"))
+ implementation(libs.junit)
+ implementation(libs.testRunner)
+ implementation(libs.truth)
+ }
}
}
}
diff --git a/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/CalculatePostureTest.kt b/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/CalculatePostureTest.kt
new file mode 100644
index 0000000..63a9792
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/CalculatePostureTest.kt
@@ -0,0 +1,172 @@
+/*
+ * 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 android.graphics.Rect
+import androidx.window.layout.FoldingFeature
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+@RunWith(JUnit4::class)
+class CalculatePostureTest {
+ @Test
+ fun test_calculatePosture_hasOneVerticalHinge() {
+ val posture = calculatePosture(
+ listOf(
+ MockFoldingFeature(orientation = FoldingFeature.Orientation.HORIZONTAL),
+ MockFoldingFeature(orientation = FoldingFeature.Orientation.VERTICAL),
+ MockFoldingFeature(orientation = FoldingFeature.Orientation.HORIZONTAL)
+ )
+ )
+
+ assertThat(posture.hasVerticalHinge).isTrue()
+ }
+
+ @Test
+ fun test_calculatePosture_hasNoVerticalHinge() {
+ val posture = calculatePosture(
+ listOf(
+ MockFoldingFeature(orientation = FoldingFeature.Orientation.HORIZONTAL),
+ MockFoldingFeature(orientation = FoldingFeature.Orientation.HORIZONTAL)
+ )
+ )
+
+ assertThat(posture.hasVerticalHinge).isFalse()
+ }
+
+ @Test
+ fun test_calculatePosture_hasMultipleVerticalHinge() {
+ val posture = calculatePosture(
+ listOf(
+ MockFoldingFeature(orientation = FoldingFeature.Orientation.HORIZONTAL),
+ MockFoldingFeature(orientation = FoldingFeature.Orientation.VERTICAL),
+ MockFoldingFeature(orientation = FoldingFeature.Orientation.VERTICAL),
+ )
+ )
+
+ assertThat(posture.hasVerticalHinge).isTrue()
+ }
+
+ @Test
+ fun test_calculatePosture_hasOneSeparatingHinge() {
+ val posture = calculatePosture(
+ listOf(
+ MockFoldingFeature(isSeparating = true),
+ MockFoldingFeature(isSeparating = false),
+ MockFoldingFeature(isSeparating = false),
+ )
+ )
+
+ assertThat(posture.hasSeparatingHinge).isTrue()
+ }
+
+ @Test
+ fun test_calculatePosture_hasNoSeparatingHinge() {
+ val posture = calculatePosture(
+ listOf(
+ MockFoldingFeature(isSeparating = false),
+ MockFoldingFeature(isSeparating = false),
+ )
+ )
+
+ assertThat(posture.hasSeparatingHinge).isFalse()
+ }
+
+ @Test
+ fun test_calculatePosture_hasMultipleSeparatingHinge() {
+ val posture = calculatePosture(
+ listOf(
+ MockFoldingFeature(isSeparating = true),
+ MockFoldingFeature(isSeparating = false),
+ MockFoldingFeature(isSeparating = true),
+ )
+ )
+
+ assertThat(posture.hasSeparatingHinge).isTrue()
+ }
+
+ @Test
+ fun test_calculatePosture_isTableTop_noSeparating() {
+ val posture = calculatePosture(
+ listOf(
+ MockFoldingFeature(
+ isSeparating = false,
+ orientation = FoldingFeature.Orientation.HORIZONTAL,
+ state = FoldingFeature.State.HALF_OPENED
+ ),
+ )
+ )
+
+ assertThat(posture.isTabletop).isTrue()
+ }
+
+ @Test
+ fun test_calculatePosture_isTableTop_separating() {
+ val posture = calculatePosture(
+ listOf(
+ MockFoldingFeature(
+ isSeparating = true,
+ orientation = FoldingFeature.Orientation.HORIZONTAL,
+ state = FoldingFeature.State.HALF_OPENED
+ ),
+ )
+ )
+
+ assertThat(posture.isTabletop).isTrue()
+ }
+
+ @Test
+ fun test_calculatePosture_isNotTableTop_verticalHinge() {
+ val posture = calculatePosture(
+ listOf(
+ MockFoldingFeature(
+ isSeparating = false,
+ orientation = FoldingFeature.Orientation.VERTICAL,
+ state = FoldingFeature.State.HALF_OPENED
+ ),
+ )
+ )
+
+ assertThat(posture.isTabletop).isFalse()
+ }
+
+ @Test
+ fun test_calculatePosture_isNotTableTop_flat() {
+ val posture = calculatePosture(
+ listOf(
+ MockFoldingFeature(
+ isSeparating = false,
+ orientation = FoldingFeature.Orientation.HORIZONTAL,
+ state = FoldingFeature.State.FLAT
+ ),
+ )
+ )
+
+ assertThat(posture.isTabletop).isFalse()
+ }
+}
+
+internal class MockFoldingFeature(
+ override val isSeparating: Boolean = false,
+ override val occlusionType: FoldingFeature.OcclusionType = FoldingFeature.OcclusionType.NONE,
+ override val orientation: FoldingFeature.Orientation = FoldingFeature.Orientation.VERTICAL,
+ override val state: FoldingFeature.State = FoldingFeature.State.FLAT,
+ override val bounds: Rect = Rect(0, 0, 1, 1)
+) : FoldingFeature
diff --git a/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/CalculateWindowAdaptiveInfoTest.kt b/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/CalculateWindowAdaptiveInfoTest.kt
new file mode 100644
index 0000000..db9c2a3
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/CalculateWindowAdaptiveInfoTest.kt
@@ -0,0 +1,119 @@
+/*
+ * 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 android.content.res.Configuration
+import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
+import androidx.compose.material3.windowsizeclass.WindowSizeClass
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.toSize
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.window.layout.FoldingFeature
+import androidx.window.layout.WindowLayoutInfo
+import androidx.window.layout.WindowMetricsCalculator
+import androidx.window.testing.layout.WindowLayoutInfoPublisherRule
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CalculateWindowAdaptiveInfoTest {
+ private val composeRule = createComposeRule()
+ private val layoutInfoRule = WindowLayoutInfoPublisherRule()
+
+ @get:Rule
+ val testRule: TestRule
+ init {
+ testRule = RuleChain.outerRule(layoutInfoRule).around(composeRule)
+ }
+
+ @OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
+ @Test
+ fun test_calculateWindowAdaptiveInfo() {
+ lateinit var actualAdaptiveInfo: WindowAdaptiveInfo
+ val mockWindowSize = mutableStateOf(MockWindowSize1)
+ WindowMetricsCalculator.overrideDecorator(
+ MockWindowMetricsCalculatorDecorator(mockWindowSize)
+ )
+
+ composeRule.setContent {
+ val testConfiguration = Configuration(LocalConfiguration.current)
+ testConfiguration.screenWidthDp = mockWindowSize.value.width
+ testConfiguration.screenHeightDp = mockWindowSize.value.height
+ CompositionLocalProvider(
+ LocalDensity provides MockDensity,
+ LocalConfiguration provides testConfiguration
+ ) {
+ actualAdaptiveInfo = calculateWindowAdaptiveInfo()
+ }
+ }
+
+ layoutInfoRule.overrideWindowLayoutInfo(
+ WindowLayoutInfo(MockFoldingFeatures1)
+ )
+
+ composeRule.runOnIdle {
+ assertThat(actualAdaptiveInfo.windowSizeClass).isEqualTo(
+ WindowSizeClass.calculateFromSize(MockWindowSize1.toSize(), MockDensity))
+ assertThat(actualAdaptiveInfo.posture).isEqualTo(calculatePosture(MockFoldingFeatures1))
+ }
+
+ layoutInfoRule.overrideWindowLayoutInfo(
+ WindowLayoutInfo(MockFoldingFeatures2)
+ )
+ mockWindowSize.value = MockWindowSize2
+
+ composeRule.runOnIdle {
+ assertThat(actualAdaptiveInfo.windowSizeClass).isEqualTo(
+ WindowSizeClass.calculateFromSize(MockWindowSize2.toSize(), MockDensity))
+ assertThat(actualAdaptiveInfo.posture).isEqualTo(calculatePosture(MockFoldingFeatures2))
+ }
+ }
+
+ companion object {
+ private val MockFoldingFeatures1 = listOf(
+ MockFoldingFeature(orientation = FoldingFeature.Orientation.HORIZONTAL),
+ MockFoldingFeature(orientation = FoldingFeature.Orientation.VERTICAL),
+ MockFoldingFeature(orientation = FoldingFeature.Orientation.HORIZONTAL)
+ )
+
+ private val MockFoldingFeatures2 = listOf(
+ MockFoldingFeature(
+ isSeparating = false,
+ orientation = FoldingFeature.Orientation.HORIZONTAL,
+ state = FoldingFeature.State.FLAT
+ ),
+ )
+
+ private val MockWindowSize1 = IntSize(400, 800)
+ private val MockWindowSize2 = IntSize(800, 400)
+
+ private val MockDensity = Density(1f, 1f)
+ }
+}
\ No newline at end of file
diff --git a/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/FoldingFeaturesAsStateTest.kt b/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/FoldingFeaturesAsStateTest.kt
new file mode 100644
index 0000000..709ddf0
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/FoldingFeaturesAsStateTest.kt
@@ -0,0 +1,96 @@
+/*
+ * 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 android.graphics.Rect
+import androidx.compose.runtime.State
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.window.layout.DisplayFeature
+import androidx.window.layout.FoldingFeature
+import androidx.window.layout.WindowLayoutInfo
+import androidx.window.testing.layout.FoldingFeature
+import androidx.window.testing.layout.WindowLayoutInfoPublisherRule
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class FoldingFeaturesAsStateTest {
+ private val composeRule = createComposeRule()
+ private val publisherRule = WindowLayoutInfoPublisherRule()
+
+ @get:Rule
+ val testRule: TestRule
+ init {
+ testRule = RuleChain.outerRule(publisherRule).around(composeRule)
+ }
+
+ @Test
+ fun test_foldingFeatureAsState_returnEmptyListInitially() {
+ lateinit var actualFoldingFeatures: State<List<FoldingFeature>>
+
+ composeRule.setContent {
+ actualFoldingFeatures = foldingFeaturesAsState()
+ }
+
+ composeRule.runOnIdle {
+ assertThat(actualFoldingFeatures.value).isEmpty()
+ }
+ }
+
+ @Test
+ fun test_foldingFeatureAsState_returnCurrentFoldingFeatures() {
+ lateinit var actualFoldingFeatures: State<List<FoldingFeature>>
+
+ composeRule.setContent {
+ actualFoldingFeatures = foldingFeaturesAsState()
+ }
+
+ publisherRule.overrideWindowLayoutInfo(
+ WindowLayoutInfo(
+ listOf(MockFoldingFeature1, MockFoldingFeature2, MockDisplayFeature)
+ )
+ )
+
+ composeRule.runOnIdle {
+ assertThat(actualFoldingFeatures.value.size).isEqualTo(2)
+ assertThat(MockFoldingFeature1 in actualFoldingFeatures.value).isTrue()
+ assertThat(MockFoldingFeature2 in actualFoldingFeatures.value).isTrue()
+ }
+ }
+
+ companion object {
+ val MockFoldingFeature1 = FoldingFeature(
+ windowBounds = Rect(0, 0, 1024, 800),
+ size = 1
+ )
+ val MockFoldingFeature2 = FoldingFeature(
+ windowBounds = Rect(0, 0, 1024, 800),
+ size = 0
+ )
+ val MockDisplayFeature = object : DisplayFeature {
+ override val bounds = Rect(10, 10, 12, 12)
+ }
+ }
+}
diff --git a/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/WindowSizeAsStateTest.kt b/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/WindowSizeAsStateTest.kt
new file mode 100644
index 0000000..fed00fc
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/WindowSizeAsStateTest.kt
@@ -0,0 +1,108 @@
+/*
+ * 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 android.app.Activity
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Rect
+import androidx.annotation.UiContext
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.State
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.IntSize
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.window.layout.WindowMetrics
+import androidx.window.layout.WindowMetricsCalculator
+import androidx.window.layout.WindowMetricsCalculatorDecorator
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class WindowSizeAsStateTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun test_windowSizeAsState() {
+ lateinit var actualWindowSize: State<IntSize>
+
+ val mockWindowSize = mutableStateOf(MockWindowSize1)
+ WindowMetricsCalculator.overrideDecorator(
+ MockWindowMetricsCalculatorDecorator(mockWindowSize)
+ )
+
+ rule.setContent {
+ val testConfiguration = Configuration(LocalConfiguration.current)
+ testConfiguration.screenWidthDp = mockWindowSize.value.width
+ testConfiguration.screenHeightDp = mockWindowSize.value.height
+ CompositionLocalProvider(LocalConfiguration provides testConfiguration) {
+ actualWindowSize = windowSizeAsState()
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(actualWindowSize.value).isEqualTo(MockWindowSize1)
+ }
+
+ mockWindowSize.value = MockWindowSize2
+
+ rule.runOnIdle {
+ assertThat(actualWindowSize.value).isEqualTo(MockWindowSize2)
+ }
+ }
+
+ companion object {
+ val MockWindowSize1 = IntSize(1000, 600)
+ val MockWindowSize2 = IntSize(800, 400)
+ }
+}
+
+internal class MockWindowMetricsCalculatorDecorator(
+ private val mockWindowSize: State<IntSize>
+) : WindowMetricsCalculatorDecorator {
+ override fun decorate(calculator: WindowMetricsCalculator): WindowMetricsCalculator {
+ return MockWindowMetricsCalculator(mockWindowSize)
+ }
+}
+
+internal class MockWindowMetricsCalculator(
+ private val mockWindowSize: State<IntSize>
+) : WindowMetricsCalculator {
+ override fun computeCurrentWindowMetrics(activity: Activity): WindowMetrics {
+ return WindowMetrics(
+ Rect(0, 0, mockWindowSize.value.width, mockWindowSize.value.height)
+ )
+ }
+
+ override fun computeMaximumWindowMetrics(activity: Activity): WindowMetrics {
+ return computeCurrentWindowMetrics(activity)
+ }
+
+ override fun computeCurrentWindowMetrics(@UiContext context: Context): WindowMetrics {
+ return WindowMetrics(
+ Rect(0, 0, mockWindowSize.value.width, mockWindowSize.value.height)
+ )
+ }
+}
\ No newline at end of file
diff --git a/compose/material3/material3-adaptive/src/androidMain/AndroidManifest.xml b/compose/material3/material3-adaptive/src/androidMain/AndroidManifest.xml
new file mode 100644
index 0000000..3150d7d
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/androidMain/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?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/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/AndroidPosture.android.kt b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/AndroidPosture.android.kt
new file mode 100644
index 0000000..cad4404
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/AndroidPosture.android.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.compose.material3.adaptive
+
+import androidx.window.layout.FoldingFeature
+
+/**
+ * Calculates the [Posture] for a given list of [FoldingFeature]s. This methods converts framework
+ * folding info into the Material-opinionated posture info.
+ */
+@ExperimentalMaterial3AdaptiveApi
+fun calculatePosture(foldingFeatures: List<FoldingFeature>): Posture {
+ var hasVerticalHinge = false
+ var isTableTop = false
+ var hasSeparatingHinge = false
+ foldingFeatures.forEach {
+ if (it.orientation == FoldingFeature.Orientation.VERTICAL) {
+ hasVerticalHinge = true
+ }
+ if (it.isSeparating) {
+ hasSeparatingHinge = true
+ }
+ if (it.orientation == FoldingFeature.Orientation.HORIZONTAL &&
+ it.state == FoldingFeature.State.HALF_OPENED) {
+ isTableTop = true
+ }
+ }
+ return Posture(hasVerticalHinge, isTableTop, hasSeparatingHinge)
+}
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
new file mode 100644
index 0000000..786df6b
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/AndroidWindowInfo.android.kt
@@ -0,0 +1,114 @@
+/*
+ * 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 android.app.Activity
+import android.content.Context
+import androidx.annotation.UiContext
+import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
+import androidx.compose.material3.windowsizeclass.WindowSizeClass
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.toSize
+import androidx.window.layout.FoldingFeature
+import androidx.window.layout.WindowInfoTracker
+import androidx.window.layout.WindowMetricsCalculator
+import kotlinx.coroutines.flow.map
+
+/**
+ * Calculates and returns [WindowAdaptiveInfo] of the provided context. It's a convenient function
+ * that uses the Material default [WindowSizeClass.calculateFromSize] and [calculatePosture]
+ * functions to retrieve [WindowSizeClass] and [Posture].
+ *
+ * @param context Optional [UiContext] of the window, defaulted to [LocalContext]'s current value
+ * @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)
+ )
+}
+
+/**
+ * Collects the current window size from [WindowMetricsCalculator] in to a [State].
+ *
+ * @param context Optional [UiContext] of the window, defaulted to [LocalContext]'s current value.
+ * @return a [State] of [IntSize] that represents the current window size.
+ */
+@ExperimentalMaterial3AdaptiveApi
+@Composable
+fun windowSizeAsState(@UiContext context: Context = LocalContext.current): State<IntSize> {
+ val size = remember {
+ mutableStateOf(IntSize(0, 0))
+ }
+
+ // Observe view configuration changes and recalculate the size class on each change. We can't
+ // use Activity#onConfigurationChanged as this will sometimes fail to be called on different
+ // API levels, hence why this function needs to be @Composable so we can observe the
+ // ComposeView's configuration changes.
+ size.value = remember(context, LocalConfiguration.current) {
+ val windowBounds =
+ WindowMetricsCalculator
+ .getOrCreate()
+ .computeCurrentWindowMetrics(context)
+ .bounds
+ IntSize(windowBounds.width(), windowBounds.height())
+ }
+
+ return size
+}
+
+/**
+ * Collects the current window folding features from [WindowInfoTracker] in to a [State].
+ *
+ * @param context Optional [UiContext] of the window, defaulted to [LocalContext]'s current value.
+ * @return a [State] of a [FoldingFeature] list.
+ */
+@ExperimentalMaterial3AdaptiveApi
+@Composable
+fun foldingFeaturesAsState(
+ @UiContext context: Context = LocalContext.current
+): State<List<FoldingFeature>> {
+ return remember(context) {
+ if (context is Activity) {
+ // TODO(b/284347941) remove the instance check after the test bug is fixed.
+ WindowInfoTracker
+ .getOrCreate(context)
+ .windowLayoutInfo(context)
+ } else {
+ WindowInfoTracker
+ .getOrCreate(context)
+ .windowLayoutInfo(context)
+ }.map { it.displayFeatures.filterIsInstance<FoldingFeature>() }
+ }.collectAsState(emptyList())
+}
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirective.kt b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirective.kt
new file mode 100644
index 0000000..0b04975
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirective.kt
@@ -0,0 +1,214 @@
+/*
+ * 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.WindowWidthSizeClass
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+
+/**
+ * Calculates the standard [AdaptiveLayoutDirective] from a given [WindowAdaptiveInfo]. Use this
+ * method with [calculateWindowAdaptiveInfo] to acquire Material-recommended adaptive layout
+ * settings of the current activity window.
+ *
+ * See more details on the [Material design guideline site]
+ * (https://m3.material.io/foundations/layout/applying-layout/window-size-classes).
+ *
+ * @param windowAdaptiveInfo [WindowAdaptiveInfo] that collects useful information in making
+ * layout adaptation decisions like [WindowSizeClass].
+ * @return an [AdaptiveLayoutDirective] to be used to decide adaptive layout states.
+ */
+// TODO(b/285144647): Add more details regarding the use scenarios of this function.
+@ExperimentalMaterial3AdaptiveApi
+fun calculateStandardAdaptiveLayoutDirective(
+ windowAdaptiveInfo: WindowAdaptiveInfo
+): AdaptiveLayoutDirective {
+ val maxHorizontalPartitions: Int
+ val gutterOuterVertical: Dp
+ val gutterInnerVertical: Dp
+ when (windowAdaptiveInfo.windowSizeClass.widthSizeClass) {
+ WindowWidthSizeClass.Compact -> {
+ maxHorizontalPartitions = 1
+ gutterOuterVertical = 16.dp
+ gutterInnerVertical = 0.dp
+ }
+ WindowWidthSizeClass.Medium -> {
+ maxHorizontalPartitions = 1
+ gutterOuterVertical = 24.dp
+ gutterInnerVertical = 0.dp
+ }
+ else -> {
+ maxHorizontalPartitions = 2
+ gutterOuterVertical = 24.dp
+ gutterInnerVertical = 24.dp
+ }
+ }
+ val maxVerticalPartitions: Int
+ val gutterInnerHorizontal: Dp
+
+ // TODO(conradchen): Confirm the table top mode settings
+ if (windowAdaptiveInfo.posture.isTabletop) {
+ maxVerticalPartitions = 2
+ gutterInnerHorizontal = 24.dp
+ } else {
+ maxVerticalPartitions = 1
+ gutterInnerHorizontal = 0.dp
+ }
+
+ return AdaptiveLayoutDirective(
+ maxHorizontalPartitions,
+ GutterSizes(
+ gutterOuterVertical, gutterInnerVertical, innerHorizontal = gutterInnerHorizontal
+ ),
+ maxVerticalPartitions
+ )
+}
+
+/**
+ * Calculates the dense-mode [AdaptiveLayoutDirective] from a given [WindowAdaptiveInfo]. Use this
+ * method with [calculateWindowAdaptiveInfo] to acquire Material-recommended dense-mode adaptive
+ * layout settings of the current activity window.
+ *
+ * See more details on the [Material design guideline site]
+ * (https://m3.material.io/foundations/layout/applying-layout/window-size-classes).
+ *
+ * @param windowAdaptiveInfo [WindowAdaptiveInfo] that collects useful information in making
+ * layout adaptation decisions like [WindowSizeClass].
+ * @return an [AdaptiveLayoutDirective] to be used to decide adaptive layout states.
+ */
+// TODO(b/285144647): Add more details regarding the use scenarios of this function.
+@ExperimentalMaterial3AdaptiveApi
+fun calculateDenseAdaptiveLayoutDirective(
+ windowAdaptiveInfo: WindowAdaptiveInfo
+): AdaptiveLayoutDirective {
+ val maxHorizontalPartitions: Int
+ val gutterOuterVertical: Dp
+ val gutterInnerVertical: Dp
+ when (windowAdaptiveInfo.windowSizeClass.widthSizeClass) {
+ WindowWidthSizeClass.Compact -> {
+ maxHorizontalPartitions = 1
+ gutterOuterVertical = 16.dp
+ gutterInnerVertical = 0.dp
+ }
+ WindowWidthSizeClass.Medium -> {
+ // TODO(conradchen): Confirm the outer gutter size
+ maxHorizontalPartitions = 2
+ gutterOuterVertical = 24.dp
+ gutterInnerVertical = 24.dp
+ }
+ else -> {
+ maxHorizontalPartitions = 2
+ gutterOuterVertical = 24.dp
+ gutterInnerVertical = 24.dp
+ }
+ }
+ val maxVerticalPartitions: Int
+ val gutterInnerHorizontal: Dp
+
+ if (windowAdaptiveInfo.posture.isTabletop) {
+ maxVerticalPartitions = 2
+ gutterInnerHorizontal = 24.dp
+ } else {
+ maxVerticalPartitions = 1
+ gutterInnerHorizontal = 0.dp
+ }
+
+ return AdaptiveLayoutDirective(
+ maxHorizontalPartitions,
+ GutterSizes(
+ gutterOuterVertical, gutterInnerVertical, innerHorizontal = gutterInnerHorizontal
+ ),
+ maxVerticalPartitions
+ )
+}
+
+/**
+ * Top-level directives about how an adaptive layout should be arranged and spaced, like how many
+ * partitions the layout can be split into and what should be the gutter size.
+ */
+class AdaptiveLayoutDirective(
+ /** How many partitions along the horizontal axis the respective layout can be split into. */
+ val maxHorizontalPartitions: Int,
+ /** The gutter size of the respective layout should preserve. */
+ val gutterSizes: GutterSizes,
+ /**
+ * How many partitions along the vertical axis the respective layout can be split into.
+ * The default value is 1.
+ */
+ val maxVerticalPartitions: Int = 1
+) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is AdaptiveLayoutDirective) return false
+ if (maxHorizontalPartitions != other.maxHorizontalPartitions) return false
+ if (gutterSizes != other.gutterSizes) return false
+ if (maxVerticalPartitions != other.maxVerticalPartitions) return false
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = maxHorizontalPartitions
+ result = 31 * result + gutterSizes.hashCode()
+ result = 31 * result + maxVerticalPartitions
+ return result
+ }
+}
+
+/**
+ * Denotes the gutter sizes of an adaptive layout. Gutters of an adaptive layouts include margins
+ * between panes ([innerVertical] and [innerHorizontal]) and paddings of the layout itself
+ * ([outerVertical] and [outerHorizontal]). Usually we will expect larger gutter sizes to be set
+ * when the layout is larger and more panes are shown in the layout.
+ */
+class GutterSizes(
+ /**
+ * Size of the outer vertical gutters. It's similar to left/right paddings of a normal layout.
+ */
+ val outerVertical: Dp,
+ /**
+ * Size of the inner vertical gutters. It's similar to left/right margins of the layout's
+ * children.
+ */
+ val innerVertical: Dp,
+ /**
+ * Size of the outer horizontal gutters. It's similar to top/bottom paddings of a normal layout.
+ */
+ val outerHorizontal: Dp = outerVertical,
+ /**
+ * Size of the inner horizontal gutters. It's similar to top/bottom margins of the layout's
+ * children.
+ */
+ val innerHorizontal: Dp = innerVertical
+) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is GutterSizes) return false
+ if (outerVertical != other.outerVertical) return false
+ if (innerVertical != other.innerVertical) return false
+ if (outerHorizontal != other.outerHorizontal) return false
+ if (innerHorizontal != other.innerHorizontal) return false
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = outerVertical.hashCode()
+ result = 31 * result + innerVertical.hashCode()
+ result = 31 * result + outerHorizontal.hashCode()
+ result = 31 * result + innerHorizontal.hashCode()
+ return result
+ }
+}
\ No newline at end of file
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
index 002f5f5..967aacf 100644
--- 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
@@ -21,6 +21,7 @@
import androidx.compose.material3.Surface
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.Layout
@@ -28,9 +29,9 @@
/**
* The Navigation Suite wraps the provided content and places the adequate provided navigation
- * component on the screen according to the current NavigationLayoutType.
+ * component on the screen according to the current [NavigationLayoutType].
*
- * TODO: Add the navigationLayoutType param
+ * @param navigationLayoutType the current [NavigationLayoutType]
* @param modifier the [Modifier] to be applied to the navigation suite
* @param navigationComponent the navigation component to be displayed
* @param containerColor the color used for the background of the navigation suite. Use
@@ -45,6 +46,7 @@
@ExperimentalMaterial3AdaptiveApi
@Composable
internal fun NavigationSuite(
+ navigationLayoutType: NavigationLayoutType,
modifier: Modifier = Modifier,
navigationComponent: @Composable () -> Unit,
containerColor: Color = MaterialTheme.colorScheme.background,
@@ -53,6 +55,7 @@
) {
Surface(modifier = modifier, color = containerColor, contentColor = contentColor) {
NavigationSuiteLayout(
+ navigationLayoutType = navigationLayoutType,
navigationComponent = navigationComponent,
content = content
)
@@ -62,13 +65,14 @@
/**
* Layout for a [NavigationSuite]'s content.
*
- * TODO: Add the navigationLayoutType param.
+ * @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 = {}
) {
@@ -77,14 +81,158 @@
Box(modifier = Modifier.layoutId("navigation")) { navigationComponent() }
Box(modifier = Modifier.layoutId("content")) { content() }
}
- ) { _, constraints ->
+ ) { 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) {
- // TODO: Add the placement logic based on the NavigationLayoutType.
+ 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].
+ }
+ }
}
}
}
-/* TODO: Add NavigationLayoutType class and NavigationSuiteFeature. */
\ No newline at end of file
+/**
+ * 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
+ * [androidx.compose.material3.NavigationBar] and properly place it on the screen.
+ *
+ * @see androidx.compose.material3.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
+ * [androidx.compose.material3.NavigationRail] and properly place it on the screen.
+ *
+ * @see androidx.compose.material3.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
+ * [androidx.compose.material3.PermanentDrawerSheet] and properly place it on the screen.
+ *
+ * @see androidx.compose.material3.PermanentDrawerSheet
+ */
+ @JvmField
+ val NavigationDrawer =
+ NavigationLayoutType(
+ description = "NavigationDrawer",
+ alignment = Alignment.TopStart,
+ orientation = NavigationSuiteFeature.Orientation.Vertical,
+ )
+ }
+}
\ No newline at end of file
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/PaneScaffold.kt b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/PaneScaffold.kt
new file mode 100644
index 0000000..94f7ce2
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/PaneScaffold.kt
@@ -0,0 +1,88 @@
+/*
+ * 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.ui.Modifier
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.ParentDataModifierNode
+import androidx.compose.ui.platform.InspectorInfo
+import androidx.compose.ui.platform.debugInspectorInfo
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+
+/**
+ * Scope for the panes of pane scaffolds.
+ */
+@ExperimentalMaterial3AdaptiveApi
+interface PaneScaffoldScope {
+ /**
+ * Specify the preferred width of the pane. The relevant pane scaffold implementations are
+ * supposed to respect the preferred width of a pane whenever it's possible.
+ */
+ fun Modifier.preferredWidth(width: Dp): Modifier
+}
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+private object PaneScaffoldScopeInstance : PaneScaffoldScope {
+ override fun Modifier.preferredWidth(width: Dp): Modifier {
+ require(width == Dp.Unspecified || width > 0.dp)
+ return this.then(PreferredWidthElement(width))
+ }
+}
+
+private class PreferredWidthElement(
+ private val width: Dp,
+) : ModifierNodeElement<PreferredWidthNode>() {
+ private val inspectorInfo = debugInspectorInfo {
+ name = "preferredWidth"
+ value = width
+ }
+
+ override fun create(): PreferredWidthNode {
+ return PreferredWidthNode(width)
+ }
+
+ override fun update(node: PreferredWidthNode) {
+ node.width = width
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
+ inspectorInfo()
+ }
+
+ override fun hashCode(): Int {
+ return width.hashCode()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ val otherModifier = other as? PreferredWidthElement ?: return false
+ return width == otherModifier.width
+ }
+}
+
+private class PreferredWidthNode(var width: Dp) : ParentDataModifierNode, Modifier.Node() {
+ override fun Density.modifyParentData(parentData: Any?) =
+ ((parentData as? PaneScaffoldParentData) ?: PaneScaffoldParentData()).also {
+ it.preferredWidth = with(this) { width.toPx() }
+ }
+}
+
+private data class PaneScaffoldParentData(
+ var preferredWidth: Float = Float.NaN,
+)
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/Posture.kt b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/Posture.kt
new file mode 100644
index 0000000..da4686c
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/Posture.kt
@@ -0,0 +1,67 @@
+/*
+ * 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
+
+/**
+ * Posture info that can help make layout adaptation decisions. For example when
+ * [Posture.hasSeparatingHinge] is `true`, the layout may want to avoid putting any content over
+ * the hinge area. We suggest to use [calculatePosture] to retrieve instances of this class in
+ * applications, unless you have a strong need of customization that cannot be fulfilled by the
+ * default implementation.
+ */
+@ExperimentalMaterial3AdaptiveApi
+class Posture(
+ /**
+ * `true` if at least one vertical hinge is present in the middle of the current window. When
+ * this is `true`, it means the current window is separated into multiple partitions along the
+ * horizontal axis and developers may consider separating the layout into multiple partitions
+ * accordingly.
+ */
+ val hasVerticalHinge: Boolean = false,
+
+ /**
+ * `true` if the current window is considered as in the table top mode, i.e. there is
+ * one half-opened horizontal hinge in the middle of the current window. When this is `true` it
+ * usually means it's hard for users to interact with the window area around the hinge and
+ * developers may consider separating the layout along the hinge and show software keyboard or
+ * other controls in the bottom half of the window.
+ */
+ val isTabletop: Boolean = false,
+
+ /**
+ * `true` if at least one hinge present in the current window is separating, i.e., content
+ * cannot be displayed on the hinge area. When this is `true` developer may want to avoid
+ * showing anything around the hinge area because the content will be cut or not visible.
+ */
+ val hasSeparatingHinge: Boolean = false
+) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is Posture) return false
+ if (hasVerticalHinge != other.hasVerticalHinge) return false
+ if (isTabletop != other.isTabletop) return false
+ if (hasSeparatingHinge != other.hasSeparatingHinge) return false
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = hasVerticalHinge.hashCode()
+ result = 31 * result + isTabletop.hashCode()
+ result = 31 * result + hasSeparatingHinge.hashCode()
+ return result
+ }
+}
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffoldArrangement.kt b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffoldArrangement.kt
new file mode 100644
index 0000000..de525a5
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffoldArrangement.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.compose.material3.adaptive
+
+import androidx.compose.runtime.Immutable
+
+/**
+ * Represents the pane order of [ThreePaneScaffold] from start to end. Note that the values of
+ * [firstPane], [secondPane] and [thirdPane] have to be different, otherwise
+ * [IllegalArgumentException] will be thrown.
+ */
+@ExperimentalMaterial3AdaptiveApi
+@Immutable
+class ThreePaneScaffoldArrangement(
+ /** The first pane from the start of the [ThreePaneScaffold]. */
+ val firstPane: ThreePaneScaffoldRole,
+ /** The second pane from the start of the [ThreePaneScaffold]. */
+ val secondPane: ThreePaneScaffoldRole,
+ /** The third pane from the start of the [ThreePaneScaffold]. */
+ val thirdPane: ThreePaneScaffoldRole
+) {
+ init {
+ require(firstPane != secondPane && secondPane != thirdPane && firstPane != thirdPane) {
+ "invalid ThreePaneScaffoldArrangement($firstPane, $secondPane, $thirdPane)" +
+ " - panes must be unique"
+ }
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is ThreePaneScaffoldArrangement) return false
+ if (firstPane != other.firstPane) return false
+ if (secondPane != other.secondPane) return false
+ if (thirdPane != other.thirdPane) return false
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = firstPane.hashCode()
+ result = 31 * result + secondPane.hashCode()
+ result = 31 * result + thirdPane.hashCode()
+ return result
+ }
+}
+
+/**
+ * The set of the available pane roles of [ThreePaneScaffold].
+ */
+@ExperimentalMaterial3AdaptiveApi
+enum class ThreePaneScaffoldRole {
+ /**
+ * The primary pane of [ThreePaneScaffold]. It is supposed to have the highest priority during
+ * layout adaptation and usually contains the most important content of the screen, like content
+ * details in a list-detail settings.
+ */
+ Primary,
+ /**
+ * The secondary pane of [ThreePaneScaffold]. It is supposed to have the second highest priority
+ * during layout adaptation and usually contains the supplement content of the screen, like
+ * content list in a list-detail settings.
+ */
+ Secondary,
+ /**
+ * The tertiary pane of [ThreePaneScaffold]. It is supposed to have the lowest priority during
+ * layout adaptation and usually contains the additional info which will only be shown under
+ * user interaction.
+ */
+ Tertiary
+}
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/WindowAdaptiveInfo.kt b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/WindowAdaptiveInfo.kt
new file mode 100644
index 0000000..a5bdcf0
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/WindowAdaptiveInfo.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.WindowSizeClass
+
+/**
+ * This class collects window info that affects adaptation decisions. An adaptive layout is supposed
+ * to use the info from this class to decide how the layout is supposed to be adapted.
+ */
+@ExperimentalMaterial3AdaptiveApi
+class WindowAdaptiveInfo(
+ /** [WindowSizeClass] of the current window. */
+ val windowSizeClass: WindowSizeClass,
+ /** [Posture] of the current window. */
+ val posture: Posture
+) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is WindowAdaptiveInfo) return false
+ if (windowSizeClass != other.windowSizeClass) return false
+ if (posture != other.posture) return false
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = windowSizeClass.hashCode()
+ result = 31 * result + posture.hashCode()
+ return result
+ }
+}
diff --git a/compose/material3/material3-adaptive/src/test/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirectiveTest.kt b/compose/material3/material3-adaptive/src/test/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirectiveTest.kt
new file mode 100644
index 0000000..6ae0180
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/test/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirectiveTest.kt
@@ -0,0 +1,166 @@
+/*
+ * 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
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class, ExperimentalMaterial3WindowSizeClassApi::class)
+@RunWith(JUnit4::class)
+class AdaptiveLayoutDirectiveTest {
+ @Test
+ fun test_calculateStandardAdaptiveLayoutDirective_compactWidth() {
+ val layoutDirective = calculateStandardAdaptiveLayoutDirective(
+ WindowAdaptiveInfo(
+ WindowSizeClass.calculateFromSize(DpSize(400.dp, 800.dp)),
+ Posture()
+ )
+ )
+
+ assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(1)
+ assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
+ assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(16.dp)
+ assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
+ assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(16.dp)
+ assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+ }
+
+ @Test
+ fun test_calculateStandardAdaptiveLayoutDirective_mediumWidth() {
+ val layoutDirective = calculateStandardAdaptiveLayoutDirective(
+ WindowAdaptiveInfo(
+ WindowSizeClass.calculateFromSize(DpSize(750.dp, 900.dp)),
+ Posture()
+ )
+ )
+
+ assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(1)
+ assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
+ assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
+ assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+ }
+
+ @Test
+ fun test_calculateStandardAdaptiveLayoutDirective_expandedWidth() {
+ val layoutDirective = calculateStandardAdaptiveLayoutDirective(
+ WindowAdaptiveInfo(
+ WindowSizeClass.calculateFromSize(DpSize(1200.dp, 800.dp)),
+ Posture()
+ )
+ )
+
+ assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(2)
+ assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
+ assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+ }
+
+ @Test
+ fun test_calculateStandardAdaptiveLayoutDirective_tabletop() {
+ val layoutDirective = calculateStandardAdaptiveLayoutDirective(
+ WindowAdaptiveInfo(
+ WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
+ Posture(isTabletop = true)
+ )
+ )
+
+ assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(1)
+ assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(2)
+ assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
+ assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(24.dp)
+ }
+
+ @Test
+ fun test_calculateDenseAdaptiveLayoutDirective_compactWidth() {
+ val layoutDirective = calculateDenseAdaptiveLayoutDirective(
+ WindowAdaptiveInfo(
+ WindowSizeClass.calculateFromSize(DpSize(400.dp, 800.dp)),
+ Posture()
+ )
+ )
+
+ assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(1)
+ assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
+ assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(16.dp)
+ assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
+ assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(16.dp)
+ assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+ }
+
+ @Test
+ fun test_calculateDenseAdaptiveLayoutDirective_mediumWidth() {
+ val layoutDirective = calculateDenseAdaptiveLayoutDirective(
+ WindowAdaptiveInfo(
+ WindowSizeClass.calculateFromSize(DpSize(750.dp, 900.dp)),
+ Posture()
+ )
+ )
+
+ assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(2)
+ assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
+ assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+ }
+
+ @Test
+ fun test_calculateDenseAdaptiveLayoutDirective_expandedWidth() {
+ val layoutDirective = calculateDenseAdaptiveLayoutDirective(
+ WindowAdaptiveInfo(
+ WindowSizeClass.calculateFromSize(DpSize(1200.dp, 800.dp)),
+ Posture()
+ )
+ )
+
+ assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(2)
+ assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
+ assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+ }
+
+ @Test
+ fun test_calculateDenseAdaptiveLayoutDirective_tabletop() {
+ val layoutDirective = calculateDenseAdaptiveLayoutDirective(
+ WindowAdaptiveInfo(
+ WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
+ Posture(isTabletop = true)
+ )
+ )
+
+ assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(2)
+ assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(2)
+ assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+ assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(24.dp)
+ }
+}
diff --git a/compose/material3/material3-window-size-class/api/current.txt b/compose/material3/material3-window-size-class/api/current.txt
index 88ceafc..ab5ca42 100644
--- a/compose/material3/material3-window-size-class/api/current.txt
+++ b/compose/material3/material3-window-size-class/api/current.txt
@@ -32,6 +32,7 @@
public static final class WindowSizeClass.Companion {
method @androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi @org.jetbrains.annotations.TestOnly public androidx.compose.material3.windowsizeclass.WindowSizeClass calculateFromSize(long size);
+ method @androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi public androidx.compose.material3.windowsizeclass.WindowSizeClass calculateFromSize(long size, androidx.compose.ui.unit.Density density, optional java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> supportedWidthSizeClasses, optional java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> supportedHeightSizeClasses);
}
@androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> {
diff --git a/compose/material3/material3-window-size-class/api/restricted_current.txt b/compose/material3/material3-window-size-class/api/restricted_current.txt
index 88ceafc..ab5ca42 100644
--- a/compose/material3/material3-window-size-class/api/restricted_current.txt
+++ b/compose/material3/material3-window-size-class/api/restricted_current.txt
@@ -32,6 +32,7 @@
public static final class WindowSizeClass.Companion {
method @androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi @org.jetbrains.annotations.TestOnly public androidx.compose.material3.windowsizeclass.WindowSizeClass calculateFromSize(long size);
+ method @androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi public androidx.compose.material3.windowsizeclass.WindowSizeClass calculateFromSize(long size, androidx.compose.ui.unit.Density density, optional java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> supportedWidthSizeClasses, optional java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> supportedHeightSizeClasses);
}
@androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> {
diff --git a/compose/material3/material3-window-size-class/src/commonMain/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClass.kt b/compose/material3/material3-window-size-class/src/commonMain/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClass.kt
index c663e94..dd1c8eb 100644
--- a/compose/material3/material3-window-size-class/src/commonMain/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClass.kt
+++ b/compose/material3/material3-window-size-class/src/commonMain/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClass.kt
@@ -17,6 +17,8 @@
package androidx.compose.material3.windowsizeclass
import androidx.compose.runtime.Immutable
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
@@ -55,6 +57,32 @@
val windowHeightSizeClass = WindowHeightSizeClass.fromHeight(size.height)
return WindowSizeClass(windowWidthSizeClass, windowHeightSizeClass)
}
+
+ /**
+ * Calculates the best matched [WindowSizeClass] for a given [size] and [Density] according
+ * to the provided [supportedWidthSizeClasses] and [supportedHeightSizeClasses].
+ *
+ * @param size of the window
+ * @param density of the window
+ * @param supportedWidthSizeClasses the set of width size classes that are supported
+ * @param supportedHeightSizeClasses the set of height size classes that are supported
+ * @return [WindowSizeClass] corresponding to the given width and height
+ */
+ @ExperimentalMaterial3WindowSizeClassApi
+ fun calculateFromSize(
+ size: Size,
+ density: Density,
+ supportedWidthSizeClasses: Set<WindowWidthSizeClass> =
+ WindowWidthSizeClass.DefaultSizeClasses,
+ supportedHeightSizeClasses: Set<WindowHeightSizeClass> =
+ WindowHeightSizeClass.DefaultSizeClasses
+ ): WindowSizeClass {
+ val windowWidthSizeClass =
+ WindowWidthSizeClass.fromWidth(size.width, density, supportedWidthSizeClasses)
+ val windowHeightSizeClass =
+ WindowHeightSizeClass.fromHeight(size.height, density, supportedHeightSizeClasses)
+ return WindowSizeClass(windowWidthSizeClass, windowHeightSizeClass)
+ }
}
override fun equals(other: Any?): Boolean {
@@ -92,7 +120,8 @@
value class WindowWidthSizeClass private constructor(private val value: Int) :
Comparable<WindowWidthSizeClass> {
- override operator fun compareTo(other: WindowWidthSizeClass) = value.compareTo(other.value)
+ override operator fun compareTo(other: WindowWidthSizeClass) =
+ breakpoint().compareTo(other.breakpoint())
override fun toString(): String {
return "WindowWidthSizeClass." + when (this) {
@@ -119,14 +148,44 @@
*/
val Expanded = WindowWidthSizeClass(2)
+ /** The default set of size classes. Should never expand to ensure behavior consistency. */
+ internal val DefaultSizeClasses = setOf(Compact, Medium, Expanded)
+
+ private fun WindowWidthSizeClass.breakpoint(): Dp {
+ return when {
+ this == Expanded -> 840.dp
+ this == Medium -> 600.dp
+ else -> 0.dp
+ }
+ }
+
/** Calculates the [WindowWidthSizeClass] for a given [width] */
internal fun fromWidth(width: Dp): WindowWidthSizeClass {
- require(width >= 0.dp) { "Width must not be negative" }
- return when {
- width < 600.dp -> Compact
- width < 840.dp -> Medium
- else -> Expanded
+ return fromWidth(
+ with(defaultDensity) { width.toPx() }, defaultDensity, DefaultSizeClasses
+ )
+ }
+
+ /**
+ * Calculates the best matched [WindowWidthSizeClass] for a given [width] in Pixels and
+ * a given [Density] from [supportedSizeClasses].
+ */
+ internal fun fromWidth(
+ width: Float,
+ density: Density,
+ supportedSizeClasses: Set<WindowWidthSizeClass>
+ ): WindowWidthSizeClass {
+ require(width >= 0) { "Width must not be negative" }
+ require(supportedSizeClasses.isNotEmpty()) { "Must support at least one size class" }
+ val sortedSizeClasses = supportedSizeClasses.sortedDescending()
+ // Find the largest supported size class that matches the width
+ sortedSizeClasses.forEach {
+ if (width >= with(density) { it.breakpoint().toPx() }) {
+ return it
+ }
}
+ // If none of the size classes matches, return the smallest one.
+ return sortedSizeClasses.last()
}
}
}
@@ -145,7 +204,8 @@
value class WindowHeightSizeClass private constructor(private val value: Int) :
Comparable<WindowHeightSizeClass> {
- override operator fun compareTo(other: WindowHeightSizeClass) = value.compareTo(other.value)
+ override operator fun compareTo(other: WindowHeightSizeClass) =
+ breakpoint().compareTo(other.breakpoint())
override fun toString(): String {
return "WindowHeightSizeClass." + when (this) {
@@ -166,14 +226,46 @@
/** Represents the majority of tablets in portrait */
val Expanded = WindowHeightSizeClass(2)
+ /** The default set of size classes. Should never expand to ensure behavior consistency. */
+ internal val DefaultSizeClasses = setOf(Compact, Medium, Expanded)
+
+ private fun WindowHeightSizeClass.breakpoint(): Dp {
+ return when {
+ this == Expanded -> 900.dp
+ this == Medium -> 480.dp
+ else -> 0.dp
+ }
+ }
+
/** Calculates the [WindowHeightSizeClass] for a given [height] */
internal fun fromHeight(height: Dp): WindowHeightSizeClass {
- require(height >= 0.dp) { "Height must not be negative" }
- return when {
- height < 480.dp -> Compact
- height < 900.dp -> Medium
- else -> Expanded
+ return fromHeight(
+ with(defaultDensity) { height.toPx() }, defaultDensity, DefaultSizeClasses
+ )
+ }
+
+ /**
+ * Calculates the best matched [WindowHeightSizeClass] for a given [height] in Pixels and
+ * a given [Density] from [supportedSizeClasses].
+ */
+ internal fun fromHeight(
+ height: Float,
+ density: Density,
+ supportedSizeClasses: Set<WindowHeightSizeClass>
+ ): WindowHeightSizeClass {
+ require(height >= 0) { "Width must not be negative" }
+ require(supportedSizeClasses.isNotEmpty()) { "Must support at least one size class" }
+ val sortedSizeClasses = supportedSizeClasses.sortedDescending()
+ // Find the largest supported size class that matches the width
+ sortedSizeClasses.forEach {
+ if (height >= with(density) { it.breakpoint().toPx() }) {
+ return it
+ }
}
+ // If none of the size classes matches, return the smallest one.
+ return sortedSizeClasses.last()
}
}
}
+
+private val defaultDensity = Density(1F, 1F)
diff --git a/compose/material3/material3-window-size-class/src/test/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClassTest.kt b/compose/material3/material3-window-size-class/src/test/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClassTest.kt
index b570d75..e7619ee 100644
--- a/compose/material3/material3-window-size-class/src/test/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClassTest.kt
+++ b/compose/material3/material3-window-size-class/src/test/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClassTest.kt
@@ -16,6 +16,7 @@
package androidx.compose.material3.windowsizeclass
+import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
import com.google.common.truth.Truth.assertThat
import kotlin.test.assertFailsWith
@@ -25,7 +26,6 @@
@RunWith(JUnit4::class)
class WindowSizeClassTest {
-
@Test
fun calculateWidthSizeClass_forNegativeWidth_throws() {
assertFailsWith(IllegalArgumentException::class) {
@@ -34,13 +34,45 @@
}
@Test
- fun calculateHeightSizeClass_forNegativeWidth_throws() {
+ fun calculateHeightSizeClass_forNegativeHeight_throws() {
assertFailsWith(IllegalArgumentException::class) {
WindowHeightSizeClass.fromHeight((-10).dp)
}
}
@Test
+ fun calculateWidthSizeClass_forNegativeWidthInPx_throws() {
+ assertFailsWith(IllegalArgumentException::class) {
+ WindowWidthSizeClass.fromWidth(
+ -10F, DefaultDensity, WindowWidthSizeClass.DefaultSizeClasses
+ )
+ }
+ }
+
+ @Test
+ fun calculateHeightSizeClass_forNegativeHeightInPx_throws() {
+ assertFailsWith(IllegalArgumentException::class) {
+ WindowHeightSizeClass.fromHeight(
+ -10F, DefaultDensity, WindowHeightSizeClass.DefaultSizeClasses
+ )
+ }
+ }
+
+ @Test
+ fun calculateWidthSizeClass_noSupportedSizeClass_throws() {
+ assertFailsWith(IllegalArgumentException::class) {
+ WindowWidthSizeClass.fromWidth(10F, DefaultDensity, emptySet())
+ }
+ }
+
+ @Test
+ fun calculateHeightSizeClass_noSupportedSizeClass_throws() {
+ assertFailsWith(IllegalArgumentException::class) {
+ WindowHeightSizeClass.fromHeight(10F, DefaultDensity, emptySet())
+ }
+ }
+
+ @Test
fun calculateWidthSizeClass() {
assertThat(WindowWidthSizeClass.fromWidth(0.dp)).isEqualTo(WindowWidthSizeClass.Compact)
assertThat(WindowWidthSizeClass.fromWidth(200.dp)).isEqualTo(WindowWidthSizeClass.Compact)
@@ -69,6 +101,118 @@
}
@Test
+ fun calculateWidthSizeClass_withDefaultDensity() {
+ assertWidthClass(WindowWidthSizeClass.Compact, 0F)
+ assertWidthClass(WindowWidthSizeClass.Compact, 200F)
+
+ assertWidthClass(WindowWidthSizeClass.Medium, 600F)
+ assertWidthClass(WindowWidthSizeClass.Medium, 700F)
+
+ assertWidthClass(WindowWidthSizeClass.Expanded, 840F)
+ assertWidthClass(WindowWidthSizeClass.Expanded, 1000F)
+ }
+
+ @Test
+ fun calculateHeightSizeClass_withDefaultDensity() {
+ assertHeightClass(WindowHeightSizeClass.Compact, 0F)
+ assertHeightClass(WindowHeightSizeClass.Compact, 200F)
+
+ assertHeightClass(WindowHeightSizeClass.Medium, 480F)
+ assertHeightClass(WindowHeightSizeClass.Medium, 700F)
+
+ assertHeightClass(WindowHeightSizeClass.Expanded, 900F)
+ assertHeightClass(WindowHeightSizeClass.Expanded, 1000F)
+ }
+
+ @Test
+ fun calculateWidthSizeClass_withMockDensity() {
+ val mockDensity = Density(2F, 2F)
+
+ assertWidthClass(WindowWidthSizeClass.Compact, 0F, mockDensity)
+ assertWidthClass(WindowWidthSizeClass.Compact, 400F, mockDensity)
+
+ assertWidthClass(WindowWidthSizeClass.Medium, 1200F, mockDensity)
+ assertWidthClass(WindowWidthSizeClass.Medium, 1400F, mockDensity)
+
+ assertWidthClass(WindowWidthSizeClass.Expanded, 1680F, mockDensity)
+ assertWidthClass(WindowWidthSizeClass.Expanded, 2000F, mockDensity)
+ }
+
+ @Test
+ fun calculateHeightSizeClass_withMockDensity() {
+ val mockDensity = Density(2F, 2F)
+
+ assertHeightClass(WindowHeightSizeClass.Compact, 0F, mockDensity)
+ assertHeightClass(WindowHeightSizeClass.Compact, 400F, mockDensity)
+
+ assertHeightClass(WindowHeightSizeClass.Medium, 960F, mockDensity)
+ assertHeightClass(WindowHeightSizeClass.Medium, 1400F, mockDensity)
+
+ assertHeightClass(WindowHeightSizeClass.Expanded, 1800F, mockDensity)
+ assertHeightClass(WindowHeightSizeClass.Expanded, 2000F, mockDensity)
+ }
+
+ @Test
+ fun calculateWidthSizeClass_useBestMatchedSupportedSizeClasses() {
+ assertWidthClass(
+ WindowWidthSizeClass.Compact,
+ 700F,
+ supportedSizeClasses = setOf(
+ WindowWidthSizeClass.Compact, WindowWidthSizeClass.Expanded
+ )
+ )
+
+ assertWidthClass(
+ WindowWidthSizeClass.Medium,
+ 1000F,
+ supportedSizeClasses = setOf(
+ WindowWidthSizeClass.Compact, WindowWidthSizeClass.Medium
+ )
+ )
+ }
+
+ @Test
+ fun calculateHeightSizeClass_useBestMatchedSupportedSizeClasses() {
+ assertHeightClass(
+ WindowHeightSizeClass.Compact,
+ 700F,
+ supportedSizeClasses = setOf(
+ WindowHeightSizeClass.Compact, WindowHeightSizeClass.Expanded
+ )
+ )
+
+ assertHeightClass(
+ WindowHeightSizeClass.Medium,
+ 1000F,
+ supportedSizeClasses = setOf(
+ WindowHeightSizeClass.Compact, WindowHeightSizeClass.Medium
+ )
+ )
+ }
+
+ @Test
+ fun calculateWidthSizeClass_fallbackToTheSmallestSizeClasses() {
+ assertWidthClass(
+ WindowWidthSizeClass.Medium,
+ 200F,
+ supportedSizeClasses = setOf(
+ WindowWidthSizeClass.Medium, WindowWidthSizeClass.Expanded
+ )
+ )
+ }
+
+ @Test
+ fun calculateHeightSizeClass_fallbackToTheSmallestSizeClasses() {
+ assertHeightClass(
+ WindowHeightSizeClass.Medium,
+ 200F,
+ supportedSizeClasses = setOf(
+ WindowHeightSizeClass.Medium, WindowHeightSizeClass.Expanded
+ )
+ )
+ }
+
+ @Test
fun widthSizeClassToString() {
assertThat(WindowWidthSizeClass.Compact.toString())
.isEqualTo("WindowWidthSizeClass.Compact")
@@ -193,4 +337,30 @@
assertThat(WindowHeightSizeClass.Compact >= WindowHeightSizeClass.Expanded).isFalse()
assertThat(WindowHeightSizeClass.Medium >= WindowHeightSizeClass.Expanded).isFalse()
}
+
+ private fun assertWidthClass(
+ expectedSizeClass: WindowWidthSizeClass,
+ width: Float,
+ density: Density = DefaultDensity,
+ supportedSizeClasses: Set<WindowWidthSizeClass> = WindowWidthSizeClass.DefaultSizeClasses
+ ) {
+ assertThat(
+ WindowWidthSizeClass.fromWidth(width, density, supportedSizeClasses)
+ ).isEqualTo(expectedSizeClass)
+ }
+
+ private fun assertHeightClass(
+ expectedSizeClass: WindowHeightSizeClass,
+ height: Float,
+ density: Density = DefaultDensity,
+ supportedSizeClasses: Set<WindowHeightSizeClass> = WindowHeightSizeClass.DefaultSizeClasses
+ ) {
+ assertThat(
+ WindowHeightSizeClass.fromHeight(height, density, supportedSizeClasses)
+ ).isEqualTo(expectedSizeClass)
+ }
+
+ companion object {
+ private val DefaultDensity = Density(1F, 1F)
+ }
}
\ No newline at end of file
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 422f0ec..3275ebb 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -167,7 +167,7 @@
}
public final class CalendarModelKt {
- method @androidx.compose.material3.ExperimentalMaterial3Api public static String formatWithSkeleton(long utcTimeMillis, String skeleton, optional java.util.Locale locale);
+ method @androidx.compose.material3.ExperimentalMaterial3Api public static String formatWithSkeleton(long utcTimeMillis, String skeleton, java.util.Locale locale);
}
public final class CalendarModel_androidKt {
@@ -240,7 +240,9 @@
@androidx.compose.runtime.Stable public final class ColorScheme {
ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim);
- method public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim, long surfaceBright, long surfaceDim, long surfaceContainer, long surfaceContainerHigh, long surfaceContainerHighest, long surfaceContainerLow, long surfaceContainerLowest);
+ method @Deprecated public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceDim, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest);
method public long getBackground();
method public long getError();
method public long getErrorContainer();
@@ -266,6 +268,13 @@
method public long getSecondary();
method public long getSecondaryContainer();
method public long getSurface();
+ method public long getSurfaceBright();
+ method public long getSurfaceContainer();
+ method public long getSurfaceContainerHigh();
+ method public long getSurfaceContainerHighest();
+ method public long getSurfaceContainerLow();
+ method public long getSurfaceContainerLowest();
+ method public long getSurfaceDim();
method public long getSurfaceTint();
method public long getSurfaceVariant();
method public long getTertiary();
@@ -295,6 +304,13 @@
property public final long secondary;
property public final long secondaryContainer;
property public final long surface;
+ property public final long surfaceBright;
+ property public final long surfaceContainer;
+ property public final long surfaceContainerHigh;
+ property public final long surfaceContainerHighest;
+ property public final long surfaceContainerLow;
+ property public final long surfaceContainerLowest;
+ property public final long surfaceDim;
property public final long surfaceTint;
property public final long surfaceVariant;
property public final long tertiary;
@@ -304,9 +320,13 @@
public final class ColorSchemeKt {
method public static long contentColorFor(androidx.compose.material3.ColorScheme, long backgroundColor);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static long contentColorFor(long backgroundColor);
- method public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
- method public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method @Deprecated public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest, optional long surfaceDim);
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalTonalElevationEnabled();
+ method @Deprecated public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest, optional long surfaceDim);
method public static long surfaceColorAtElevation(androidx.compose.material3.ColorScheme, float elevation);
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalTonalElevationEnabled;
}
public final class ContentColorKt {
@@ -888,15 +908,19 @@
@androidx.compose.material3.ExperimentalMaterial3Api public final class SearchBarDefaults {
method @androidx.compose.runtime.Composable public androidx.compose.material3.SearchBarColors colors(optional long containerColor, optional long dividerColor, optional androidx.compose.material3.TextFieldColors inputFieldColors);
method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getDockedShape();
- method public float getElevation();
+ method @Deprecated public float getElevation();
method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFullScreenShape();
method public float getInputFieldHeight();
method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getInputFieldShape();
+ method public float getShadowElevation();
+ method public float getTonalElevation();
method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors inputFieldColors(optional long textColor, optional long disabledTextColor, optional long cursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long placeholderColor, optional long disabledPlaceholderColor);
method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors inputFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long cursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor);
- property public final float Elevation;
+ property @Deprecated public final float Elevation;
property public final float InputFieldHeight;
+ property public final float ShadowElevation;
+ property public final float TonalElevation;
property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape dockedShape;
property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape fullScreenShape;
property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape inputFieldShape;
@@ -905,8 +929,8 @@
}
public final class SearchBarKt {
- method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DockedSearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
- method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DockedSearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
}
@androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class SelectableChipBorder {
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 422f0ec..3275ebb 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -167,7 +167,7 @@
}
public final class CalendarModelKt {
- method @androidx.compose.material3.ExperimentalMaterial3Api public static String formatWithSkeleton(long utcTimeMillis, String skeleton, optional java.util.Locale locale);
+ method @androidx.compose.material3.ExperimentalMaterial3Api public static String formatWithSkeleton(long utcTimeMillis, String skeleton, java.util.Locale locale);
}
public final class CalendarModel_androidKt {
@@ -240,7 +240,9 @@
@androidx.compose.runtime.Stable public final class ColorScheme {
ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim);
- method public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim, long surfaceBright, long surfaceDim, long surfaceContainer, long surfaceContainerHigh, long surfaceContainerHighest, long surfaceContainerLow, long surfaceContainerLowest);
+ method @Deprecated public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceDim, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest);
method public long getBackground();
method public long getError();
method public long getErrorContainer();
@@ -266,6 +268,13 @@
method public long getSecondary();
method public long getSecondaryContainer();
method public long getSurface();
+ method public long getSurfaceBright();
+ method public long getSurfaceContainer();
+ method public long getSurfaceContainerHigh();
+ method public long getSurfaceContainerHighest();
+ method public long getSurfaceContainerLow();
+ method public long getSurfaceContainerLowest();
+ method public long getSurfaceDim();
method public long getSurfaceTint();
method public long getSurfaceVariant();
method public long getTertiary();
@@ -295,6 +304,13 @@
property public final long secondary;
property public final long secondaryContainer;
property public final long surface;
+ property public final long surfaceBright;
+ property public final long surfaceContainer;
+ property public final long surfaceContainerHigh;
+ property public final long surfaceContainerHighest;
+ property public final long surfaceContainerLow;
+ property public final long surfaceContainerLowest;
+ property public final long surfaceDim;
property public final long surfaceTint;
property public final long surfaceVariant;
property public final long tertiary;
@@ -304,9 +320,13 @@
public final class ColorSchemeKt {
method public static long contentColorFor(androidx.compose.material3.ColorScheme, long backgroundColor);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static long contentColorFor(long backgroundColor);
- method public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
- method public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method @Deprecated public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest, optional long surfaceDim);
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalTonalElevationEnabled();
+ method @Deprecated public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest, optional long surfaceDim);
method public static long surfaceColorAtElevation(androidx.compose.material3.ColorScheme, float elevation);
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalTonalElevationEnabled;
}
public final class ContentColorKt {
@@ -888,15 +908,19 @@
@androidx.compose.material3.ExperimentalMaterial3Api public final class SearchBarDefaults {
method @androidx.compose.runtime.Composable public androidx.compose.material3.SearchBarColors colors(optional long containerColor, optional long dividerColor, optional androidx.compose.material3.TextFieldColors inputFieldColors);
method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getDockedShape();
- method public float getElevation();
+ method @Deprecated public float getElevation();
method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFullScreenShape();
method public float getInputFieldHeight();
method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getInputFieldShape();
+ method public float getShadowElevation();
+ method public float getTonalElevation();
method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors inputFieldColors(optional long textColor, optional long disabledTextColor, optional long cursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long placeholderColor, optional long disabledPlaceholderColor);
method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors inputFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long cursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor);
- property public final float Elevation;
+ property @Deprecated public final float Elevation;
property public final float InputFieldHeight;
+ property public final float ShadowElevation;
+ property public final float TonalElevation;
property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape dockedShape;
property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape fullScreenShape;
property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape inputFieldShape;
@@ -905,8 +929,8 @@
}
public final class SearchBarKt {
- method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DockedSearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
- method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DockedSearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
}
@androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class SelectableChipBorder {
diff --git a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
index aef2f9c..65a4227 100644
--- a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
+++ b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
@@ -101,6 +101,7 @@
import androidx.compose.material3.samples.PinnedTopAppBar
import androidx.compose.material3.samples.PlainTooltipSample
import androidx.compose.material3.samples.PlainTooltipWithManualInvocationSample
+import androidx.compose.material3.samples.PrimaryIconTabs
import androidx.compose.material3.samples.PrimaryTabs
import androidx.compose.material3.samples.RadioButtonSample
import androidx.compose.material3.samples.RadioGroupSample
@@ -905,6 +906,13 @@
PrimaryTabs()
},
Example(
+ name = ::PrimaryIconTabs.name,
+ description = TabsExampleDescription,
+ sourceUrl = TabsExampleSourceUrl
+ ) {
+ PrimaryIconTabs()
+ },
+ Example(
name = ::SecondaryTabs.name,
description = TabsExampleDescription,
sourceUrl = TabsExampleSourceUrl
diff --git a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/ui/theme/Theme.kt b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/ui/theme/Theme.kt
index 84545ca..e84bab3 100644
--- a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/ui/theme/Theme.kt
+++ b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/ui/theme/Theme.kt
@@ -130,61 +130,81 @@
}
private val LightCustomColorScheme = lightColorScheme(
- primary = Color(0xFF984816),
+ primary = Color(0xFF006E2C),
onPrimary = Color(0xFFFFFFFF),
- primaryContainer = Color(0xFFFFDBC9),
- onPrimaryContainer = Color(0xFF341000),
- inversePrimary = Color(0xFFFFB68F),
- secondary = Color(0xFF765849),
+ primaryContainer = Color(0xFF43B55F),
+ onPrimaryContainer = Color(0xFF004117),
+ inversePrimary = Color(0xFF6DDD81),
+ secondary = Color(0xFF3F6743),
onSecondary = Color(0xFFFFFFFF),
- secondaryContainer = Color(0xFFFFDBC9),
- onSecondaryContainer = Color(0xFF2B160B),
- tertiary = Color(0xFF656032),
+ secondaryContainer = Color(0xFFC2F0C2),
+ onSecondaryContainer = Color(0xFF466F4A),
+ tertiary = Color(0xFF005EB3),
onTertiary = Color(0xFFFFFFFF),
- tertiaryContainer = Color(0xFFEBE4AA),
- onTertiaryContainer = Color(0xFF1F1C00),
- background = Color(0xFFFCFCFC),
- onBackground = Color(0xFF201A17),
- surface = Color(0xFFFCFCFC),
- onSurface = Color(0xFF201A17),
- surfaceVariant = Color(0xFFF4DED5),
- onSurfaceVariant = Color(0xFF53443D),
- inverseSurface = Color(0xFF362F2C),
- inverseOnSurface = Color(0xFFFBEEE9),
- error = Color(0xFFBA1B1B),
+ tertiaryContainer = Color(0xFF5EA1FF),
+ onTertiaryContainer = Color(0xFF00376C),
+ background = Color(0xFFF5FBF0),
+ onBackground = Color(0xFF171D17),
+ surface = Color(0xFFF5FBF0),
+ onSurface = Color(0xFF171D17),
+ surfaceVariant = Color(0xFFD9E6D6),
+ onSurfaceVariant = Color(0xFF3E4A3E),
+ inverseSurface = Color(0xFF2C322B),
+ inverseOnSurface = Color(0xFFECF3E8),
+ error = Color(0xFFBA1A1A),
onError = Color(0xFFFFFFFF),
- errorContainer = Color(0xFFFFDAD4),
- onErrorContainer = Color(0xFF410001),
- outline = Color(0xFF85736B),
+ errorContainer = Color(0xFFFFDAD6),
+ onErrorContainer = Color(0xFF410002),
+ outline = Color(0xFF6C786A),
+ outlineVariant = Color(0xFFBDCABA),
+ scrim = Color(0xFF000000),
+ surfaceTint = Color(0xFF006E2C),
+ surfaceContainerHighest = Color(0xFFDEE4DA),
+ surfaceContainerHigh = Color(0xFFE4EADF),
+ surfaceContainer = Color(0xFFE9F0E5),
+ surfaceContainerLow = Color(0xFFEFF6EB),
+ surfaceContainerLowest = Color(0xFFFFFFFF),
+ surfaceBright = Color(0xFFF5FBF0),
+ surfaceDim = Color(0xFFD5DCD1)
)
private val DarkCustomColorScheme = darkColorScheme(
- primary = Color(0xFFFFB68F),
- onPrimary = Color(0xFF562000),
- primaryContainer = Color(0xFF793100),
- onPrimaryContainer = Color(0xFFFFDBC9),
- inversePrimary = Color(0xFF984816),
- secondary = Color(0xFFE6BEAC),
- onSecondary = Color(0xFF432B1E),
- secondaryContainer = Color(0xFF5C4032),
- onSecondaryContainer = Color(0xFFFFDBC9),
- tertiary = Color(0xFFCFC890),
- onTertiary = Color(0xFF353107),
- tertiaryContainer = Color(0xFF4C481C),
- onTertiaryContainer = Color(0xFFEBE4AA),
- background = Color(0xFF201A17),
- onBackground = Color(0xFFEDE0DB),
- surface = Color(0xFF201A17),
- onSurface = Color(0xFFEDE0DB),
- surfaceVariant = Color(0xFF53443D),
- onSurfaceVariant = Color(0xFFD7C2B9),
- inverseSurface = Color(0xFFEDE0DB),
- inverseOnSurface = Color(0xFF362F2C),
+ primary = Color(0xFF6DDD81),
+ onPrimary = Color(0xFF003914),
+ primaryContainer = Color(0xFF008738),
+ onPrimaryContainer = Color(0xFFF7FFF2),
+ inversePrimary = Color(0xFF006E2C),
+ secondary = Color(0xFFA5D2A6),
+ onSecondary = Color(0xFF0F3819),
+ secondaryContainer = Color(0xFF1D4524),
+ onSecondaryContainer = Color(0xFF87B389),
+ tertiary = Color(0xFFA7C8FF),
+ onTertiary = Color(0xFF003061),
+ tertiaryContainer = Color(0xFF0774D9),
+ onTertiaryContainer = Color(0xFFFDFCFF),
+ background = Color(0xFF0F150F),
+ onBackground = Color(0xFFDEE4DA),
+ surface = Color(0xFF0F150F),
+ onSurface = Color(0xFFDEE4DA),
+ surfaceVariant = Color(0xFF3E4A3E),
+ onSurfaceVariant = Color(0xFFBDCABA),
+ inverseSurface = Color(0xFFDEE4DA),
+ inverseOnSurface = Color(0xFF2C322B),
error = Color(0xFFFFB4A9),
onError = Color(0xFF680003),
errorContainer = Color(0xFF930006),
onErrorContainer = Color(0xFFFFDAD4),
- outline = Color(0xFFA08D85),
+ outline = Color(0xFF6C786A),
+ outlineVariant = Color(0xFF3E4A3E),
+ scrim = Color(0xFF000000),
+ surfaceTint = Color(0xFF6DDD81),
+ surfaceContainerHighest = Color(0xFF30362F),
+ surfaceContainerHigh = Color(0xFF252C25),
+ surfaceContainer = Color(0xFF1B211B),
+ surfaceContainerLow = Color(0xFF171D17),
+ surfaceContainerLowest = Color(0xFF0A100A),
+ surfaceBright = Color(0xFF343B34),
+ surfaceDim = Color(0xFF0F150F)
)
private tailrec fun Context.findActivity(): Activity =
diff --git a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/ColorSchemeDemo.kt b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/ColorSchemeDemo.kt
index 8df1367..18b888f 100644
--- a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/ColorSchemeDemo.kt
+++ b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/ColorSchemeDemo.kt
@@ -16,6 +16,7 @@
package androidx.compose.material3.demos
+import android.annotation.SuppressLint
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -34,6 +35,7 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.unit.dp
@Composable
@@ -42,14 +44,11 @@
Row(
modifier = Modifier.padding(8.dp),
) {
- Column(Modifier.weight(1f).verticalScroll(rememberScrollState())) {
+ Column(
+ Modifier
+ .weight(1f)
+ .verticalScroll(rememberScrollState())) {
Text("Surfaces", style = MaterialTheme.typography.bodyLarge)
- SurfaceColorSwatch(
- surface = colorScheme.background,
- surfaceText = "Background",
- onSurface = colorScheme.onBackground,
- onSurfaceText = "On Background"
- )
Spacer(modifier = Modifier.height(16.dp))
SurfaceColorSwatch(
surface = colorScheme.surface,
@@ -58,6 +57,65 @@
onSurfaceText = "On Surface"
)
Spacer(modifier = Modifier.height(16.dp))
+ DoubleTile(
+ leftTile = {
+ ColorTile(
+ text = "Surface Bright",
+ color = colorScheme.surfaceBright,
+ )
+ },
+ rightTile = {
+ ColorTile(
+ text = "Surface Dim",
+ color = colorScheme.surfaceDim,
+ )
+ },
+ )
+ DoubleTile(
+ leftTile = {
+ ColorTile(
+ text = "Surface Container",
+ color = colorScheme.surfaceContainer,
+ )
+ },
+ rightTile = {
+ ColorTile(
+ text = "Surface",
+ color = colorScheme.surface,
+ )
+ },
+ )
+ Text("Surface Container Variants", style = MaterialTheme.typography.bodyLarge)
+ Spacer(modifier = Modifier.height(16.dp))
+ DoubleTile(
+ leftTile = {
+ ColorTile(
+ text = "High Emphasis",
+ color = colorScheme.surfaceContainerHigh,
+ )
+ },
+ rightTile = {
+ ColorTile(
+ text = "Highest Emphasis",
+ color = colorScheme.surfaceContainerHighest,
+ )
+ },
+ )
+ DoubleTile(
+ leftTile = {
+ ColorTile(
+ text = "Low Emphasis",
+ color = colorScheme.surfaceContainerLow,
+ )
+ },
+ rightTile = {
+ ColorTile(
+ text = "Lowest Emphasis",
+ color = colorScheme.surfaceContainerLowest,
+ )
+ },
+ )
+ Spacer(modifier = Modifier.height(16.dp))
SurfaceColorSwatch(
surface = colorScheme.surfaceVariant,
surfaceText = "Surface Variant",
@@ -96,7 +154,10 @@
Spacer(modifier = Modifier.height(16.dp))
}
Spacer(modifier = Modifier.width(24.dp))
- Column(Modifier.weight(1f).verticalScroll(rememberScrollState())) {
+ Column(
+ Modifier
+ .weight(1f)
+ .verticalScroll(rememberScrollState())) {
Text("Content", style = MaterialTheme.typography.bodyLarge)
ContentColorSwatch(
color = colorScheme.primary,
@@ -223,6 +284,8 @@
}
}
+@SuppressLint("NullAnnotationGroup")
+@OptIn(ExperimentalTextApi::class)
@Composable
private fun ColorTile(text: String, color: Color) {
var borderColor = Color.Transparent
@@ -231,7 +294,9 @@
} else if (color == Color.White) borderColor = Color.Black
Surface(
- modifier = Modifier.height(48.dp).fillMaxWidth(),
+ modifier = Modifier
+ .height(48.dp)
+ .fillMaxWidth(),
color = color,
border = BorderStroke(1.dp, borderColor),
) {
@@ -239,9 +304,9 @@
text,
Modifier.padding(4.dp),
style =
- MaterialTheme.typography.bodyMedium.copy(
- if (color.luminance() < .25) Color.White else Color.Black
- )
+ MaterialTheme.typography.bodyMedium.copy(
+ if (color.luminance() < .25) Color.White else Color.Black
+ )
)
}
-}
+}
\ No newline at end of file
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt
index c19a692..f92469a 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt
@@ -61,6 +61,7 @@
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+@Preview
@Composable
fun PrimaryTabs() {
var state by remember { mutableStateOf(0) }
@@ -91,6 +92,32 @@
}
}
+@Preview
+@Composable
+fun PrimaryIconTabs() {
+ var state by remember { mutableStateOf(0) }
+ val icons = listOf(Icons.Filled.Favorite, Icons.Filled.Favorite, Icons.Filled.Favorite)
+ Column {
+ TabRow(selectedTabIndex = state, indicator = @Composable { tabPositions ->
+ if (state < tabPositions.size) {
+ TabRowDefaults.PrimaryIndicator(
+ modifier = Modifier.tabIndicatorOffset(tabPositions[state]),
+ width = tabPositions[state].contentWidth
+ )
+ }
+ }) {
+ icons.forEachIndexed { index, icon ->
+ Tab(
+ selected = state == index,
+ onClick = { state = index },
+ icon = { Icon(icon, contentDescription = "Favorite") }
+ )
+ }
+ }
+ }
+}
+
+@Preview
@Composable
fun SecondaryTabs() {
var state by remember { mutableStateOf(0) }
@@ -137,6 +164,7 @@
}
}
+@Preview
@Composable
fun IconTabs() {
var state by remember { mutableStateOf(0) }
@@ -159,6 +187,7 @@
}
}
+@Preview
@Composable
fun TextAndIconTabs() {
var state by remember { mutableStateOf(0) }
@@ -186,6 +215,7 @@
}
}
+@Preview
@Composable
fun LeadingIconTabs() {
var state by remember { mutableStateOf(0) }
@@ -213,6 +243,7 @@
}
}
+@Preview
@Composable
fun ScrollingPrimaryTabs() {
var state by remember { mutableStateOf(0) }
@@ -254,6 +285,7 @@
}
}
+@Preview
@Composable
fun ScrollingSecondaryTabs() {
var state by remember { mutableStateOf(0) }
@@ -287,6 +319,7 @@
}
}
+@Preview
@Composable
fun ScrollingTextTabs() {
var state by remember { mutableStateOf(0) }
@@ -412,6 +445,7 @@
}
}
+@Preview
@Composable
fun ScrollingFancyIndicatorContainerTabs() {
var state by remember { mutableStateOf(0) }
@@ -452,7 +486,6 @@
}
}
-@Preview
@Sampled
@Composable
fun FancyTab(title: String, onClick: () -> Unit, selected: Boolean) {
@@ -478,7 +511,6 @@
}
}
-@Preview
@Sampled
@Composable
fun FancyIndicator(color: Color, modifier: Modifier = Modifier) {
@@ -492,7 +524,6 @@
)
}
-@Preview
@Sampled
@Composable
fun FancyAnimatedIndicator(tabPositions: List<TabPosition>, selectedTabIndex: Int) {
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/BadgeTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/BadgeTest.kt
index 93da69a..21d3299 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/BadgeTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/BadgeTest.kt
@@ -16,6 +16,7 @@
package androidx.compose.material3
import android.os.Build
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
@@ -30,6 +31,7 @@
import androidx.compose.ui.test.assertContentDescriptionEquals
import androidx.compose.ui.test.assertHeightIsEqualTo
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
+import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
import androidx.compose.ui.test.assertWidthIsAtLeast
import androidx.compose.ui.test.assertWidthIsEqualTo
import androidx.compose.ui.test.captureToImage
@@ -44,6 +46,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
+import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -241,6 +244,45 @@
.assertWidthIsEqualTo(icon.defaultWidth)
.assertHeightIsEqualTo(icon.defaultHeight)
}
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Test
+ fun badgeBox_smallGreatGrandParentAndLargeAnchor_adjustedBadge() {
+ val greatGrandParentTag = "greatGrandParentLayout"
+ val badgeTag = "badgeTag"
+
+ rule.setMaterialContent(lightColorScheme()) {
+ Box(
+ modifier = Modifier.size(50.dp)
+ .testTag(greatGrandParentTag)
+ ) {
+ Box {
+ BadgedBox(
+ badge = {
+ Badge(modifier = Modifier
+ .testTag(badgeTag)
+ ) { Text("999+") }
+ }
+ ) {
+ Icon(
+ icon,
+ null,
+ modifier = Modifier.size(40.dp)
+ )
+ }
+ }
+ }
+ }
+
+ val badge = rule.onNodeWithTag(badgeTag)
+ val badgeBounds = rule.onNodeWithTag(badgeTag).getUnclippedBoundsInRoot()
+ val greatGrandParentBounds =
+ rule.onNodeWithTag(greatGrandParentTag).getUnclippedBoundsInRoot()
+
+ badge.assertTopPositionInRootIsEqualTo(greatGrandParentBounds.top)
+ // Manually test the badge's right bound.
+ assertThat(badgeBounds.right == greatGrandParentBounds.right).isTrue()
+ }
}
private const val TestBadgeTag = "badge"
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ColorSchemeScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ColorSchemeScreenshotTest.kt
index e83405a..2b52272 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ColorSchemeScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ColorSchemeScreenshotTest.kt
@@ -15,6 +15,7 @@
*/
package androidx.compose.material3
+import android.annotation.SuppressLint
import android.os.Build
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Box
@@ -34,10 +35,10 @@
import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.captureToImage
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.unit.dp
import androidx.test.filters.MediumTest
import androidx.test.filters.SdkSuppress
@@ -50,7 +51,6 @@
@MediumTest
@RunWith(Parameterized::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-@OptIn(ExperimentalTestApi::class, ExperimentalMaterial3Api::class)
class ColorSchemeScreenshotTest(private val scheme: ColorSchemeWrapper) {
@get:Rule
@@ -80,61 +80,81 @@
// name is as expected.
companion object {
private val LightCustomColorScheme = lightColorScheme(
- primary = Color(0xFF984816),
+ primary = Color(0xFF006E2C),
onPrimary = Color(0xFFFFFFFF),
- primaryContainer = Color(0xFFFFDBC9),
- onPrimaryContainer = Color(0xFF341000),
- inversePrimary = Color(0xFFFFB68F),
- secondary = Color(0xFF765849),
+ primaryContainer = Color(0xFF43B55F),
+ onPrimaryContainer = Color(0xFF004117),
+ inversePrimary = Color(0xFF6DDD81),
+ secondary = Color(0xFF3F6743),
onSecondary = Color(0xFFFFFFFF),
- secondaryContainer = Color(0xFFFFDBC9),
- onSecondaryContainer = Color(0xFF2B160B),
- tertiary = Color(0xFF656032),
+ secondaryContainer = Color(0xFFC2F0C2),
+ onSecondaryContainer = Color(0xFF466F4A),
+ tertiary = Color(0xFF005EB3),
onTertiary = Color(0xFFFFFFFF),
- tertiaryContainer = Color(0xFFEBE4AA),
- onTertiaryContainer = Color(0xFF1F1C00),
- background = Color(0xFFFCFCFC),
- onBackground = Color(0xFF201A17),
- surface = Color(0xFFFCFCFC),
- onSurface = Color(0xFF201A17),
- surfaceVariant = Color(0xFFF4DED5),
- onSurfaceVariant = Color(0xFF53443D),
- inverseSurface = Color(0xFF362F2C),
- inverseOnSurface = Color(0xFFFBEEE9),
- error = Color(0xFFBA1B1B),
+ tertiaryContainer = Color(0xFF5EA1FF),
+ onTertiaryContainer = Color(0xFF00376C),
+ background = Color(0xFFF5FBF0),
+ onBackground = Color(0xFF171D17),
+ surface = Color(0xFFF5FBF0),
+ onSurface = Color(0xFF171D17),
+ surfaceVariant = Color(0xFFD9E6D6),
+ onSurfaceVariant = Color(0xFF3E4A3E),
+ inverseSurface = Color(0xFF2C322B),
+ inverseOnSurface = Color(0xFFECF3E8),
+ error = Color(0xFFBA1A1A),
onError = Color(0xFFFFFFFF),
- errorContainer = Color(0xFFFFDAD4),
- onErrorContainer = Color(0xFF410001),
- outline = Color(0xFF85736B),
+ errorContainer = Color(0xFFFFDAD6),
+ onErrorContainer = Color(0xFF410002),
+ outline = Color(0xFF6C786A),
+ outlineVariant = Color(0xFFBDCABA),
+ scrim = Color(0xFF000000),
+ surfaceTint = Color(0xFF006E2C),
+ surfaceContainerHighest = Color(0xFFDEE4DA),
+ surfaceContainerHigh = Color(0xFFE4EADF),
+ surfaceContainer = Color(0xFFE9F0E5),
+ surfaceContainerLow = Color(0xFFEFF6EB),
+ surfaceContainerLowest = Color(0xFFFFFFFF),
+ surfaceBright = Color(0xFFF5FBF0),
+ surfaceDim = Color(0xFFD5DCD1)
)
private val DarkCustomColorScheme = darkColorScheme(
- primary = Color(0xFFFFB68F),
- onPrimary = Color(0xFF562000),
- primaryContainer = Color(0xFF793100),
- onPrimaryContainer = Color(0xFFFFDBC9),
- inversePrimary = Color(0xFF984816),
- secondary = Color(0xFFE6BEAC),
- onSecondary = Color(0xFF432B1E),
- secondaryContainer = Color(0xFF5C4032),
- onSecondaryContainer = Color(0xFFFFDBC9),
- tertiary = Color(0xFFCFC890),
- onTertiary = Color(0xFF353107),
- tertiaryContainer = Color(0xFF4C481C),
- onTertiaryContainer = Color(0xFFEBE4AA),
- background = Color(0xFF201A17),
- onBackground = Color(0xFFEDE0DB),
- surface = Color(0xFF201A17),
- onSurface = Color(0xFFEDE0DB),
- surfaceVariant = Color(0xFF53443D),
- onSurfaceVariant = Color(0xFFD7C2B9),
- inverseSurface = Color(0xFFEDE0DB),
- inverseOnSurface = Color(0xFF362F2C),
+ primary = Color(0xFF6DDD81),
+ onPrimary = Color(0xFF003914),
+ primaryContainer = Color(0xFF008738),
+ onPrimaryContainer = Color(0xFFF7FFF2),
+ inversePrimary = Color(0xFF006E2C),
+ secondary = Color(0xFFA5D2A6),
+ onSecondary = Color(0xFF0F3819),
+ secondaryContainer = Color(0xFF1D4524),
+ onSecondaryContainer = Color(0xFF87B389),
+ tertiary = Color(0xFFA7C8FF),
+ onTertiary = Color(0xFF003061),
+ tertiaryContainer = Color(0xFF0774D9),
+ onTertiaryContainer = Color(0xFFFDFCFF),
+ background = Color(0xFF0F150F),
+ onBackground = Color(0xFFDEE4DA),
+ surface = Color(0xFF0F150F),
+ onSurface = Color(0xFFDEE4DA),
+ surfaceVariant = Color(0xFF3E4A3E),
+ onSurfaceVariant = Color(0xFFBDCABA),
+ inverseSurface = Color(0xFFDEE4DA),
+ inverseOnSurface = Color(0xFF2C322B),
error = Color(0xFFFFB4A9),
onError = Color(0xFF680003),
errorContainer = Color(0xFF930006),
onErrorContainer = Color(0xFFFFDAD4),
- outline = Color(0xFFA08D85),
+ outline = Color(0xFF6C786A),
+ outlineVariant = Color(0xFF3E4A3E),
+ scrim = Color(0xFF000000),
+ surfaceTint = Color(0xFF6DDD81),
+ surfaceContainerHighest = Color(0xFF30362F),
+ surfaceContainerHigh = Color(0xFF252C25),
+ surfaceContainer = Color(0xFF1B211B),
+ surfaceContainerLow = Color(0xFF171D17),
+ surfaceContainerLowest = Color(0xFF0A100A),
+ surfaceBright = Color(0xFF343B34),
+ surfaceDim = Color(0xFF0F150F)
)
@Parameterized.Parameters(name = "{0}")
@@ -162,38 +182,90 @@
Row(
modifier = Modifier.padding(8.dp),
) {
- Column(Modifier.weight(1f).verticalScroll(rememberScrollState())) {
+ Column(
+ Modifier
+ .weight(1f)
+ .verticalScroll(rememberScrollState())) {
Text("Surfaces", style = MaterialTheme.typography.bodyLarge)
- ColorTile(
- text = "On Background",
- color = colorScheme.onBackground,
- )
- ColorTile(
- text = "Background",
- color = colorScheme.background,
+ Spacer(modifier = Modifier.height(16.dp))
+ SurfaceColorSwatch(
+ surface = colorScheme.surface,
+ surfaceText = "Surface",
+ onSurface = colorScheme.onSurface,
+ onSurfaceText = "On Surface"
)
Spacer(modifier = Modifier.height(16.dp))
DoubleTile(
leftTile = {
ColorTile(
- text = "On Surface",
- color = colorScheme.onSurface,
+ text = "Surface Bright",
+ color = colorScheme.surfaceBright,
)
},
rightTile = {
ColorTile(
- text = "On Surface Variant",
- color = colorScheme.onSurfaceVariant,
+ text = "Surface Dim",
+ color = colorScheme.surfaceDim,
)
},
)
- ColorTile(text = "Surface", color = colorScheme.surface)
+ DoubleTile(
+ leftTile = {
+ ColorTile(
+ text = "Surface Container",
+ color = colorScheme.surfaceContainer,
+ )
+ },
+ rightTile = {
+ ColorTile(
+ text = "Surface",
+ color = colorScheme.surface,
+ )
+ },
+ )
+ Text("Surface Container Variants", style = MaterialTheme.typography.bodyLarge)
Spacer(modifier = Modifier.height(16.dp))
DoubleTile(
leftTile = {
ColorTile(
- text = "Inverse Primary",
- color = colorScheme.inversePrimary,
+ text = "High Emphasis",
+ color = colorScheme.surfaceContainerHigh,
+ )
+ },
+ rightTile = {
+ ColorTile(
+ text = "Highest Emphasis",
+ color = colorScheme.surfaceContainerHighest,
+ )
+ },
+ )
+ DoubleTile(
+ leftTile = {
+ ColorTile(
+ text = "Low Emphasis",
+ color = colorScheme.surfaceContainerLow,
+ )
+ },
+ rightTile = {
+ ColorTile(
+ text = "Lowest Emphasis",
+ color = colorScheme.surfaceContainerLowest,
+ )
+ },
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ SurfaceColorSwatch(
+ surface = colorScheme.surfaceVariant,
+ surfaceText = "Surface Variant",
+ onSurface = colorScheme.onSurfaceVariant,
+ onSurfaceText = "On Surface Variant"
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ DoubleTile(
+ leftTile = {
+ ColorTile(
+ text = "Inverse Surface",
+ color = colorScheme.inverseSurface,
)
},
rightTile = {
@@ -206,147 +278,143 @@
DoubleTile(
leftTile = {
ColorTile(
- text = "Surface Variant",
- color = colorScheme.surfaceVariant,
+ text = "Inverse Primary",
+ color = colorScheme.inversePrimary,
)
},
rightTile = {
ColorTile(
- text = "Inverse Surface",
- color = colorScheme.inverseSurface,
- )
- },
- )
- Spacer(modifier = Modifier.height(16.dp))
- DoubleTile(
- leftTile = {
- ColorTile(
text = "Surface Tint",
color = colorScheme.surfaceTint,
)
},
- rightTile = { Box(Modifier.fillMaxWidth()) },
)
+ Spacer(modifier = Modifier.height(16.dp))
}
Spacer(modifier = Modifier.width(24.dp))
- Column(Modifier.weight(1f).verticalScroll(rememberScrollState())) {
+ Column(
+ Modifier
+ .weight(1f)
+ .verticalScroll(rememberScrollState())) {
Text("Content", style = MaterialTheme.typography.bodyLarge)
- DoubleTile(
- leftTile = {
- ColorTile(
- text = "On Primary Container",
- color = colorScheme.onPrimaryContainer,
- )
- },
- rightTile = {
- ColorTile(
- text = "On Primary",
- color = colorScheme.onPrimary,
- )
- },
- )
- DoubleTile(
- leftTile = {
- ColorTile(
- text = "Primary Container",
- color = colorScheme.primaryContainer,
- )
- },
- rightTile = {
- ColorTile(
- text = "Primary",
- color = colorScheme.primary,
- )
- },
- )
+ ContentColorSwatch(
+ color = colorScheme.primary,
+ colorText = "Primary",
+ onColor = colorScheme.onPrimary,
+ onColorText = "On Primary",
+ colorContainer = colorScheme.primaryContainer,
+ colorContainerText = "Primary Container",
+ onColorContainer = colorScheme.onPrimaryContainer,
+ onColorContainerText = "On Primary Container")
Spacer(modifier = Modifier.height(16.dp))
- DoubleTile(
- leftTile = {
- ColorTile(
- text = "On Secondary Container",
- color = colorScheme.onSecondaryContainer,
- )
- },
- rightTile = {
- ColorTile(
- text = "On Secondary",
- color = colorScheme.onSecondary,
- )
- },
- )
- DoubleTile(
- leftTile = {
- ColorTile(
- text = "Secondary Container",
- color = colorScheme.secondaryContainer,
- )
- },
- rightTile = {
- ColorTile(
- text = "Secondary",
- color = colorScheme.secondary,
- )
- },
- )
+ ContentColorSwatch(
+ color = colorScheme.secondary,
+ colorText = "Secondary",
+ onColor = colorScheme.onSecondary,
+ onColorText = "On Secondary",
+ colorContainer = colorScheme.secondaryContainer,
+ colorContainerText = "Secondary Container",
+ onColorContainer = colorScheme.onSecondaryContainer,
+ onColorContainerText = "On Secondary Container")
Spacer(modifier = Modifier.height(16.dp))
- DoubleTile(
- leftTile = {
- ColorTile(
- text = "On Tertiary Container",
- color = colorScheme.onTertiaryContainer,
- )
- },
- rightTile = {
- ColorTile(
- text = "On Tertiary",
- color = colorScheme.onTertiary,
- )
- },
- )
- DoubleTile(
- leftTile = {
- ColorTile(
- text = "Tertiary Container",
- color = colorScheme.tertiaryContainer,
- )
- },
- rightTile = {
- ColorTile(
- text = "Tertiary",
- color = colorScheme.tertiary,
- )
- },
- )
+ ContentColorSwatch(
+ color = colorScheme.tertiary,
+ colorText = "Tertiary",
+ onColor = colorScheme.onTertiary,
+ onColorText = "On Tertiary",
+ colorContainer = colorScheme.tertiaryContainer,
+ colorContainerText = "Tertiary Container",
+ onColorContainer = colorScheme.onTertiaryContainer,
+ onColorContainerText = "On Tertiary Container")
+ Spacer(modifier = Modifier.height(16.dp))
+ ContentColorSwatch(
+ color = colorScheme.error,
+ colorText = "Error",
+ onColor = colorScheme.onError,
+ onColorText = "On Error",
+ colorContainer = colorScheme.errorContainer,
+ colorContainerText = "Error Container",
+ onColorContainer = colorScheme.onErrorContainer,
+ onColorContainerText = "On Error Container")
Spacer(modifier = Modifier.height(16.dp))
Text("Utility", style = MaterialTheme.typography.bodyLarge)
DoubleTile(
leftTile = {
ColorTile(
- text = "On Error",
- color = colorScheme.onError,
+ text = "Outline",
+ color = colorScheme.outline,
)
},
rightTile = {
ColorTile(
- text = "Outline",
- color = colorScheme.outline,
+ text = "Outline Variant",
+ color = colorScheme.outlineVariant,
)
}
)
- DoubleTile(
- leftTile = {
- ColorTile(
- text = "Error",
- color = colorScheme.error,
- )
- },
- rightTile = { Box(Modifier.fillMaxWidth()) },
- )
}
}
}
@Composable
+private fun SurfaceColorSwatch(
+ surface: Color,
+ surfaceText: String,
+ onSurface: Color,
+ onSurfaceText: String
+) {
+ ColorTile(
+ text = surfaceText,
+ color = surface,
+ )
+ ColorTile(
+ text = onSurfaceText,
+ color = onSurface,
+ )
+}
+
+@Composable
+private fun ContentColorSwatch(
+ color: Color,
+ colorText: String,
+ onColor: Color,
+ onColorText: String,
+ colorContainer: Color,
+ colorContainerText: String,
+ onColorContainer: Color,
+ onColorContainerText: String,
+) {
+ DoubleTile(
+ leftTile = {
+ ColorTile(
+ text = colorText,
+ color = color
+ )
+ },
+ rightTile = {
+ ColorTile(
+ text = onColorText,
+ color = onColor,
+ )
+ },
+ )
+ DoubleTile(
+ leftTile = {
+ ColorTile(
+ text = colorContainerText,
+ color = colorContainer,
+ )
+ },
+ rightTile = {
+ ColorTile(
+ text = onColorContainerText,
+ color = onColorContainer,
+ )
+ },
+ )
+}
+
+@Composable
private fun DoubleTile(leftTile: @Composable () -> Unit, rightTile: @Composable () -> Unit) {
Row(modifier = Modifier.fillMaxWidth()) {
Box(modifier = Modifier.weight(1f)) { leftTile() }
@@ -354,6 +422,8 @@
}
}
+@SuppressLint("NullAnnotationGroup")
+@OptIn(ExperimentalTextApi::class)
@Composable
private fun ColorTile(text: String, color: Color) {
var borderColor = Color.Transparent
@@ -362,7 +432,9 @@
} else if (color == Color.White) borderColor = Color.Black
Surface(
- modifier = Modifier.height(48.dp).fillMaxWidth(),
+ modifier = Modifier
+ .height(48.dp)
+ .fillMaxWidth(),
color = color,
border = BorderStroke(1.dp, borderColor),
) {
@@ -375,4 +447,4 @@
)
)
}
-}
+}
\ No newline at end of file
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ColorUtilTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ColorUtilTest.kt
new file mode 100644
index 0000000..a281147
--- /dev/null
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ColorUtilTest.kt
@@ -0,0 +1,176 @@
+/*
+ * 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
+
+import androidx.compose.ui.graphics.Color
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorUtilTest {
+ @Test
+ fun setLuminance0_returnsBlack() {
+ assertThat(Color.Red.setLuminance(0f)).isEqualTo(Color.Black)
+ assertThat(Color.Blue.setLuminance(0f)).isEqualTo(Color.Black)
+ assertThat(Color.Green.setLuminance(0f)).isEqualTo(Color.Black)
+ assertThat(Color.Magenta.setLuminance(0f)).isEqualTo(Color.Black)
+ assertThat(Color.Cyan.setLuminance(0f)).isEqualTo(Color.Black)
+ assertThat(Color.White.setLuminance(0f)).isEqualTo(Color.Black)
+ assertThat(Color.Black.setLuminance(0f)).isEqualTo(Color.Black)
+ }
+
+ @Test
+ fun setLuminance100_returnsWhite() {
+ assertThat(Color.Red.setLuminance(100f)).isEqualTo(Color.White)
+ assertThat(Color.Blue.setLuminance(100f)).isEqualTo(Color.White)
+ assertThat(Color.Green.setLuminance(100f)).isEqualTo(Color.White)
+ assertThat(Color.Magenta.setLuminance(100f)).isEqualTo(Color.White)
+ assertThat(Color.Cyan.setLuminance(100f)).isEqualTo(Color.White)
+ assertThat(Color.White.setLuminance(100f)).isEqualTo(Color.White)
+ assertThat(Color.Black.setLuminance(100f)).isEqualTo(Color.White)
+ }
+
+ @Test
+ fun setLuminance_fromBlack() {
+ assertColorWithinTolerance(Color(0xff000000), Color.Black.setLuminance(0f), 1f)
+ assertColorWithinTolerance(Color(0xff010101), Color.Black.setLuminance(.25f), 1f)
+ assertColorWithinTolerance(Color(0xff020202), Color.Black.setLuminance(.5f), 1f)
+ assertColorWithinTolerance(Color(0xff030303), Color.Black.setLuminance(.75f), 1f)
+ assertColorWithinTolerance(Color(0xff040404), Color.Black.setLuminance(1f), 1f)
+ assertColorWithinTolerance(Color(0xff070707), Color.Black.setLuminance(2f), 1f)
+ assertColorWithinTolerance(Color(0xff0b0b0b), Color.Black.setLuminance(3f), 1f)
+ assertColorWithinTolerance(Color(0xff0e0e0e), Color.Black.setLuminance(4f), 1f)
+ assertColorWithinTolerance(Color(0xff111111), Color.Black.setLuminance(5f), 1f)
+ assertColorWithinTolerance(Color(0xff131313), Color.Black.setLuminance(6f), 1f)
+ assertColorWithinTolerance(Color(0xff151515), Color.Black.setLuminance(7f), 1f)
+ assertColorWithinTolerance(Color(0xff181818), Color.Black.setLuminance(8f), 1f)
+ assertColorWithinTolerance(Color(0xff191919), Color.Black.setLuminance(9f), 1f)
+ assertColorWithinTolerance(Color(0xff1b1b1b), Color.Black.setLuminance(10f), 1f)
+ assertColorWithinTolerance(Color(0xff303030), Color.Black.setLuminance(20f), 1f)
+ assertColorWithinTolerance(Color(0xff474747), Color.Black.setLuminance(30f), 1f)
+ assertColorWithinTolerance(Color(0xff5e5e5e), Color.Black.setLuminance(40f), 1f)
+ assertColorWithinTolerance(Color(0xff777777), Color.Black.setLuminance(50f), 1f)
+ assertColorWithinTolerance(Color(0xff919191), Color.Black.setLuminance(60f), 1f)
+ assertColorWithinTolerance(Color(0xffababab), Color.Black.setLuminance(70f), 1f)
+ assertColorWithinTolerance(Color(0xffc6c6c6), Color.Black.setLuminance(80f), 1f)
+ assertColorWithinTolerance(Color(0xffe2e2e2), Color.Black.setLuminance(90f), 1f)
+ assertColorWithinTolerance(Color(0xFFF9F9F9), Color.Black.setLuminance(98f), 1f)
+ assertColorWithinTolerance(Color(0xffffffff), Color.Black.setLuminance(99f), 1f)
+ assertColorWithinTolerance(Color(0xffffffff), Color.Black.setLuminance(100f), 1f)
+ }
+
+ @Test
+ fun setLuminance_fromRed() {
+ assertColorWithinTolerance(Color(0xffff0000), Color.Red.setLuminance(53f), 1f)
+ assertColorWithinTolerance(Color(0xFF5B0000), Color.Red.setLuminance(0f), 1f)
+ assertColorWithinTolerance(Color(0xFF5C0000), Color.Red.setLuminance(.25f), 1f)
+ assertColorWithinTolerance(Color(0xFF5C0000), Color.Red.setLuminance(.5f), 1f)
+ assertColorWithinTolerance(Color(0xFF5D0000), Color.Red.setLuminance(.75f), 1f)
+ assertColorWithinTolerance(Color(0xFF5D0000), Color.Red.setLuminance(1f), 1f)
+ assertColorWithinTolerance(Color(0xFF5F0000), Color.Red.setLuminance(2f), 1f)
+ assertColorWithinTolerance(Color(0xFF620000), Color.Red.setLuminance(3f), 1f)
+ assertColorWithinTolerance(Color(0xFF640000), Color.Red.setLuminance(4f), 1f)
+ assertColorWithinTolerance(Color(0xFF670000), Color.Red.setLuminance(5f), 1f)
+ assertColorWithinTolerance(Color(0xFF690000), Color.Red.setLuminance(6f), 1f)
+ assertColorWithinTolerance(Color(0xFF6C0000), Color.Red.setLuminance(7f), 1f)
+ assertColorWithinTolerance(Color(0xFF6E0000), Color.Red.setLuminance(8f), 1f)
+ assertColorWithinTolerance(Color(0xFF710000), Color.Red.setLuminance(9f), 1f)
+ assertColorWithinTolerance(Color(0xFF740000), Color.Red.setLuminance(10f), 1f)
+ assertColorWithinTolerance(Color(0xFF920000), Color.Red.setLuminance(20f), 1f)
+ assertColorWithinTolerance(Color(0xFFB10000), Color.Red.setLuminance(30f), 1f)
+ assertColorWithinTolerance(Color(0xFFD20000), Color.Red.setLuminance(40f), 1f)
+ assertColorWithinTolerance(Color(0xFFF40000), Color.Red.setLuminance(50f), 1f)
+ assertColorWithinTolerance(Color(0xFFFF3017), Color.Red.setLuminance(60f), 1f)
+ assertColorWithinTolerance(Color(0xFFFF5632), Color.Red.setLuminance(70f), 1f)
+ assertColorWithinTolerance(Color(0xFFFF764C), Color.Red.setLuminance(80f), 1f)
+ assertColorWithinTolerance(Color(0xFFFF9566), Color.Red.setLuminance(90f), 1f)
+ assertColorWithinTolerance(Color(0xFFFFAD7B), Color.Red.setLuminance(98f), 1f)
+ assertColorWithinTolerance(Color(0xFFFFB07D), Color.Red.setLuminance(99f), 1f)
+ assertColorWithinTolerance(Color(0xFFFFB380), Color.Red.setLuminance(100f), 1f)
+ }
+
+ @Test
+ fun setLuminance_fromGreen() {
+ assertColorWithinTolerance(Color(0xFF00FC00), Color.Green.setLuminance(86f), 1f)
+ assertColorWithinTolerance(Color(0xFF002400), Color.Green.setLuminance(0f), 1f)
+ assertColorWithinTolerance(Color(0xFF002500), Color.Green.setLuminance(.25f), 1f)
+ assertColorWithinTolerance(Color(0xFF002500), Color.Green.setLuminance(.5f), 1f)
+ assertColorWithinTolerance(Color(0xFF002500), Color.Green.setLuminance(.75f), 1f)
+ assertColorWithinTolerance(Color(0xFF002500), Color.Green.setLuminance(1f), 1f)
+ assertColorWithinTolerance(Color(0xFF002700), Color.Green.setLuminance(2f), 1f)
+ assertColorWithinTolerance(Color(0xFF002800), Color.Green.setLuminance(3f), 1f)
+ assertColorWithinTolerance(Color(0xFF002900), Color.Green.setLuminance(4f), 1f)
+ assertColorWithinTolerance(Color(0xFF002A00), Color.Green.setLuminance(5f), 1f)
+ assertColorWithinTolerance(Color(0xFF002B00), Color.Green.setLuminance(6f), 1f)
+ assertColorWithinTolerance(Color(0xFF002C00), Color.Green.setLuminance(7f), 1f)
+ assertColorWithinTolerance(Color(0xFF002D00), Color.Green.setLuminance(8f), 1f)
+ assertColorWithinTolerance(Color(0xFF002E00), Color.Green.setLuminance(9f), 1f)
+ assertColorWithinTolerance(Color(0xFF003000), Color.Green.setLuminance(10f), 1f)
+ assertColorWithinTolerance(Color(0xFF004200), Color.Green.setLuminance(20f), 1f)
+ assertColorWithinTolerance(Color(0xFF005B00), Color.Green.setLuminance(30f), 1f)
+ assertColorWithinTolerance(Color(0xFF007600), Color.Green.setLuminance(40f), 1f)
+ assertColorWithinTolerance(Color(0xFF009200), Color.Green.setLuminance(50f), 1f)
+ assertColorWithinTolerance(Color(0xFF00AE00), Color.Green.setLuminance(60f), 1f)
+ assertColorWithinTolerance(Color(0xFF00CB00), Color.Green.setLuminance(70f), 1f)
+ assertColorWithinTolerance(Color(0xFF00E800), Color.Green.setLuminance(80f), 1f)
+ assertColorWithinTolerance(Color(0xFF29FF1C), Color.Green.setLuminance(90f), 1f)
+ assertColorWithinTolerance(Color(0xFF54FF3E), Color.Green.setLuminance(98f), 1f)
+ assertColorWithinTolerance(Color(0xFF58FF42), Color.Green.setLuminance(99f), 1f)
+ assertColorWithinTolerance(Color(0xFF5DFF45), Color.Green.setLuminance(100f), 1f)
+ }
+
+ @Test
+ fun setLuminance_fromBlue() {
+ assertColorWithinTolerance(Color(0xFF0000FF), Color.Blue.setLuminance(32f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000A2), Color.Blue.setLuminance(0f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000A2), Color.Blue.setLuminance(.25f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000A3), Color.Blue.setLuminance(.5f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000A4), Color.Blue.setLuminance(.75f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000A4), Color.Blue.setLuminance(1f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000A7), Color.Blue.setLuminance(2f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000AA), Color.Blue.setLuminance(3f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000AD), Color.Blue.setLuminance(4f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000AF), Color.Blue.setLuminance(5f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000B2), Color.Blue.setLuminance(6f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000B5), Color.Blue.setLuminance(7f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000B8), Color.Blue.setLuminance(8f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000BB), Color.Blue.setLuminance(9f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000BE), Color.Blue.setLuminance(10f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000DB), Color.Blue.setLuminance(20f), 1f)
+ assertColorWithinTolerance(Color(0xFF0000F8), Color.Blue.setLuminance(30f), 1f)
+ assertColorWithinTolerance(Color(0xFF4523FF), Color.Blue.setLuminance(40f), 1f)
+ assertColorWithinTolerance(Color(0xFF7041FF), Color.Blue.setLuminance(50f), 1f)
+ assertColorWithinTolerance(Color(0xFF955DFF), Color.Blue.setLuminance(60f), 1f)
+ assertColorWithinTolerance(Color(0xFFB878FF), Color.Blue.setLuminance(70f), 1f)
+ assertColorWithinTolerance(Color(0xFFD994FF), Color.Blue.setLuminance(80f), 1f)
+ assertColorWithinTolerance(Color(0xFFFAB0FF), Color.Blue.setLuminance(90f), 1f)
+ assertColorWithinTolerance(Color(0xFFFFC7FF), Color.Blue.setLuminance(98f), 1f)
+ assertColorWithinTolerance(Color(0xFFFFCAFF), Color.Blue.setLuminance(99f), 1f)
+ assertColorWithinTolerance(Color(0xFFFFCDFF), Color.Blue.setLuminance(100f), 1f)
+ }
+
+ private fun assertColorWithinTolerance(expected: Color, actual: Color, tolerance: Float = 1f) {
+ assertThat(expected.red).isWithin(tolerance).of(actual.red)
+ assertThat(expected.green).isWithin(tolerance).of(actual.green)
+ assertThat(expected.blue).isWithin(tolerance).of(actual.blue)
+ assertThat(expected.alpha).isWithin(tolerance).of(actual.alpha)
+ }
+}
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ExposedDropdownMenuTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ExposedDropdownMenuTest.kt
index d6d9c74..9ea4779 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ExposedDropdownMenuTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ExposedDropdownMenuTest.kt
@@ -43,6 +43,7 @@
import androidx.compose.ui.test.assertIsFocused
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertTextContains
+import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
@@ -156,7 +157,10 @@
rule.waitForIdle()
}
- rule.onNodeWithTag(TFTag).assertTextContains("zzz")
+ val matcher = hasText("zzz")
+ rule.waitUntil {
+ matcher.matches(rule.onNodeWithTag(TFTag).fetchSemanticsNode())
+ }
rule.onNodeWithTag(MenuItemTag).assertIsDisplayed()
}
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt
index 2e24706..a4d3e16 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt
@@ -67,6 +67,8 @@
"fugiat nulla pariatur."
)
+ private val platformTextStyle = defaultPlatformTextStyle()
+
@get:Rule
val rule = createComposeRule()
@@ -494,7 +496,10 @@
value = TextFieldValue(text = text, selection = TextRange(text.length)),
onValueChange = {},
modifier = Modifier.width(300.dp).testTag(TextFieldTag),
- textStyle = TextStyle(textAlign = TextAlign.Center),
+ textStyle = TextStyle(
+ textAlign = TextAlign.Center,
+ platformStyle = platformTextStyle
+ ),
singleLine = true
)
}
@@ -510,7 +515,7 @@
value = TextFieldValue(text = text, selection = TextRange(text.length)),
onValueChange = {},
modifier = Modifier.fillMaxWidth().testTag(TextFieldTag),
- textStyle = TextStyle(textAlign = TextAlign.End),
+ textStyle = TextStyle(textAlign = TextAlign.End, platformStyle = platformTextStyle),
singleLine = true
)
}
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SearchBarScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SearchBarScreenshotTest.kt
index 79da314..46ec30c 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SearchBarScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SearchBarScreenshotTest.kt
@@ -140,6 +140,41 @@
}
@Test
+ fun searchBar_shadow_inactive() {
+ rule.setMaterialContent(lightColorScheme()) {
+ SearchBar(
+ modifier = Modifier.testTag(testTag),
+ query = "",
+ onQueryChange = {},
+ onSearch = {},
+ active = false,
+ onActiveChange = {},
+ placeholder = { Text("Hint") },
+ shadowElevation = 6.dp,
+ content = {},
+ )
+ }
+ assertAgainstGolden("searchBar_shadow_inactive")
+ }
+
+ @Test
+ fun searchBar_shadow_active() {
+ rule.setMaterialContent(lightColorScheme()) {
+ SearchBar(
+ modifier = Modifier.testTag(testTag),
+ query = "Query",
+ onQueryChange = {},
+ onSearch = {},
+ active = true,
+ onActiveChange = {},
+ shadowElevation = 6.dp,
+ content = { Text("Content") },
+ )
+ }
+ assertAgainstGolden("searchBar_shadow_active")
+ }
+
+ @Test
fun dockedSearchBar_inactive() {
rule.setMaterialContent(scheme.colorScheme) {
DockedSearchBar(
@@ -245,6 +280,41 @@
assertAgainstGolden("dockedSearchBar_active_customColors")
}
+ @Test
+ fun dockedSearchBar_shadow_inactive() {
+ rule.setMaterialContent(lightColorScheme()) {
+ DockedSearchBar(
+ modifier = Modifier.testTag(testTag),
+ query = "",
+ onQueryChange = {},
+ onSearch = {},
+ active = false,
+ onActiveChange = {},
+ placeholder = { Text("Hint") },
+ shadowElevation = 6.dp,
+ content = {},
+ )
+ }
+ assertAgainstGolden("dockedSearchBar_shadow_inactive")
+ }
+
+ @Test
+ fun dockedSearchBar_shadow_active() {
+ rule.setMaterialContent(lightColorScheme()) {
+ DockedSearchBar(
+ modifier = Modifier.testTag(testTag),
+ query = "Query",
+ onQueryChange = {},
+ onSearch = {},
+ active = true,
+ onActiveChange = {},
+ shadowElevation = 6.dp,
+ content = { Text("Content") },
+ )
+ }
+ assertAgainstGolden("dockedSearchBar_shadow_active")
+ }
+
private fun assertAgainstGolden(goldenName: String) {
rule.onNodeWithTag(testTag)
.captureToImage()
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SurfaceTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SurfaceTest.kt
index ee15530..a57c7a1 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SurfaceTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SurfaceTest.kt
@@ -66,7 +66,6 @@
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import org.junit.Rule
import org.junit.Test
@@ -132,7 +131,10 @@
Box(Modifier.fillMaxSize())
}
surfaceTonalColor =
- MaterialTheme.colorScheme.surfaceColorAtElevation(absoluteTonalElevation)
+ MaterialTheme.colorScheme.applyTonalElevation(
+ backgroundColor = surfaceColor,
+ elevation = absoluteTonalElevation
+ )
}
}
@@ -152,6 +154,49 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
+ fun noTonalElevationColorIsSetOnElevatedSurfaceColor_tonalElevationDisabled() {
+ var absoluteTonalElevation: Dp = 0.dp
+ var surfaceTonalColor: Color = Color.Unspecified
+ var surfaceColor: Color = Color.Unspecified
+ rule.setMaterialContent(lightColorScheme()) {
+ CompositionLocalProvider(LocalTonalElevationEnabled provides false) {
+ surfaceColor = MaterialTheme.colorScheme.surface
+ Box(
+ Modifier
+ .size(10.dp, 10.dp)
+ .semantics(mergeDescendants = true) {}
+ .testTag("box")
+ ) {
+ Surface(color = surfaceColor, tonalElevation = 2.dp) {
+ absoluteTonalElevation = LocalAbsoluteTonalElevation.current
+ Box(Modifier.fillMaxSize())
+ }
+ surfaceTonalColor =
+ MaterialTheme.colorScheme.applyTonalElevation(
+ backgroundColor = surfaceColor,
+ elevation = absoluteTonalElevation
+ )
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ Truth.assertThat(absoluteTonalElevation).isEqualTo(2.dp)
+ Truth.assertThat(surfaceColor).isEqualTo(surfaceTonalColor)
+ }
+
+ rule.onNodeWithTag("box")
+ .captureToImage()
+ .assertShape(
+ density = rule.density,
+ shape = RectangleShape,
+ shapeColor = surfaceTonalColor,
+ backgroundColor = Color.White
+ )
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
fun tonalElevationColorIsNotSetOnNonSurfaceColor() {
var absoluteTonalElevation: Dp = 0.dp
rule.setMaterialContent(lightColorScheme()) {
@@ -214,7 +259,9 @@
.testTag("top level")
) {
Surface(
- Modifier.fillMaxSize().padding(0.dp),
+ Modifier
+ .fillMaxSize()
+ .padding(0.dp),
tonalElevation = 2.dp,
shadowElevation = 2.dp,
color = Color.Blue,
@@ -234,7 +281,9 @@
.testTag("nested")
) {
Surface(
- Modifier.fillMaxSize().padding(0.dp),
+ Modifier
+ .fillMaxSize()
+ .padding(0.dp),
tonalElevation = 0.dp,
shadowElevation = 2.dp,
color = Color.Blue,
@@ -309,7 +358,9 @@
rule.setMaterialContent(lightColorScheme()) {
Surface(
onClick = { count.value += 1 },
- modifier = Modifier.semantics { role = Role.Checkbox }.testTag("surface"),
+ modifier = Modifier
+ .semantics { role = Role.Checkbox }
+ .testTag("surface"),
) {
Text("${count.value}")
Spacer(Modifier.size(30.dp))
@@ -387,7 +438,8 @@
val interactionSource = MutableInteractionSource()
rule.setMaterialContent(lightColorScheme()) {
Surface(
- modifier = Modifier.testTag("surface")
+ modifier = Modifier
+ .testTag("surface")
.clickable(
interactionSource = interactionSource,
indication = null,
@@ -471,11 +523,15 @@
rule.setContent {
Box(Modifier.fillMaxSize()) {
Button(
- modifier = Modifier.fillMaxSize().testTag("clickable"),
+ modifier = Modifier
+ .fillMaxSize()
+ .testTag("clickable"),
onClick = { state.value += 1 }
) { Text("button fullscreen") }
Surface(
- Modifier.fillMaxSize().testTag("surface"),
+ Modifier
+ .fillMaxSize()
+ .testTag("surface"),
) {}
}
}
@@ -514,7 +570,9 @@
Surface(
selected = selected.value,
onClick = { selected.value = !selected.value },
- modifier = Modifier.semantics { role = Role.Switch }.testTag("surface"),
+ modifier = Modifier
+ .semantics { role = Role.Switch }
+ .testTag("surface"),
) {
Text("${selected.value}")
Spacer(Modifier.size(30.dp))
@@ -618,7 +676,9 @@
Surface(
checked = toggled.value,
onCheckedChange = { toggled.value = !toggled.value },
- modifier = Modifier.semantics { role = Role.Tab }.testTag("surface"),
+ modifier = Modifier
+ .semantics { role = Role.Tab }
+ .testTag("surface"),
) {
Text("${toggled.value}")
Spacer(Modifier.size(30.dp))
@@ -699,7 +759,9 @@
rule.setContent {
Box(Modifier.fillMaxSize()) {
Surface(
- Modifier.fillMaxSize().testTag("surface"),
+ Modifier
+ .fillMaxSize()
+ .testTag("surface"),
) {
Box(
Modifier
@@ -709,7 +771,8 @@
awaitEachGesture {
hitTested.value = true
val event = awaitPointerEvent(PointerEventPass.Final)
- Truth.assertThat(event.changes[0].isConsumed)
+ Truth
+ .assertThat(event.changes[0].isConsumed)
.isFalse()
}
}
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt
index 7d39a04..927f5fb 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt
@@ -67,6 +67,8 @@
"fugiat nulla pariatur."
)
+ private val platformTextStyle = defaultPlatformTextStyle()
+
@get:Rule
val rule = createComposeRule()
@@ -500,7 +502,10 @@
value = TextFieldValue(text = text, selection = TextRange(text.length)),
onValueChange = {},
modifier = Modifier.width(300.dp).testTag(TextFieldTag),
- textStyle = TextStyle(textAlign = TextAlign.Center),
+ textStyle = TextStyle(
+ textAlign = TextAlign.Center,
+ platformStyle = platformTextStyle
+ ),
singleLine = true
)
}
@@ -516,7 +521,7 @@
value = TextFieldValue(text = text, selection = TextRange(text.length)),
onValueChange = {},
modifier = Modifier.fillMaxWidth().testTag(TextFieldTag),
- textStyle = TextStyle(textAlign = TextAlign.End),
+ textStyle = TextStyle(textAlign = TextAlign.End, platformStyle = platformTextStyle),
singleLine = true
)
}
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextTest.kt
index a945ab4..f19952b 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextTest.kt
@@ -17,14 +17,17 @@
package androidx.compose.material3
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.SemanticsActions
-import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontStyle
@@ -34,7 +37,7 @@
import androidx.compose.ui.unit.sp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
-import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -57,6 +60,26 @@
private val TestText = "TestText"
@Test
+ fun testDefaultIncludeFontPadding() {
+ var localTextStyle: TextStyle? = null
+ var displayMediumTextStyle: TextStyle? = null
+ rule.setContent {
+ MaterialTheme {
+ localTextStyle = LocalTextStyle.current
+ displayMediumTextStyle = LocalTypography.current.displayMedium
+ }
+ }
+
+ assertThat(
+ localTextStyle?.platformStyle?.paragraphStyle?.includeFontPadding
+ ).isEqualTo(false)
+
+ assertThat(
+ displayMediumTextStyle?.platformStyle?.paragraphStyle?.includeFontPadding
+ ).isEqualTo(false)
+ }
+
+ @Test
fun inheritsThemeTextStyle() {
var textColor: Color? = null
var textAlign: TextAlign? = null
@@ -81,11 +104,11 @@
}
rule.runOnIdle {
- Truth.assertThat(textColor).isEqualTo(ExpectedTextStyle.color)
- Truth.assertThat(textAlign).isEqualTo(ExpectedTextStyle.textAlign)
- Truth.assertThat(fontSize).isEqualTo(ExpectedTextStyle.fontSize)
- Truth.assertThat(fontStyle).isEqualTo(ExpectedTextStyle.fontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(ExpectedTextStyle.letterSpacing)
+ assertThat(textColor).isEqualTo(ExpectedTextStyle.color)
+ assertThat(textAlign).isEqualTo(ExpectedTextStyle.textAlign)
+ assertThat(fontSize).isEqualTo(ExpectedTextStyle.fontSize)
+ assertThat(fontStyle).isEqualTo(ExpectedTextStyle.fontStyle)
+ assertThat(letterSpacing).isEqualTo(ExpectedTextStyle.letterSpacing)
}
}
@@ -122,11 +145,11 @@
}
rule.runOnIdle {
- Truth.assertThat(textColor).isEqualTo(testStyle.color)
- Truth.assertThat(textAlign).isEqualTo(testStyle.textAlign)
- Truth.assertThat(fontSize).isEqualTo(testStyle.fontSize)
- Truth.assertThat(fontStyle).isEqualTo(testStyle.fontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(testStyle.letterSpacing)
+ assertThat(textColor).isEqualTo(testStyle.color)
+ assertThat(textAlign).isEqualTo(testStyle.textAlign)
+ assertThat(fontSize).isEqualTo(testStyle.fontSize)
+ assertThat(fontStyle).isEqualTo(testStyle.fontStyle)
+ assertThat(letterSpacing).isEqualTo(testStyle.letterSpacing)
}
}
@@ -167,11 +190,11 @@
rule.runOnIdle {
// explicit parameters should override values from the style.
- Truth.assertThat(textColor).isEqualTo(expectedColor)
- Truth.assertThat(textAlign).isEqualTo(expectedTextAlign)
- Truth.assertThat(fontSize).isEqualTo(expectedFontSize)
- Truth.assertThat(fontStyle).isEqualTo(expectedFontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
+ assertThat(textColor).isEqualTo(expectedColor)
+ assertThat(textAlign).isEqualTo(expectedTextAlign)
+ assertThat(fontSize).isEqualTo(expectedFontSize)
+ assertThat(fontStyle).isEqualTo(expectedFontStyle)
+ assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
}
}
@@ -214,11 +237,11 @@
rule.runOnIdle {
// explicit parameters should override values from the style.
- Truth.assertThat(textColor).isEqualTo(expectedColor)
- Truth.assertThat(textAlign).isEqualTo(expectedTextAlign)
- Truth.assertThat(fontSize).isEqualTo(expectedFontSize)
- Truth.assertThat(fontStyle).isEqualTo(expectedFontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
+ assertThat(textColor).isEqualTo(expectedColor)
+ assertThat(textAlign).isEqualTo(expectedTextAlign)
+ assertThat(fontSize).isEqualTo(expectedFontSize)
+ assertThat(fontStyle).isEqualTo(expectedFontStyle)
+ assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
}
}
@@ -235,10 +258,72 @@
}
}
+ val textLayoutResults = getTextLayoutResults("text")
+ assert(textLayoutResults != null) { "TextLayoutResult is null" }
+ }
+
+ @Test
+ fun testContentColorChangeVisibleInSemantics() {
+ var switchColor by mutableStateOf(false)
+ rule.setContent {
+ MaterialTheme {
+ val color = if (switchColor) {
+ MaterialTheme.colorScheme.surface
+ } else {
+ MaterialTheme.colorScheme.secondary
+ }
+ Surface(color = color) {
+ Text(
+ TestText,
+ modifier = Modifier.testTag("text")
+ )
+ }
+ }
+ }
+
+ val textLayoutResults = getTextLayoutResults("text")
+ switchColor = true
+ rule.waitForIdle()
+ val textLayoutResults2 = getTextLayoutResults("text")
+
+ assertThat(textLayoutResults2?.layoutInput?.style?.color).isNotNull()
+ assertThat(textLayoutResults2?.layoutInput?.style?.color)
+ .isNotEqualTo(textLayoutResults?.layoutInput?.style?.color)
+ }
+
+ @Test
+ fun testContentColorChangeVisibleInSemantics_annotatedString() {
+ var switchColor by mutableStateOf(false)
+ rule.setContent {
+ MaterialTheme {
+ val color = if (switchColor) {
+ MaterialTheme.colorScheme.surface
+ } else {
+ MaterialTheme.colorScheme.secondary
+ }
+ Surface(color = color) {
+ Text(
+ AnnotatedString(TestText),
+ modifier = Modifier.testTag("text")
+ )
+ }
+ }
+ }
+
+ val textLayoutResults = getTextLayoutResults("text")
+ switchColor = true
+ rule.waitForIdle()
+ val textLayoutResults2 = getTextLayoutResults("text")
+
+ assertThat(textLayoutResults2?.layoutInput?.style?.color).isNotNull()
+ assertThat(textLayoutResults2?.layoutInput?.style?.color)
+ .isNotEqualTo(textLayoutResults?.layoutInput?.style?.color)
+ }
+
+ private fun getTextLayoutResults(tag: String): TextLayoutResult? {
val textLayoutResults = mutableListOf<TextLayoutResult>()
- rule.onNodeWithTag("text")
- .assertTextEquals(TestText)
+ rule.onNodeWithTag(tag)
.performSemanticsAction(SemanticsActions.GetTextLayoutResult) { it(textLayoutResults) }
- assert(textLayoutResults.size == 1) { "TextLayoutResult is null" }
+ return textLayoutResults.firstOrNull()
}
}
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/CalendarModel.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/CalendarModel.android.kt
index e4fe3ed..da51b9f 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/CalendarModel.android.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/CalendarModel.android.kt
@@ -18,11 +18,6 @@
import android.os.Build
import android.text.format.DateFormat
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.ReadOnlyComposable
-import androidx.compose.ui.platform.LocalConfiguration
-import androidx.core.os.ConfigurationCompat
-import java.util.Locale
/**
* Returns a [CalendarModel] to be used by the date picker.
@@ -47,13 +42,13 @@
*
* @param utcTimeMillis a UTC timestamp to format (milliseconds from epoch)
* @param skeleton a date format skeleton
- * @param locale the [Locale] to use when formatting the given timestamp
+ * @param locale the [CalendarLocale] to use when formatting the given timestamp
*/
@ExperimentalMaterial3Api
actual fun formatWithSkeleton(
utcTimeMillis: Long,
skeleton: String,
- locale: Locale
+ locale: CalendarLocale
): String {
val pattern = DateFormat.getBestDateTimePattern(locale, skeleton)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -62,14 +57,3 @@
LegacyCalendarModelImpl.formatWithPattern(utcTimeMillis, pattern, locale)
}
}
-
-/**
- * A composable function that returns the default [Locale]. It will be recomposed when the
- * `Configuration` gets updated.
- */
-@Composable
-@ReadOnlyComposable
-@ExperimentalMaterial3Api
-internal actual fun defaultLocale(): Locale {
- return ConfigurationCompat.getLocales(LocalConfiguration.current).get(0) ?: Locale.getDefault()
-}
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DefaultPlatformTextStyle.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DefaultPlatformTextStyle.android.kt
index f3ed0e3..d8dcc5c 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DefaultPlatformTextStyle.android.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DefaultPlatformTextStyle.android.kt
@@ -18,7 +18,7 @@
import androidx.compose.ui.text.PlatformTextStyle
-private const val DefaultIncludeFontPadding = true
+private const val DefaultIncludeFontPadding = false
@Suppress("DEPRECATION")
private val DefaultPlatformTextStyle = PlatformTextStyle(
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DynamicTonalPalette.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DynamicTonalPalette.kt
index e5de4b1..231f4d5 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DynamicTonalPalette.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DynamicTonalPalette.kt
@@ -22,6 +22,10 @@
import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.colorspace.ColorSpaces
+import androidx.core.math.MathUtils
+import kotlin.math.pow
+import kotlin.math.roundToInt
/** Dynamic colors in Material. */
@RequiresApi(Build.VERSION_CODES.S)
@@ -29,16 +33,38 @@
// The neutral tonal range from the generated dynamic color palette.
neutral100 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_0),
neutral99 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_10),
+ neutral98 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
+ .setLuminance(98f),
+ neutral96 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
+ .setLuminance(96f),
neutral95 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_50),
+ neutral94 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
+ .setLuminance(94f),
+ neutral92 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
+ .setLuminance(92f),
neutral90 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_100),
+ neutral87 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
+ .setLuminance(87f),
neutral80 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_200),
neutral70 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_300),
neutral60 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_400),
neutral50 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_500),
neutral40 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600),
neutral30 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_700),
+ neutral24 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
+ .setLuminance(24f),
+ neutral22 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
+ .setLuminance(22f),
neutral20 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_800),
+ neutral17 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
+ .setLuminance(17f),
+ neutral12 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
+ .setLuminance(12f),
neutral10 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_900),
+ neutral6 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
+ .setLuminance(6f),
+ neutral4 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600)
+ .setLuminance(4f),
neutral0 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_1000),
// The neutral variant tonal range, sometimes called "neutral 2", from the
@@ -138,6 +164,16 @@
inverseSurface = tonalPalette.neutral20,
inverseOnSurface = tonalPalette.neutral95,
outline = tonalPalette.neutralVariant50,
+ outlineVariant = tonalPalette.neutralVariant80,
+ scrim = tonalPalette.neutral0,
+ surfaceBright = tonalPalette.neutral98,
+ surfaceDim = tonalPalette.neutral87,
+ surfaceContainer = tonalPalette.neutral94,
+ surfaceContainerHigh = tonalPalette.neutral92,
+ surfaceContainerHighest = tonalPalette.neutral90,
+ surfaceContainerLow = tonalPalette.neutral96,
+ surfaceContainerLowest = tonalPalette.neutral100,
+ surfaceTint = tonalPalette.primary40,
)
}
@@ -176,6 +212,16 @@
inverseSurface = tonalPalette.neutral90,
inverseOnSurface = tonalPalette.neutral20,
outline = tonalPalette.neutralVariant60,
+ outlineVariant = tonalPalette.neutral30,
+ scrim = tonalPalette.neutral0,
+ surfaceBright = tonalPalette.neutral24,
+ surfaceDim = tonalPalette.neutral6,
+ surfaceContainer = tonalPalette.neutral12,
+ surfaceContainerHigh = tonalPalette.neutral17,
+ surfaceContainerHighest = tonalPalette.neutral22,
+ surfaceContainerLow = tonalPalette.neutral10,
+ surfaceContainerLowest = tonalPalette.neutral4,
+ surfaceTint = tonalPalette.primary80,
)
}
@@ -186,3 +232,66 @@
return Color(context.resources.getColor(id, context.theme))
}
}
+
+/**
+ * Set the luminance(tone) of this color. Chroma may decrease because chroma has a different maximum
+ * for any given hue and luminance.
+ *
+ * @param newLuminance 0 <= newLuminance <= 100; invalid values are corrected.
+ */
+internal fun Color.setLuminance(
+ /*@FloatRange(from = 0.0, to = 100.0)*/
+ newLuminance: Float
+): Color {
+ if ((newLuminance < 0.0001) or (newLuminance > 99.9999)) {
+ // aRGBFromLstar() from monet ColorUtil.java
+ val y = 100 * labInvf((newLuminance + 16) / 116)
+ println("y: $y")
+ val component = delinearized(y)
+ println("component: $component")
+
+ return Color(
+ /* red = */component,
+ /* green = */component,
+ /* blue = */component,
+ )
+ }
+
+ val sLAB = this.convert(ColorSpaces.CieLab)
+ return Color(
+ /* luminance = */newLuminance,
+ /* a = */sLAB.component2(),
+ /* b = */sLAB.component3(),
+ colorSpace = ColorSpaces.CieLab
+ ).convert(ColorSpaces.Srgb)
+}
+
+/** Helper method from monet ColorUtils.java */
+private fun labInvf(ft: Float): Float {
+ val e = 216f / 24389f
+ val kappa = 24389f / 27f
+ val ft3 = ft * ft * ft
+ return if (ft3 > e) {
+ ft3
+ } else {
+ (116 * ft - 16) / kappa
+ }
+}
+
+/**
+ * Helper method from monet ColorUtils.java
+ *
+ * Delinearizes an RGB component.
+ *
+ * @param rgbComponent 0.0 <= rgb_component <= 100.0, represents linear R/G/B channel
+ * @return 0 <= output <= 255, color channel converted to regular RGB space
+ */
+private fun delinearized(rgbComponent: Float): Int {
+ val normalized = rgbComponent / 100
+ val delinearized = if (normalized <= 0.0031308) {
+ normalized * 12.92
+ } else {
+ 1.055 * normalized.toDouble().pow(1.0 / 2.4) - 0.055
+ }
+ return MathUtils.clamp((delinearized * 255.0).roundToInt(), 0, 255)
+}
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/SearchBar.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/SearchBar.kt
index 67b3345..8b84f83 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/SearchBar.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/SearchBar.kt
@@ -53,6 +53,7 @@
import androidx.compose.foundation.text.selection.LocalTextSelectionColors
import androidx.compose.foundation.text.selection.TextSelectionColors
import androidx.compose.material3.SearchBarDefaults.InputFieldHeight
+import androidx.compose.material3.tokens.ElevationTokens
import androidx.compose.material3.tokens.FilledTextFieldTokens
import androidx.compose.material3.tokens.MotionTokens
import androidx.compose.material3.tokens.SearchBarTokens
@@ -149,6 +150,7 @@
* translucent primary color overlay is applied on top of the container. A higher tonal elevation
* value will result in a darker color in light theme and lighter color in dark theme. See also:
* [Surface].
+ * @param shadowElevation the elevation for the shadow below the search bar
* @param windowInsets the window insets that the search bar will respect
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this search bar. You can create and pass in your own `remember`ed instance to observe
@@ -170,7 +172,8 @@
trailingIcon: @Composable (() -> Unit)? = null,
shape: Shape = SearchBarDefaults.inputFieldShape,
colors: SearchBarColors = SearchBarDefaults.colors(),
- tonalElevation: Dp = SearchBarDefaults.Elevation,
+ tonalElevation: Dp = SearchBarDefaults.TonalElevation,
+ shadowElevation: Dp = SearchBarDefaults.ShadowElevation,
windowInsets: WindowInsets = SearchBarDefaults.windowInsets,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable ColumnScope.() -> Unit,
@@ -221,6 +224,7 @@
color = colors.containerColor,
contentColor = contentColorFor(colors.containerColor),
tonalElevation = tonalElevation,
+ shadowElevation = shadowElevation,
modifier = modifier
.zIndex(1f)
.onConsumedWindowInsetsChanged { consumedInsets ->
@@ -333,6 +337,7 @@
* translucent primary color overlay is applied on top of the container. A higher tonal elevation
* value will result in a darker color in light theme and lighter color in dark theme. See also:
* [Surface].
+ * @param shadowElevation the elevation for the shadow below the search bar
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this search bar. You can create and pass in your own `remember`ed instance to observe
* [Interaction]s and customize the appearance / behavior of this search bar in different states.
@@ -353,7 +358,8 @@
trailingIcon: @Composable (() -> Unit)? = null,
shape: Shape = SearchBarDefaults.dockedShape,
colors: SearchBarColors = SearchBarDefaults.colors(),
- tonalElevation: Dp = SearchBarDefaults.Elevation,
+ tonalElevation: Dp = SearchBarDefaults.TonalElevation,
+ shadowElevation: Dp = SearchBarDefaults.ShadowElevation,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable ColumnScope.() -> Unit,
) {
@@ -364,6 +370,7 @@
color = colors.containerColor,
contentColor = contentColorFor(colors.containerColor),
tonalElevation = tonalElevation,
+ shadowElevation = shadowElevation,
modifier = modifier
.zIndex(1f)
.width(SearchBarMinWidth)
@@ -495,8 +502,18 @@
*/
@ExperimentalMaterial3Api
object SearchBarDefaults {
- /** Default elevation for a search bar. */
- val Elevation: Dp = SearchBarTokens.ContainerElevation
+ /** Default tonal elevation for a search bar. */
+ val TonalElevation: Dp = SearchBarTokens.ContainerElevation
+
+ /** Default shadow elevation for a search bar. */
+ val ShadowElevation: Dp = ElevationTokens.Level0
+
+ @Deprecated(
+ message = "Renamed to TonalElevation. Not to be confused with ShadowElevation.",
+ replaceWith = ReplaceWith("TonalElevation"),
+ level = DeprecationLevel.WARNING,
+ )
+ val Elevation: Dp = TonalElevation
/** Default height for a search bar's input field, or a search bar in the inactive state. */
val InputFieldHeight: Dp = SearchBarTokens.ContainerHeight
diff --git a/compose/material3/material3/src/androidMain/res/values-ar/strings.xml b/compose/material3/material3/src/androidMain/res/values-ar/strings.xml
index 473b9ee..135a7a1 100644
--- a/compose/material3/material3/src/androidMain/res/values-ar/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ar/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"في النطاق"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"إدخال التواريخ"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"إدخال نطاق زمني غير صالح"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"بطاقة سفلية"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"مقبض السحب"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"تصغير البطاقة السفلية"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"إغلاق البطاقة السفلية"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-as/strings.xml b/compose/material3/material3/src/androidMain/res/values-as/strings.xml
index 8613356..a2d7236 100644
--- a/compose/material3/material3/src/androidMain/res/values-as/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-as/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"পৰিসৰৰ ভিতৰত আছে"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"তাৰিখ দিয়ক"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"অমান্য তাৰিখৰ পৰিসৰৰ ইনপুট"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"তলৰ শ্বীট"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"ড্ৰেগ হেণ্ডেল"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"তলৰ শ্বীটখন সংকোচন কৰক"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"তলৰ শ্বীটখন অগ্ৰাহ্য কৰক"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-az/strings.xml b/compose/material3/material3/src/androidMain/res/values-az/strings.xml
index ffd5a79..61f1619 100644
--- a/compose/material3/material3/src/androidMain/res/values-az/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-az/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Bu aralıqda"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Tarixlər daxil edin"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Yanlış tarix aralığı daxiletməsi"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Aşağıdakı vərəq"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Dəstəyi çəkin"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Aşağıdakı vərəqi yığcamlaşdırın"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Aşağıdakı vərəqi rədd edin"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-be/strings.xml b/compose/material3/material3/src/androidMain/res/values-be/strings.xml
index 09ba25c..f79e60a 100644
--- a/compose/material3/material3/src/androidMain/res/values-be/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-be/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"У межах дыяпазону"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Увядзіце даты"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Уведзены няправільны дыяпазон дат"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Ніжні аркуш"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Маркер перацягвання"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Згарнуць ніжні аркуш"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Закрыць ніжні аркуш"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-bg/strings.xml b/compose/material3/material3/src/androidMain/res/values-bg/strings.xml
index d8ae5c8..7867bad 100644
--- a/compose/material3/material3/src/androidMain/res/values-bg/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-bg/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"В диапазона"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Въвеждане на дати"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Въведен е невалиден период от време"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Долен лист"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Манипулатор за преместване с плъзгане"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Свиване на долния лист"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Отхвърляне на долния лист"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-bn/strings.xml b/compose/material3/material3/src/androidMain/res/values-bn/strings.xml
index 78b8edb..bf4f5ed 100644
--- a/compose/material3/material3/src/androidMain/res/values-bn/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-bn/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"সীমার মধ্যে"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"তারিখ লিখুন"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"তারিখের ব্যাপ্তি সম্পর্কিত ইনপুট ভুল দেওয়া আছে"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"স্ক্রিনের নিচে অ্যাটাচ করা শিট"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"টেনে আনার হ্যান্ডেল"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"স্ক্রিনের নিচে অ্যাটাচ করা শিট আড়াল করুন"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"স্ক্রিনের নিচে অ্যাটাচ করা শিট বাতিল করুন"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ca/strings.xml b/compose/material3/material3/src/androidMain/res/values-ca/strings.xml
index c186bcf..3aa3804 100644
--- a/compose/material3/material3/src/androidMain/res/values-ca/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ca/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Dins de l\'interval"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Introdueix les dates"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"S\'ha introduït un interval de dates no vàlid"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Full inferior"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Ansa per arrossegar"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Replega el full inferior"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Ignora el full inferior"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-da/strings.xml b/compose/material3/material3/src/androidMain/res/values-da/strings.xml
index 3e5f09c..0e6512b 100644
--- a/compose/material3/material3/src/androidMain/res/values-da/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-da/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Inden for de valgte dage"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Angiv datoer"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Det angivne datointerval er ugyldigt"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Felt i bunden"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Håndtag"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Skjul felt i bunden"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Luk felt i bunden"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml b/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml
index bd8c434..6e371c5 100644
--- a/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"In range"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Enter dates"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Invalid date range input"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Bottom sheet"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Drag handle"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Collapse bottom sheet"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Dismiss bottom sheet"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml b/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml
index bd8c434..6e371c5 100644
--- a/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"In range"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Enter dates"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Invalid date range input"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Bottom sheet"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Drag handle"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Collapse bottom sheet"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Dismiss bottom sheet"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml b/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml
index bd8c434..6e371c5 100644
--- a/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"In range"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Enter dates"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Invalid date range input"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Bottom sheet"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Drag handle"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Collapse bottom sheet"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Dismiss bottom sheet"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-es/strings.xml b/compose/material3/material3/src/androidMain/res/values-es/strings.xml
index 212a0c2..6a0edbd 100644
--- a/compose/material3/material3/src/androidMain/res/values-es/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-es/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Dentro del intervalo"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Introducir fechas"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"El intervalo de fechas no es válido"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Hoja inferior"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Controlador de arrastre"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Contrae la hoja inferior"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Cierra la hoja inferior"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-et/strings.xml b/compose/material3/material3/src/androidMain/res/values-et/strings.xml
index a3c0edf..ac7c8f0 100644
--- a/compose/material3/material3/src/androidMain/res/values-et/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-et/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Vahemikus"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Sisestage kuupäevad"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Sisestati sobimatu kuupäevavahemik"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Alumine leht"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Lohistamispide"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Alumise lehe ahendamine"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Alumisest lehest loobumine"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-eu/strings.xml b/compose/material3/material3/src/androidMain/res/values-eu/strings.xml
index d8e2674..890afc8 100644
--- a/compose/material3/material3/src/androidMain/res/values-eu/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-eu/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Barrutian"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Idatzi datak"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Idatzitako data tarteak ez du balio"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Pantailaren behealdean ainguratutako orria"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Arrastatzeko kontrol-puntua"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Tolestu pantailaren behealdean ainguratutako orria"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Baztertu pantailaren behealdean ainguratutako orria"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-fi/strings.xml b/compose/material3/material3/src/androidMain/res/values-fi/strings.xml
index 21bb3d0..044bc71 100644
--- a/compose/material3/material3/src/androidMain/res/values-fi/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-fi/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Valitulla välillä"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Lisää päivämäärät"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Virheellinen ajanjakso"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Alapaneeli"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Vetokahva"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Tiivistä alapaneeli"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Hylkää alapaneeli"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-fr/strings.xml b/compose/material3/material3/src/androidMain/res/values-fr/strings.xml
index 16c33c6..966933c 100644
--- a/compose/material3/material3/src/androidMain/res/values-fr/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-fr/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Dans la plage"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Saisir des dates"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Plage de dates non valide"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Bottom sheet"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Poignée de déplacement"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Réduire la bottom sheet"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Fermer la bottom sheet"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-gl/strings.xml b/compose/material3/material3/src/androidMain/res/values-gl/strings.xml
index 8860bac..0d2dad7 100644
--- a/compose/material3/material3/src/androidMain/res/values-gl/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-gl/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Dentro do intervalo"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Indica as datas"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Indicouse un intervalo de datas que non é válido"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Panel inferior"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Controlador de arrastre"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Contrae o panel inferior"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Pecha o panel inferior"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-gu/strings.xml b/compose/material3/material3/src/androidMain/res/values-gu/strings.xml
index 9017ea3..ca86b3a 100644
--- a/compose/material3/material3/src/androidMain/res/values-gu/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-gu/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"રેન્જમાં છે"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"તારીખો દાખલ કરો"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"તારીખની શ્રેણીનું અમાન્ય ઇનપુટ"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"બોટમ શીટ"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"ઑબ્જેક્ટ ખેંચવાનું હૅન્ડલ"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"બોટમ શીટ નાની કરો"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"બોટમ શીટ છોડી દો"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-hu/strings.xml b/compose/material3/material3/src/androidMain/res/values-hu/strings.xml
index bc7af67..8a447ae 100644
--- a/compose/material3/material3/src/androidMain/res/values-hu/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-hu/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Tartományon belül"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Dátumok megadása"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Érvénytelen a megadott dátumtartomány"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Alsó lap"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Fogópont"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Az alsó lap összecsukása"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Az alsó lap elvetése"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-hy/strings.xml b/compose/material3/material3/src/androidMain/res/values-hy/strings.xml
index 087a7a9..c02768e 100644
--- a/compose/material3/material3/src/androidMain/res/values-hy/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-hy/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Միջակայքում"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Մուտքագրեք ամսաթվերը"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Մուտքագրված ամսաթվերի միջակայքն անվավեր է"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Ներքևի էկրան"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Տեղափոխման նշիչ"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Ծալել ներքևի էկրանը"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Փակել ներքևի էկրանը"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-in/strings.xml b/compose/material3/material3/src/androidMain/res/values-in/strings.xml
index 283a4ff..3d89985 100644
--- a/compose/material3/material3/src/androidMain/res/values-in/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-in/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Dalam rentang"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Masukkan tanggal"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Input rentang tanggal tidak valid"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Sheet Bawah"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Handel geser"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Menciutkan sheet bawah"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Menutup sheet bawah"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-is/strings.xml b/compose/material3/material3/src/androidMain/res/values-is/strings.xml
index 64a4e58..36d2881 100644
--- a/compose/material3/material3/src/androidMain/res/values-is/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-is/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Innan tímabils"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Slá inn dagsetningar"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Ógilt tímabil fært inn"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Blað neðst"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Dragkló"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Minnka blað neðst"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Hunsa blað neðst"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-kk/strings.xml b/compose/material3/material3/src/androidMain/res/values-kk/strings.xml
index 4434953..2b79f5b 100644
--- a/compose/material3/material3/src/androidMain/res/values-kk/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-kk/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Күндер аралығында"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Күндерді енгізіңіз"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Жарамсыз күндер аралығы енгізілген."</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Төменгі парақша"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Сүйрейтін тетік"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Төменгі парақшаны жию"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Төменгі парақшаны жабу"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-kn/strings.xml b/compose/material3/material3/src/androidMain/res/values-kn/strings.xml
index 14ef000..b4d0917 100644
--- a/compose/material3/material3/src/androidMain/res/values-kn/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-kn/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"ವ್ಯಾಪ್ತಿಯಲ್ಲಿದೆ"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"ದಿನಾಂಕಗಳನ್ನು ನಮೂದಿಸಿ"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"ದಿನಾಂಕ ವ್ಯಾಪ್ತಿಯ ಇನ್ಪುಟ್ ಅಮಾನ್ಯವಾಗಿದೆ"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"ಕೆಳಭಾಗದ ಶೀಟ್"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"ಹ್ಯಾಂಡಲ್ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"ಕೆಳಭಾಗದ ಶೀಟ್ ಅನ್ನು ಕುಗ್ಗಿಸಿ"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"ಕೆಳಭಾಗದ ಶೀಟ್ ಅನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ko/strings.xml b/compose/material3/material3/src/androidMain/res/values-ko/strings.xml
index 1e40372..703a020 100644
--- a/compose/material3/material3/src/androidMain/res/values-ko/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ko/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"범위 내"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"날짜 입력"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"잘못된 기간 입력"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"하단 시트"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"드래그 핸들"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"하단 시트 접기"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"하단 시트 닫기"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ky/strings.xml b/compose/material3/material3/src/androidMain/res/values-ky/strings.xml
index 11f4e20..c6f6d91 100644
--- a/compose/material3/material3/src/androidMain/res/values-ky/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ky/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Төмөнкү убакыт аралыгындагы күн"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Күндөрдү киргизүү"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Даталар диапазону туура эмес тандалды"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Ылдыйкы экран"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Сүйрөө маркери"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Ылдыйкы экранды жыйыштыруу"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Ылдыйкы экранды жабуу"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-lt/strings.xml b/compose/material3/material3/src/androidMain/res/values-lt/strings.xml
index 5d5fc0e..e8ba569 100644
--- a/compose/material3/material3/src/androidMain/res/values-lt/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-lt/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Diapazone"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Įvesti datas"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Netinkama dienų sekos įvestis"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Apatinis lapas"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Vilkimo rankenėlė"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Sutraukti apatinį lapą"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Atsisakyti apatinio lapo"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-mk/strings.xml b/compose/material3/material3/src/androidMain/res/values-mk/strings.xml
index 50b7e6d..a1c757d 100644
--- a/compose/material3/material3/src/androidMain/res/values-mk/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-mk/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Во опсег"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Внесете датуми"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Внесовте неважечки временски период"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Долен лист"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Рачка за влечење"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Собери го долниот лист"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Отфрли го долниот лист"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ml/strings.xml b/compose/material3/material3/src/androidMain/res/values-ml/strings.xml
index 7e3c96b..bc651fd 100644
--- a/compose/material3/material3/src/androidMain/res/values-ml/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ml/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"പരിധിയിൽ"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"തീയതികൾ നൽകുക"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"തീയതി ശ്രേണി ഇൻപുട്ട് അസാധുവാണ്"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"ബോട്ടം ഷീറ്റ്"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"വലിച്ചിടുന്നതിനുള്ള ഹാൻഡിൽ"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"ബോട്ടം ഷീറ്റ് ചുരുക്കുക"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"ബോട്ടം ഷീറ്റ് ഡിസ്മിസ് ചെയ്യുക"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-mn/strings.xml b/compose/material3/material3/src/androidMain/res/values-mn/strings.xml
index e7f1a06..c705e03 100644
--- a/compose/material3/material3/src/androidMain/res/values-mn/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-mn/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Мужид байгаа"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Огноо оруулах"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Хугацааны интервалын оролт буруу байна"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Доод хүснэгт"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Чирэх бариул"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Доод хүснэгтийг хураах"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Доод хүснэгтийг хаах"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-my/strings.xml b/compose/material3/material3/src/androidMain/res/values-my/strings.xml
index 6314074..a99df20 100644
--- a/compose/material3/material3/src/androidMain/res/values-my/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-my/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"အပိုင်းအခြားအတွင်း"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"ရက်စွဲများထည့်ပါ"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"ဒေတာအပိုင်းအခြား ထည့်သွင်းမှု မမှန်ပါ"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"အောက်ခြေအပိုဆောင်း စာမျက်နှာ"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"ဖိဆွဲအထိန်း"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"အောက်ခြေအပိုဆောင်း စာမျက်နှာကို ချုံ့သည်"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"အောက်ခြေအပိုဆောင်း စာမျက်နှာကို ပယ်သည်"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-nb/strings.xml b/compose/material3/material3/src/androidMain/res/values-nb/strings.xml
index 1032b2a..c834651 100644
--- a/compose/material3/material3/src/androidMain/res/values-nb/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-nb/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Innenfor området"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Legg inn datoer"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"En ugyldig datoperiode er valgt"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Felt nederst"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Håndtak"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Skjul feltet nederst"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Lukk feltet nederst"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-nl/strings.xml b/compose/material3/material3/src/androidMain/res/values-nl/strings.xml
index 359d164..22e97a7 100644
--- a/compose/material3/material3/src/androidMain/res/values-nl/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-nl/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Binnen bereik"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Datums opgeven"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Ongeldige invoer voor periode"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Blad onderaan"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Handgreep voor slepen"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Blad onderaan samenvouwen"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Blad onderaan sluiten"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-or/strings.xml b/compose/material3/material3/src/androidMain/res/values-or/strings.xml
index 954f415..ef0e743 100644
--- a/compose/material3/material3/src/androidMain/res/values-or/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-or/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"ରେଞ୍ଜରେ ଅଛି"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"ତାରିଖଗୁଡ଼ିକ ଲେଖନ୍ତୁ"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"ଅବୈଧ ତାରିଖ ରେଞ୍ଜ ଇନପୁଟ"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"ବଟମ ସିଟ"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"ଡ୍ରାଗ ହେଣ୍ଡେଲ"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"ବଟମ ସିଟକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"ବଟମ ସିଟକୁ ଖାରଜ କରନ୍ତୁ"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-pa/strings.xml b/compose/material3/material3/src/androidMain/res/values-pa/strings.xml
index f7ef4eb..c932a73 100644
--- a/compose/material3/material3/src/androidMain/res/values-pa/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-pa/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"ਰੇਂਜ ਵਿੱਚ"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"ਤਾਰੀਖਾਂ ਦਾਖਲ ਕਰੋ"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"ਇਨਪੁੱਟ ਕੀਤੀ ਗਈ ਤਾਰੀਖ ਦੀ ਰੇਂਜ ਅਵੈਧ ਹੈ"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"ਹੇਠਲੀ ਸ਼ੀਟ"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"ਘਸੀਟਣ ਵਾਲਾ ਹੈਂਡਲ"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"ਹੇਠਲੀ ਸ਼ੀਟ ਨੂੰ ਸਮੇਟੋ"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"ਹੇਠਲੀ ਸ਼ੀਟ ਨੂੰ ਖਾਰਜ ਕਰੋ"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-pl/strings.xml b/compose/material3/material3/src/androidMain/res/values-pl/strings.xml
index 1f0ae4d..e4c2559 100644
--- a/compose/material3/material3/src/androidMain/res/values-pl/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-pl/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"W zakresie"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Wprowadź daty"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Nieprawidłowy zakres dat"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Plansza dolna"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Uchwyt do przeciągania"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Zwiń planszę dolną"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Zamknij planszę dolną"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-pt-rPT/strings.xml b/compose/material3/material3/src/androidMain/res/values-pt-rPT/strings.xml
index ebcd3985..0170c26 100644
--- a/compose/material3/material3/src/androidMain/res/values-pt-rPT/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-pt-rPT/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Dentro do intervalo"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Introduza as datas"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Entrada do intervalo de datas inválida"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Secção inferior"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Indicador para arrastar"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Reduza a secção inferior"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Ignore a secção inferior"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ru/strings.xml b/compose/material3/material3/src/androidMain/res/values-ru/strings.xml
index 71413c77..86a40de 100644
--- a/compose/material3/material3/src/androidMain/res/values-ru/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ru/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"День в диапазоне дат"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Введите даты"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Указан недопустимый диапазон дат."</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Нижний экран"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Маркер перемещения"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Свернуть нижний экран"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Закрыть нижний экран"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-si/strings.xml b/compose/material3/material3/src/androidMain/res/values-si/strings.xml
index 27939f6..a1a2e51 100644
--- a/compose/material3/material3/src/androidMain/res/values-si/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-si/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"පරාසය තුළ"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"දින ඇතුළු කරන්න"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"අවලංගු දින පරාස ආදානය"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"පහළම පත්රය"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"ඇදීම් හැඬලය"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"පහළම පත්රය හකුළන්න"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"පහළම පත්රය අස් කරන්න"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-sl/strings.xml b/compose/material3/material3/src/androidMain/res/values-sl/strings.xml
index 3505958..d09f814 100644
--- a/compose/material3/material3/src/androidMain/res/values-sl/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-sl/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Znotraj obdobja"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Vnesite datume"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Neveljaven vnos obdobja."</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Razdelek na dnu zaslona"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Ročica za vlečenje"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Strnitev razdelka na dnu zaslona"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Opustitev razdelka na dnu zaslona"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-sv/strings.xml b/compose/material3/material3/src/androidMain/res/values-sv/strings.xml
index d1eaa82..f783d26 100644
--- a/compose/material3/material3/src/androidMain/res/values-sv/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-sv/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Inom intervall"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Ange datum"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Ett ogiltigt datumintervall har angetts"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Ark på nedre delen av skärmen"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Handtag"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Komprimera arket på nedre delen av skärmen"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Stäng arket på nedre delen av skärmen"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ta/strings.xml b/compose/material3/material3/src/androidMain/res/values-ta/strings.xml
index c3a6b40..de52179 100644
--- a/compose/material3/material3/src/androidMain/res/values-ta/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ta/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"வரம்பிற்குள் உள்ளது"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"தேதிகளை உள்ளிடுங்கள்"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"தவறான தேதி வரம்பை உள்ளிட்டுள்ளீர்கள்"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"கீழ்ப்புற ஷீட்"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"இழுப்பதற்கான ஹேண்டில்"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"கீழ்ப்புற ஷீட்டைச் சுருக்கும்"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"கீழ்ப்புற ஷீட்டை நிராகரிக்கும்"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-te/strings.xml b/compose/material3/material3/src/androidMain/res/values-te/strings.xml
index 539d571..64eb6ae 100644
--- a/compose/material3/material3/src/androidMain/res/values-te/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-te/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"పరిధిలో ఉంది"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"తేదీలను ఎంటర్ చేయండి"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"తేదీల పరిధి ఇన్పుట్ చెల్లదు"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"దిగువున ఉన్న షీట్"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"లాగే హ్యాండిల్"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"దిగువున ఉన్న షీట్ను కుదిస్తుంది"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"దిగువున ఉన్న షీట్ను విస్మరిస్తుంది"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-th/strings.xml b/compose/material3/material3/src/androidMain/res/values-th/strings.xml
index b710696..4d70e7d 100644
--- a/compose/material3/material3/src/androidMain/res/values-th/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-th/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"อยู่ในช่วงวันที่ที่เลือก"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"ป้อนวันที่"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"การป้อนข้อมูลช่วงวันที่ไม่ถูกต้อง"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Bottom Sheet"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"แฮนเดิลการลาก"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"ยุบ Bottom Sheet"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"ปิด Bottom Sheet"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-tl/strings.xml b/compose/material3/material3/src/androidMain/res/values-tl/strings.xml
index 78aefd7..5c1121a 100644
--- a/compose/material3/material3/src/androidMain/res/values-tl/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-tl/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"May signal"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Maglagay ng mga petsa"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Invalid ang input na hanay ng petsa"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Bottom Sheet"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Handle sa pag-drag"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"I-collapse ang bottom sheet"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"I-dismiss ang bottom sheet"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-tr/strings.xml b/compose/material3/material3/src/androidMain/res/values-tr/strings.xml
index 0be0e2d..ef2acd4 100644
--- a/compose/material3/material3/src/androidMain/res/values-tr/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-tr/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Aralıkta"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Tarihleri girin"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Geçersiz tarih aralığı girişi"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Alt Sayfa"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Sürükleme tutamacı"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Alt sayfayı daralt"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Alt sayfayı kapat"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-uk/strings.xml b/compose/material3/material3/src/androidMain/res/values-uk/strings.xml
index b9c7bd5..bc13ae1 100644
--- a/compose/material3/material3/src/androidMain/res/values-uk/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-uk/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"У діапазоні"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Введіть дати"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Указано недійсний діапазон дат"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Нижній екран"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Маркер переміщення"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Згорнути нижній екран"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Закрити нижній екран"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-vi/strings.xml b/compose/material3/material3/src/androidMain/res/values-vi/strings.xml
index e5f1699..f0a0ee6 100644
--- a/compose/material3/material3/src/androidMain/res/values-vi/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-vi/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"Trong khoảng"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"Nhập ngày"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"Phạm vi ngày đã nhập không hợp lệ"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"Bảng dưới cùng"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"Nút kéo"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"Thu gọn bảng dưới cùng"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"Đóng bảng dưới cùng"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml b/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml
index 876cb0f..0fd94f0 100644
--- a/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"在范围内"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"输入日期"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"输入的日期范围无效"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"底部动作条"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"拖动手柄"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"收起底部动作条"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"关闭底部动作条"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml b/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml
index aa77db0..147412a 100644
--- a/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"喺指定日期範圍內"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"輸入日期"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"輸入的日期範圍無效"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"頁底面板"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"拖曳控點"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"收合頁底面板"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"關閉頁底面板"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml b/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml
index 7052471..e1303e8 100644
--- a/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml
@@ -54,8 +54,7 @@
<string name="m3c_date_range_picker_day_in_range" msgid="2138321128465719402">"在有效範圍內"</string>
<string name="m3c_date_range_input_title" msgid="3148384720560189467">"輸入日期"</string>
<string name="m3c_date_range_input_invalid_range_input" msgid="3190049423327661366">"輸入的日期範圍無效"</string>
- <!-- no translation found for m3c_bottom_sheet_pane_title (3010635850035863127) -->
- <skip />
+ <string name="m3c_bottom_sheet_pane_title" msgid="3010635850035863127">"底部功能表"</string>
<string name="m3c_bottom_sheet_drag_handle_description" msgid="8403354765404029791">"拖曳控點"</string>
<string name="m3c_bottom_sheet_collapse_description" msgid="2988463736136100848">"收合底部功能表"</string>
<string name="m3c_bottom_sheet_dismiss_description" msgid="1555567894577437024">"關閉底部功能表"</string>
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt
index fe5ea6e..811d6fa 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt
@@ -27,6 +27,10 @@
import androidx.compose.material3.tokens.BadgeTokens
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+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
@@ -34,8 +38,11 @@
import androidx.compose.ui.layout.FirstBaseline
import androidx.compose.ui.layout.LastBaseline
import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.layoutId
+import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.unit.dp
+import kotlin.math.roundToInt
/**
* Material Design badge box.
@@ -64,6 +71,13 @@
modifier: Modifier = Modifier,
content: @Composable BoxScope.() -> Unit,
) {
+ var layoutAbsoluteLeft by remember { mutableFloatStateOf(0f) }
+ var layoutAbsoluteTop by remember { mutableFloatStateOf(0f) }
+ // We use Float.POSITIVE_INFINITY and Float.NEGATIVE_INFINITY to represent the case
+ // when there isn't a great grand parent layout.
+ var greatGrandParentAbsoluteRight by remember { mutableFloatStateOf(Float.POSITIVE_INFINITY) }
+ var greatGrandParentAbsoluteTop by remember { mutableFloatStateOf(Float.NEGATIVE_INFINITY) }
+
Layout(
{
Box(
@@ -77,6 +91,16 @@
)
},
modifier = modifier
+ .onGloballyPositioned { coordinates ->
+ layoutAbsoluteLeft = coordinates.boundsInWindow().left
+ layoutAbsoluteTop = coordinates.boundsInWindow().top
+ val layoutGreatGrandParent =
+ coordinates.parentLayoutCoordinates?.parentLayoutCoordinates?.parentCoordinates
+ layoutGreatGrandParent?.let {
+ greatGrandParentAbsoluteRight = it.boundsInWindow().right
+ greatGrandParentAbsoluteTop = it.boundsInWindow().top
+ }
+ }
) { measurables, constraints ->
val badgePlaceable = measurables.first { it.layoutId == "badge" }.measure(
@@ -111,8 +135,25 @@
if (hasContent) BadgeWithContentVerticalOffset else BadgeOffset
anchorPlaceable.placeRelative(0, 0)
- val badgeX = anchorPlaceable.width + badgeHorizontalOffset.roundToPx()
- val badgeY = -badgePlaceable.height / 2 + badgeVerticalOffset.roundToPx()
+
+ // Desired Badge placement
+ var badgeX = anchorPlaceable.width + badgeHorizontalOffset.roundToPx()
+ var badgeY = -badgePlaceable.height / 2 + badgeVerticalOffset.roundToPx()
+ // Badge correction logic if the badge will be cut off by the grandparent bounds.
+ val badgeAbsoluteTop = layoutAbsoluteTop + badgeY
+ val badgeAbsoluteRight = layoutAbsoluteLeft + badgeX + badgePlaceable.width.toFloat()
+ val badgeGreatGrandParentHorizontalDiff =
+ greatGrandParentAbsoluteRight - badgeAbsoluteRight
+ val badgeGreatGrandParentVerticalDiff =
+ badgeAbsoluteTop - greatGrandParentAbsoluteTop
+ // Adjust badgeX and badgeY if the desired placement would cause it to clip.
+ if (badgeGreatGrandParentHorizontalDiff < 0) {
+ badgeX += badgeGreatGrandParentHorizontalDiff.roundToInt()
+ }
+ if (badgeGreatGrandParentVerticalDiff < 0) {
+ badgeY -= badgeGreatGrandParentVerticalDiff.roundToInt()
+ }
+
badgePlaceable.placeRelative(badgeX, badgeY)
}
}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt
index d81502f7..20adb98 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt
@@ -43,7 +43,7 @@
import androidx.compose.ui.semantics.expand
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.Dp
-import java.lang.Float.max
+import kotlin.math.max
import kotlin.math.roundToInt
import kotlinx.coroutines.launch
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt
index 681a824..6580872 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt
@@ -855,22 +855,24 @@
val animatable = remember { Animatable(target, Dp.VectorConverter) }
- if (!enabled) {
- // No transition when moving to a disabled state
- LaunchedEffect(target) { animatable.snapTo(target) }
- } else {
- LaunchedEffect(target) {
- val lastInteraction = when (animatable.targetValue) {
- pressedElevation -> PressInteraction.Press(Offset.Zero)
- hoveredElevation -> HoverInteraction.Enter()
- focusedElevation -> FocusInteraction.Focus()
- else -> null
+ LaunchedEffect(target) {
+ if (animatable.targetValue != target) {
+ if (!enabled) {
+ // No transition when moving to a disabled state
+ animatable.snapTo(target)
+ } else {
+ val lastInteraction = when (animatable.targetValue) {
+ pressedElevation -> PressInteraction.Press(Offset.Zero)
+ hoveredElevation -> HoverInteraction.Enter()
+ focusedElevation -> FocusInteraction.Focus()
+ else -> null
+ }
+ animatable.animateElevation(
+ from = lastInteraction,
+ to = interaction,
+ target = target
+ )
}
- animatable.animateElevation(
- from = lastInteraction,
- to = interaction,
- target = target
- )
}
}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/CalendarModel.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/CalendarModel.kt
index 9991e2d..ac96c34 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/CalendarModel.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/CalendarModel.kt
@@ -16,10 +16,7 @@
package androidx.compose.material3
-import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.ReadOnlyComposable
-import java.util.Locale
/**
* Creates a [CalendarModel] to be used by the date picker.
@@ -38,25 +35,15 @@
*
* @param utcTimeMillis a UTC timestamp to format (milliseconds from epoch)
* @param skeleton a date format skeleton
- * @param locale the [Locale] to use when formatting the given timestamp
+ * @param locale the [CalendarLocale] to use when formatting the given timestamp
*/
@ExperimentalMaterial3Api
expect fun formatWithSkeleton(
utcTimeMillis: Long,
skeleton: String,
- locale: Locale = Locale.getDefault()
+ locale: CalendarLocale
): String
-/**
- * A composable function that returns the default [Locale].
- *
- * When running on an Android platform, it will be recomposed when the `Configuration` gets updated.
- */
-@Composable
-@ReadOnlyComposable
-@ExperimentalMaterial3Api
-internal expect fun defaultLocale(): Locale
-
@ExperimentalMaterial3Api
internal interface CalendarModel {
@@ -84,7 +71,7 @@
val weekdayNames: List<Pair<String, String>>
/**
- * Returns a [DateInputFormat] for the given [Locale].
+ * Returns a [DateInputFormat] for the given [CalendarLocale].
*
* The input format represents the date with two digits for the day and the month, and
* four digits for the year.
@@ -99,7 +86,7 @@
* - dd.MM.yyyy
* - MM/dd/yyyy
*/
- fun getDateInputFormat(locale: Locale = Locale.getDefault()): DateInputFormat
+ fun getDateInputFormat(locale: CalendarLocale = defaultLocale()): DateInputFormat
/**
* Returns a [CalendarDate] from a given _UTC_ time in milliseconds.
@@ -166,12 +153,12 @@
*
* @param month a [CalendarMonth] to format
* @param skeleton a date format skeleton
- * @param locale the [Locale] to use when formatting the given month
+ * @param locale the [CalendarLocale] to use when formatting the given month
*/
fun formatWithSkeleton(
month: CalendarMonth,
skeleton: String,
- locale: Locale = Locale.getDefault()
+ locale: CalendarLocale = defaultLocale()
): String =
formatWithSkeleton(month.startUtcTimeMillis, skeleton, locale)
@@ -180,12 +167,12 @@
*
* @param date a [CalendarDate] to format
* @param skeleton a date format skeleton
- * @param locale the [Locale] to use when formatting the given date
+ * @param locale the [CalendarLocale] to use when formatting the given date
*/
fun formatWithSkeleton(
date: CalendarDate,
skeleton: String,
- locale: Locale = Locale.getDefault()
+ locale: CalendarLocale = defaultLocale()
): String = formatWithSkeleton(date.utcTimeMillis, skeleton, locale)
/**
@@ -193,9 +180,9 @@
*
* @param utcTimeMillis a UTC timestamp to format (milliseconds from epoch)
* @param pattern a date format pattern
- * @param locale the [Locale] to use when formatting the given timestamp
+ * @param locale the [CalendarLocale] to use when formatting the given timestamp
*/
- fun formatWithPattern(utcTimeMillis: Long, pattern: String, locale: Locale): String
+ fun formatWithPattern(utcTimeMillis: Long, pattern: String, locale: CalendarLocale): String
/**
* Parses a date string into a [CalendarDate].
@@ -234,12 +221,12 @@
this.utcTimeMillis.compareTo(other.utcTimeMillis)
/**
- * Formats the date into a string with the given skeleton format and a [Locale].
+ * Formats the date into a string with the given skeleton format and a [CalendarLocale].
*/
fun format(
calendarModel: CalendarModel,
skeleton: String,
- locale: Locale = Locale.getDefault()
+ locale: CalendarLocale = defaultLocale()
): String =
calendarModel.formatWithSkeleton(this, skeleton, locale)
}
@@ -277,12 +264,12 @@
}
/**
- * Formats the month into a string with the given skeleton format and a [Locale].
+ * Formats the month into a string with the given skeleton format and a [CalendarLocale].
*/
fun format(
calendarModel: CalendarModel,
skeleton: String,
- locale: Locale = Locale.getDefault()
+ locale: CalendarLocale = defaultLocale()
): String =
calendarModel.formatWithSkeleton(this, skeleton, locale)
}
@@ -290,8 +277,8 @@
/**
* Holds the date input format pattern information.
*
- * This data class hold the delimiter that is used by the current [Locale] when representing dates
- * in a short format, as well as a date pattern with and without a delimiter.
+ * This data class hold the delimiter that is used by the current [CalendarLocale] when representing
+ * dates in a short format, as well as a date pattern with and without a delimiter.
*/
@ExperimentalMaterial3Api
@Immutable
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Card.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Card.kt
index ccdfa68..e952287 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Card.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Card.kt
@@ -670,22 +670,24 @@
val animatable = remember { Animatable(target, Dp.VectorConverter) }
LaunchedEffect(target) {
- if (enabled) {
- val lastInteraction = when (animatable.targetValue) {
- pressedElevation -> PressInteraction.Press(Offset.Zero)
- hoveredElevation -> HoverInteraction.Enter()
- focusedElevation -> FocusInteraction.Focus()
- draggedElevation -> DragInteraction.Start()
- else -> null
+ if (animatable.targetValue != target) {
+ if (!enabled) {
+ // No transition when moving to a disabled state.
+ animatable.snapTo(target)
+ } else {
+ val lastInteraction = when (animatable.targetValue) {
+ pressedElevation -> PressInteraction.Press(Offset.Zero)
+ hoveredElevation -> HoverInteraction.Enter()
+ focusedElevation -> FocusInteraction.Focus()
+ draggedElevation -> DragInteraction.Start()
+ else -> null
+ }
+ animatable.animateElevation(
+ from = lastInteraction,
+ to = interaction,
+ target = target
+ )
}
- animatable.animateElevation(
- from = lastInteraction,
- to = interaction,
- target = target
- )
- } else {
- // No transition when moving to a disabled state.
- animatable.snapTo(target)
}
}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
index b2c7357..4ddcc13 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
@@ -1550,15 +1550,17 @@
val animatable = remember { Animatable(target, Dp.VectorConverter) }
LaunchedEffect(target) {
- if (!enabled) {
- // No transition when moving to a disabled state
- animatable.snapTo(target)
- } else {
- animatable.animateElevation(
- from = lastInteraction, to = interaction, target = target
- )
+ if (animatable.targetValue != target) {
+ if (!enabled) {
+ // No transition when moving to a disabled state
+ animatable.snapTo(target)
+ } else {
+ animatable.animateElevation(
+ from = lastInteraction, to = interaction, target = target
+ )
+ }
+ lastInteraction = interaction
}
- lastInteraction = interaction
}
return animatable.asState()
@@ -1705,15 +1707,17 @@
val animatable = remember { Animatable(target, Dp.VectorConverter) }
LaunchedEffect(target) {
- if (!enabled) {
- // No transition when moving to a disabled state
- animatable.snapTo(target)
- } else {
- animatable.animateElevation(
- from = lastInteraction, to = interaction, target = target
- )
+ if (animatable.targetValue != target) {
+ if (!enabled) {
+ // No transition when moving to a disabled state
+ animatable.snapTo(target)
+ } else {
+ animatable.animateElevation(
+ from = lastInteraction, to = interaction, target = target
+ )
+ }
+ lastInteraction = interaction
}
- lastInteraction = interaction
}
return animatable.asState()
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ColorScheme.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ColorScheme.kt
index 19b5893..279033a 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ColorScheme.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ColorScheme.kt
@@ -95,6 +95,22 @@
* @property outlineVariant Utility color used for boundaries for decorative elements when strong
* contrast is not required.
* @property scrim Color of a scrim that obscures content.
+ * @property surfaceBright A [surface] variant that is always brighter than [surface], whether in
+ * light or dark mode.
+ * @property surfaceDim A [surface] variant that is always dimmer than [surface], whether in light or
+ * dark mode.
+ * @property surfaceContainer A [surface] variant that affects containers of components, such as
+ * cards, sheets, and menus.
+ * @property surfaceContainerHigh A [surface] variant for containers with higher emphasis than
+ * [surfaceContainer]. Use this role for content which requires more emphasis than [surfaceContainer].
+ * @property surfaceContainerHighest A [surface] variant for containers with higher emphasis than
+ * [surfaceContainerHigh]. Use this role for content which requires more emphasis than
+ * [surfaceContainerHigh].
+ * @property surfaceContainerLow A [surface] variant for containers with lower emphasis than
+ * [surfaceContainer]. Use this role for content which requires less emphasis than [surfaceContainer].
+ * @property surfaceContainerLowest A [surface] variant for containers with lower emphasis than
+ * [surfaceContainerLow]. Use this role for content which requires less emphasis than
+ * [surfaceContainerLow].
*/
@Stable
class ColorScheme(
@@ -127,7 +143,82 @@
outline: Color,
outlineVariant: Color,
scrim: Color,
+ surfaceBright: Color,
+ surfaceDim: Color,
+ surfaceContainer: Color,
+ surfaceContainerHigh: Color,
+ surfaceContainerHighest: Color,
+ surfaceContainerLow: Color,
+ surfaceContainerLowest: Color,
) {
+ constructor(
+ primary: Color,
+ onPrimary: Color,
+ primaryContainer: Color,
+ onPrimaryContainer: Color,
+ inversePrimary: Color,
+ secondary: Color,
+ onSecondary: Color,
+ secondaryContainer: Color,
+ onSecondaryContainer: Color,
+ tertiary: Color,
+ onTertiary: Color,
+ tertiaryContainer: Color,
+ onTertiaryContainer: Color,
+ background: Color,
+ onBackground: Color,
+ surface: Color,
+ onSurface: Color,
+ surfaceVariant: Color,
+ onSurfaceVariant: Color,
+ surfaceTint: Color,
+ inverseSurface: Color,
+ inverseOnSurface: Color,
+ error: Color,
+ onError: Color,
+ errorContainer: Color,
+ onErrorContainer: Color,
+ outline: Color,
+ outlineVariant: Color,
+ scrim: Color,
+ ) : this(
+ primary = primary,
+ onPrimary = onPrimary,
+ primaryContainer = primaryContainer,
+ onPrimaryContainer = onPrimaryContainer,
+ inversePrimary = inversePrimary,
+ secondary = secondary,
+ onSecondary = onSecondary,
+ secondaryContainer = secondaryContainer,
+ onSecondaryContainer = onSecondaryContainer,
+ tertiary = tertiary,
+ onTertiary = onTertiary,
+ tertiaryContainer = tertiaryContainer,
+ onTertiaryContainer = onTertiaryContainer,
+ background = background,
+ onBackground = onBackground,
+ surface = surface,
+ onSurface = onSurface,
+ surfaceVariant = surfaceVariant,
+ onSurfaceVariant = onSurfaceVariant,
+ surfaceTint = surfaceTint,
+ inverseSurface = inverseSurface,
+ inverseOnSurface = inverseOnSurface,
+ error = error,
+ onError = onError,
+ errorContainer = errorContainer,
+ onErrorContainer = onErrorContainer,
+ outline = outline,
+ outlineVariant = outlineVariant,
+ scrim = scrim,
+ surfaceBright = Color.Unspecified,
+ surfaceDim = Color.Unspecified,
+ surfaceContainer = Color.Unspecified,
+ surfaceContainerHigh = Color.Unspecified,
+ surfaceContainerHighest = Color.Unspecified,
+ surfaceContainerLow = Color.Unspecified,
+ surfaceContainerLowest = Color.Unspecified,
+ )
var primary by mutableStateOf(primary, structuralEqualityPolicy())
internal set
var onPrimary by mutableStateOf(onPrimary, structuralEqualityPolicy())
@@ -186,6 +277,21 @@
internal set
var scrim by mutableStateOf(scrim, structuralEqualityPolicy())
internal set
+ var surfaceBright by mutableStateOf(surfaceBright, structuralEqualityPolicy())
+ internal set
+ var surfaceDim by mutableStateOf(surfaceDim, structuralEqualityPolicy())
+ internal set
+ var surfaceContainer by mutableStateOf(surfaceContainer, structuralEqualityPolicy())
+ internal set
+ var surfaceContainerHigh by mutableStateOf(surfaceContainerHigh, structuralEqualityPolicy())
+ internal set
+ var surfaceContainerHighest by mutableStateOf(
+ surfaceContainerHighest, structuralEqualityPolicy())
+ internal set
+ var surfaceContainerLow by mutableStateOf(surfaceContainerLow, structuralEqualityPolicy())
+ internal set
+ var surfaceContainerLowest by mutableStateOf(surfaceContainerLowest, structuralEqualityPolicy())
+ internal set
/** Returns a copy of this ColorScheme, optionally overriding some of the values. */
fun copy(
@@ -218,6 +324,13 @@
outline: Color = this.outline,
outlineVariant: Color = this.outlineVariant,
scrim: Color = this.scrim,
+ surfaceBright: Color = this.surfaceBright,
+ surfaceDim: Color = this.surfaceDim,
+ surfaceContainer: Color = this.surfaceContainer,
+ surfaceContainerHigh: Color = this.surfaceContainerHigh,
+ surfaceContainerHighest: Color = this.surfaceContainerHighest,
+ surfaceContainerLow: Color = this.surfaceContainerLow,
+ surfaceContainerLowest: Color = this.surfaceContainerLowest,
): ColorScheme =
ColorScheme(
primary = primary,
@@ -249,6 +362,82 @@
outline = outline,
outlineVariant = outlineVariant,
scrim = scrim,
+ surfaceBright = surfaceBright,
+ surfaceDim = surfaceDim,
+ surfaceContainer = surfaceContainer,
+ surfaceContainerHigh = surfaceContainerHigh,
+ surfaceContainerHighest = surfaceContainerHighest,
+ surfaceContainerLow = surfaceContainerLow,
+ surfaceContainerLowest = surfaceContainerLowest,
+ )
+
+ @Deprecated(
+ message =
+ "Maintained for binary compatibility. Use overload with additional surface roles " +
+ "instead",
+ level = DeprecationLevel.HIDDEN
+ )
+ fun copy(
+ primary: Color = this.primary,
+ onPrimary: Color = this.onPrimary,
+ primaryContainer: Color = this.primaryContainer,
+ onPrimaryContainer: Color = this.onPrimaryContainer,
+ inversePrimary: Color = this.inversePrimary,
+ secondary: Color = this.secondary,
+ onSecondary: Color = this.onSecondary,
+ secondaryContainer: Color = this.secondaryContainer,
+ onSecondaryContainer: Color = this.onSecondaryContainer,
+ tertiary: Color = this.tertiary,
+ onTertiary: Color = this.onTertiary,
+ tertiaryContainer: Color = this.tertiaryContainer,
+ onTertiaryContainer: Color = this.onTertiaryContainer,
+ background: Color = this.background,
+ onBackground: Color = this.onBackground,
+ surface: Color = this.surface,
+ onSurface: Color = this.onSurface,
+ surfaceVariant: Color = this.surfaceVariant,
+ onSurfaceVariant: Color = this.onSurfaceVariant,
+ surfaceTint: Color = this.surfaceTint,
+ inverseSurface: Color = this.inverseSurface,
+ inverseOnSurface: Color = this.inverseOnSurface,
+ error: Color = this.error,
+ onError: Color = this.onError,
+ errorContainer: Color = this.errorContainer,
+ onErrorContainer: Color = this.onErrorContainer,
+ outline: Color = this.outline,
+ outlineVariant: Color = this.outlineVariant,
+ scrim: Color = this.scrim,
+ ): ColorScheme =
+ copy(
+ primary = primary,
+ onPrimary = onPrimary,
+ primaryContainer = primaryContainer,
+ onPrimaryContainer = onPrimaryContainer,
+ inversePrimary = inversePrimary,
+ secondary = secondary,
+ onSecondary = onSecondary,
+ secondaryContainer = secondaryContainer,
+ onSecondaryContainer = onSecondaryContainer,
+ tertiary = tertiary,
+ onTertiary = onTertiary,
+ tertiaryContainer = tertiaryContainer,
+ onTertiaryContainer = onTertiaryContainer,
+ background = background,
+ onBackground = onBackground,
+ surface = surface,
+ onSurface = onSurface,
+ surfaceVariant = surfaceVariant,
+ onSurfaceVariant = onSurfaceVariant,
+ surfaceTint = surfaceTint,
+ inverseSurface = inverseSurface,
+ inverseOnSurface = inverseOnSurface,
+ error = error,
+ onError = onError,
+ errorContainer = errorContainer,
+ onErrorContainer = onErrorContainer,
+ outline = outline,
+ outlineVariant = outlineVariant,
+ scrim = scrim,
)
override fun toString(): String {
@@ -282,6 +471,13 @@
"outline=$outline" +
"outlineVariant=$outlineVariant" +
"scrim=$scrim" +
+ "surfaceBright=$surfaceBright" +
+ "surfaceDim=$surfaceDim" +
+ "surfaceContainer=$surfaceContainer" +
+ "surfaceContainerHigh=$surfaceContainerHigh" +
+ "surfaceContainerHighest=$surfaceContainerHighest" +
+ "surfaceContainerLow=$surfaceContainerLow" +
+ "surfaceContainerLowest=$surfaceContainerLowest" +
")"
}
}
@@ -319,6 +515,13 @@
outline: Color = ColorLightTokens.Outline,
outlineVariant: Color = ColorLightTokens.OutlineVariant,
scrim: Color = ColorLightTokens.Scrim,
+ surfaceBright: Color = ColorLightTokens.SurfaceBright,
+ surfaceContainer: Color = ColorLightTokens.SurfaceContainer,
+ surfaceContainerHigh: Color = ColorLightTokens.SurfaceContainerHigh,
+ surfaceContainerHighest: Color = ColorLightTokens.SurfaceContainerHighest,
+ surfaceContainerLow: Color = ColorLightTokens.SurfaceContainerLow,
+ surfaceContainerLowest: Color = ColorLightTokens.SurfaceContainerLowest,
+ surfaceDim: Color = ColorLightTokens.SurfaceDim,
): ColorScheme =
ColorScheme(
primary = primary,
@@ -350,6 +553,81 @@
outline = outline,
outlineVariant = outlineVariant,
scrim = scrim,
+ surfaceBright = surfaceBright,
+ surfaceContainer = surfaceContainer,
+ surfaceContainerHigh = surfaceContainerHigh,
+ surfaceContainerHighest = surfaceContainerHighest,
+ surfaceContainerLow = surfaceContainerLow,
+ surfaceContainerLowest = surfaceContainerLowest,
+ surfaceDim = surfaceDim,
+ )
+
+@Deprecated(
+ message =
+ "Maintained for binary compatibility. Use overload with additional surface roles instead",
+ level = DeprecationLevel.HIDDEN
+)
+fun lightColorScheme(
+ primary: Color = ColorLightTokens.Primary,
+ onPrimary: Color = ColorLightTokens.OnPrimary,
+ primaryContainer: Color = ColorLightTokens.PrimaryContainer,
+ onPrimaryContainer: Color = ColorLightTokens.OnPrimaryContainer,
+ inversePrimary: Color = ColorLightTokens.InversePrimary,
+ secondary: Color = ColorLightTokens.Secondary,
+ onSecondary: Color = ColorLightTokens.OnSecondary,
+ secondaryContainer: Color = ColorLightTokens.SecondaryContainer,
+ onSecondaryContainer: Color = ColorLightTokens.OnSecondaryContainer,
+ tertiary: Color = ColorLightTokens.Tertiary,
+ onTertiary: Color = ColorLightTokens.OnTertiary,
+ tertiaryContainer: Color = ColorLightTokens.TertiaryContainer,
+ onTertiaryContainer: Color = ColorLightTokens.OnTertiaryContainer,
+ background: Color = ColorLightTokens.Background,
+ onBackground: Color = ColorLightTokens.OnBackground,
+ surface: Color = ColorLightTokens.Surface,
+ onSurface: Color = ColorLightTokens.OnSurface,
+ surfaceVariant: Color = ColorLightTokens.SurfaceVariant,
+ onSurfaceVariant: Color = ColorLightTokens.OnSurfaceVariant,
+ surfaceTint: Color = primary,
+ inverseSurface: Color = ColorLightTokens.InverseSurface,
+ inverseOnSurface: Color = ColorLightTokens.InverseOnSurface,
+ error: Color = ColorLightTokens.Error,
+ onError: Color = ColorLightTokens.OnError,
+ errorContainer: Color = ColorLightTokens.ErrorContainer,
+ onErrorContainer: Color = ColorLightTokens.OnErrorContainer,
+ outline: Color = ColorLightTokens.Outline,
+ outlineVariant: Color = ColorLightTokens.OutlineVariant,
+ scrim: Color = ColorLightTokens.Scrim,
+): ColorScheme =
+ lightColorScheme(
+ primary = primary,
+ onPrimary = onPrimary,
+ primaryContainer = primaryContainer,
+ onPrimaryContainer = onPrimaryContainer,
+ inversePrimary = inversePrimary,
+ secondary = secondary,
+ onSecondary = onSecondary,
+ secondaryContainer = secondaryContainer,
+ onSecondaryContainer = onSecondaryContainer,
+ tertiary = tertiary,
+ onTertiary = onTertiary,
+ tertiaryContainer = tertiaryContainer,
+ onTertiaryContainer = onTertiaryContainer,
+ background = background,
+ onBackground = onBackground,
+ surface = surface,
+ onSurface = onSurface,
+ surfaceVariant = surfaceVariant,
+ onSurfaceVariant = onSurfaceVariant,
+ surfaceTint = surfaceTint,
+ inverseSurface = inverseSurface,
+ inverseOnSurface = inverseOnSurface,
+ error = error,
+ onError = onError,
+ errorContainer = errorContainer,
+ onErrorContainer = onErrorContainer,
+ outline = outline,
+ outlineVariant = outlineVariant,
+ scrim = scrim,
)
/**
@@ -385,6 +663,13 @@
outline: Color = ColorDarkTokens.Outline,
outlineVariant: Color = ColorDarkTokens.OutlineVariant,
scrim: Color = ColorDarkTokens.Scrim,
+ surfaceBright: Color = ColorDarkTokens.SurfaceBright,
+ surfaceContainer: Color = ColorDarkTokens.SurfaceContainer,
+ surfaceContainerHigh: Color = ColorDarkTokens.SurfaceContainerHigh,
+ surfaceContainerHighest: Color = ColorLightTokens.SurfaceContainerHighest,
+ surfaceContainerLow: Color = ColorDarkTokens.SurfaceContainerLow,
+ surfaceContainerLowest: Color = ColorDarkTokens.SurfaceContainerLowest,
+ surfaceDim: Color = ColorDarkTokens.SurfaceDim,
): ColorScheme =
ColorScheme(
primary = primary,
@@ -416,6 +701,81 @@
outline = outline,
outlineVariant = outlineVariant,
scrim = scrim,
+ surfaceBright = surfaceBright,
+ surfaceContainer = surfaceContainer,
+ surfaceContainerHigh = surfaceContainerHigh,
+ surfaceContainerHighest = surfaceContainerHighest,
+ surfaceContainerLow = surfaceContainerLow,
+ surfaceContainerLowest = surfaceContainerLowest,
+ surfaceDim = surfaceDim,
+ )
+
+@Deprecated(
+ message =
+ "Maintained for binary compatibility. Use overload with additional surface roles instead",
+ level = DeprecationLevel.HIDDEN
+)
+fun darkColorScheme(
+ primary: Color = ColorDarkTokens.Primary,
+ onPrimary: Color = ColorDarkTokens.OnPrimary,
+ primaryContainer: Color = ColorDarkTokens.PrimaryContainer,
+ onPrimaryContainer: Color = ColorDarkTokens.OnPrimaryContainer,
+ inversePrimary: Color = ColorDarkTokens.InversePrimary,
+ secondary: Color = ColorDarkTokens.Secondary,
+ onSecondary: Color = ColorDarkTokens.OnSecondary,
+ secondaryContainer: Color = ColorDarkTokens.SecondaryContainer,
+ onSecondaryContainer: Color = ColorDarkTokens.OnSecondaryContainer,
+ tertiary: Color = ColorDarkTokens.Tertiary,
+ onTertiary: Color = ColorDarkTokens.OnTertiary,
+ tertiaryContainer: Color = ColorDarkTokens.TertiaryContainer,
+ onTertiaryContainer: Color = ColorDarkTokens.OnTertiaryContainer,
+ background: Color = ColorDarkTokens.Background,
+ onBackground: Color = ColorDarkTokens.OnBackground,
+ surface: Color = ColorDarkTokens.Surface,
+ onSurface: Color = ColorDarkTokens.OnSurface,
+ surfaceVariant: Color = ColorDarkTokens.SurfaceVariant,
+ onSurfaceVariant: Color = ColorDarkTokens.OnSurfaceVariant,
+ surfaceTint: Color = primary,
+ inverseSurface: Color = ColorDarkTokens.InverseSurface,
+ inverseOnSurface: Color = ColorDarkTokens.InverseOnSurface,
+ error: Color = ColorDarkTokens.Error,
+ onError: Color = ColorDarkTokens.OnError,
+ errorContainer: Color = ColorDarkTokens.ErrorContainer,
+ onErrorContainer: Color = ColorDarkTokens.OnErrorContainer,
+ outline: Color = ColorDarkTokens.Outline,
+ outlineVariant: Color = ColorDarkTokens.OutlineVariant,
+ scrim: Color = ColorDarkTokens.Scrim,
+): ColorScheme =
+ darkColorScheme(
+ primary = primary,
+ onPrimary = onPrimary,
+ primaryContainer = primaryContainer,
+ onPrimaryContainer = onPrimaryContainer,
+ inversePrimary = inversePrimary,
+ secondary = secondary,
+ onSecondary = onSecondary,
+ secondaryContainer = secondaryContainer,
+ onSecondaryContainer = onSecondaryContainer,
+ tertiary = tertiary,
+ onTertiary = onTertiary,
+ tertiaryContainer = tertiaryContainer,
+ onTertiaryContainer = onTertiaryContainer,
+ background = background,
+ onBackground = onBackground,
+ surface = surface,
+ onSurface = onSurface,
+ surfaceVariant = surfaceVariant,
+ onSurfaceVariant = onSurfaceVariant,
+ surfaceTint = surfaceTint,
+ inverseSurface = inverseSurface,
+ inverseOnSurface = inverseOnSurface,
+ error = error,
+ onError = onError,
+ errorContainer = errorContainer,
+ onErrorContainer = onErrorContainer,
+ outline = outline,
+ outlineVariant = outlineVariant,
+ scrim = scrim,
)
/**
@@ -442,13 +802,19 @@
tertiary -> onTertiary
background -> onBackground
error -> onError
- surface -> onSurface
- surfaceVariant -> onSurfaceVariant
primaryContainer -> onPrimaryContainer
secondaryContainer -> onSecondaryContainer
tertiaryContainer -> onTertiaryContainer
errorContainer -> onErrorContainer
inverseSurface -> inverseOnSurface
+ surface -> onSurface
+ surfaceVariant -> onSurfaceVariant
+ surfaceBright -> onSurface
+ surfaceContainer -> onSurface
+ surfaceContainerHigh -> onSurface
+ surfaceContainerHighest -> onSurface
+ surfaceContainerLow -> onSurface
+ surfaceContainerLowest -> onSurface
else -> Color.Unspecified
}
@@ -477,12 +843,22 @@
}
/**
- * Returns the new background [Color] to use, representing the original background [color] with an
- * overlay corresponding to [elevation] applied. The overlay will only be applied to
- * [ColorScheme.surface].
+ * Returns [ColorScheme.surfaceColorAtElevation] with the provided elevation if
+ * [LocalTonalElevationEnabled] is set to true, and the provided background color matches
+ * [ColorScheme.surface]. Otherwise, the provided color is returned unchanged.
+ *
+ * @param backgroundColor The background color to compare to [ColorScheme.surface]
+ * @param elevation The elevation provided to [ColorScheme.surfaceColorAtElevation] if
+ * [backgroundColor] matches surface.
+ *
+ * @return [ColorScheme.surfaceColorAtElevation] at [elevation] if [backgroundColor] ==
+ * [ColorScheme.surface] and [LocalTonalElevationEnabled] is set to true. Else [backgroundColor]
*/
+@Composable
+@ReadOnlyComposable
internal fun ColorScheme.applyTonalElevation(backgroundColor: Color, elevation: Dp): Color {
- return if (backgroundColor == surface) {
+ val tonalElevationEnabled = LocalTonalElevationEnabled.current
+ return if (backgroundColor == surface && tonalElevationEnabled) {
surfaceColorAtElevation(elevation)
} else {
backgroundColor
@@ -496,7 +872,6 @@
*
* @return the [ColorScheme.surface] color with an alpha of the [ColorScheme.surfaceTint] color
* overlaid on top of it.
-
*/
fun ColorScheme.surfaceColorAtElevation(
elevation: Dp,
@@ -550,6 +925,13 @@
outline = other.outline
outlineVariant = other.outlineVariant
scrim = other.scrim
+ surfaceBright = other.surfaceBright
+ surfaceDim = other.surfaceDim
+ surfaceContainer = other.surfaceContainer
+ surfaceContainerHigh = other.surfaceContainerHigh
+ surfaceContainerHighest = other.surfaceContainerHighest
+ surfaceContainerLow = other.surfaceContainerLow
+ surfaceContainerLowest = other.surfaceContainerLowest
}
/**
@@ -586,8 +968,16 @@
ColorSchemeKeyTokens.SecondaryContainer -> secondaryContainer
ColorSchemeKeyTokens.Surface -> surface
ColorSchemeKeyTokens.SurfaceVariant -> surfaceVariant
+ ColorSchemeKeyTokens.SurfaceBright -> surfaceBright
+ ColorSchemeKeyTokens.SurfaceContainer -> surfaceContainer
+ ColorSchemeKeyTokens.SurfaceContainerHigh -> surfaceContainerHigh
+ ColorSchemeKeyTokens.SurfaceContainerHighest -> surfaceContainerHighest
+ ColorSchemeKeyTokens.SurfaceContainerLow -> surfaceContainerLow
+ ColorSchemeKeyTokens.SurfaceContainerLowest -> surfaceContainerLowest
+ ColorSchemeKeyTokens.SurfaceDim -> surfaceDim
ColorSchemeKeyTokens.Tertiary -> tertiary
ColorSchemeKeyTokens.TertiaryContainer -> tertiaryContainer
+ else -> Color.Unspecified
}
}
@@ -602,6 +992,15 @@
internal val LocalColorScheme = staticCompositionLocalOf { lightColorScheme() }
/**
+ * Composition Local used to check if [ColorScheme.applyTonalElevation] will be applied down the
+ * tree.
+ *
+ * Setting this value to false will cause all subsequent surfaces down the tree to not apply
+ * tonalElevation.
+ */
+val LocalTonalElevationEnabled = staticCompositionLocalOf { true }
+
+/**
* A low level of alpha used to represent disabled components, such as text in a disabled Button.
*/
internal const val DisabledAlpha = 0.38f
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DateInput.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DateInput.kt
index 938e7b3..6e05d30 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DateInput.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DateInput.kt
@@ -42,7 +42,6 @@
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
-import java.util.Locale
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -113,7 +112,7 @@
inputIdentifier: InputIdentifier,
dateInputValidator: DateInputValidator,
dateInputFormat: DateInputFormat,
- locale: Locale,
+ locale: CalendarLocale,
colors: DatePickerColors
) {
val errorText = rememberSaveable { mutableStateOf("") }
@@ -241,12 +240,12 @@
* @param dateToValidate a [CalendarDate] input to validate
* @param inputIdentifier an [InputIdentifier] that provides information about the input field
* that is supposed to hold the date.
- * @param locale the current [Locale]
+ * @param locale the current [CalendarLocale]
*/
fun validate(
dateToValidate: CalendarDate?,
inputIdentifier: InputIdentifier,
- locale: Locale
+ locale: CalendarLocale
): String {
if (dateToValidate == null) {
return errorDatePattern.format(dateInputFormat.patternWithDelimiters.uppercase())
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DatePicker.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DatePicker.kt
index 35bd561..32e3bf0 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DatePicker.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DatePicker.kt
@@ -111,9 +111,7 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
-import java.lang.Integer.max
-import java.text.NumberFormat
-import java.util.Locale
+import kotlin.math.max
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -286,22 +284,29 @@
* January 2023).
*
* @param monthMillis timestamp in _UTC_ milliseconds from the epoch that represents the month
- * @param locale a [Locale] to use when formatting the month and year
+ * @param locale a [CalendarLocale] to use when formatting the month and year
+ *
+ * @see defaultLocale
*/
- fun formatMonthYear(@Suppress("AutoBoxing") monthMillis: Long?, locale: Locale): String?
+ fun formatMonthYear(
+ @Suppress("AutoBoxing") monthMillis: Long?,
+ locale: CalendarLocale
+ ): String?
/**
* Format a given [dateMillis] to a string representation of the date (i.e. Mar 27, 2021).
*
* @param dateMillis timestamp in _UTC_ milliseconds from the epoch that represents the date
- * @param locale a [Locale] to use when formatting the date
+ * @param locale a [CalendarLocale] to use when formatting the date
* @param forContentDescription indicates that the requested formatting is for content
* description. In these cases, the output may include a more descriptive wording that will be
* passed to a screen readers.
+ *
+ * @see defaultLocale
*/
fun formatDate(
@Suppress("AutoBoxing") dateMillis: Long?,
- locale: Locale,
+ locale: CalendarLocale,
forContentDescription: Boolean = false
): String?
}
@@ -1025,7 +1030,7 @@
override fun formatMonthYear(
monthMillis: Long?,
- locale: Locale
+ locale: CalendarLocale
): String? {
if (monthMillis == null) return null
return formatWithSkeleton(monthMillis, yearSelectionSkeleton, locale)
@@ -1033,7 +1038,7 @@
override fun formatDate(
dateMillis: Long?,
- locale: Locale,
+ locale: CalendarLocale,
forContentDescription: Boolean
): String? {
if (dateMillis == null) return null
@@ -1773,11 +1778,10 @@
)
)
// Match the years container color to any elevated surface color that is composed under it.
- val containerColor = if (colors.containerColor == MaterialTheme.colorScheme.surface) {
- MaterialTheme.colorScheme.surfaceColorAtElevation(LocalAbsoluteTonalElevation.current)
- } else {
- colors.containerColor
- }
+ val containerColor = MaterialTheme.colorScheme.applyTonalElevation(
+ backgroundColor = colors.containerColor,
+ elevation = LocalAbsoluteTonalElevation.current
+ )
val coroutineScope = rememberCoroutineScope()
val scrollToEarlierYearsLabel = getString(Strings.DatePickerScrollToShowEarlierYears)
val scrollToLaterYearsLabel = getString(Strings.DatePickerScrollToShowLaterYears)
@@ -2029,16 +2033,6 @@
)
}
-/**
- * Returns a string representation of an integer at the current Locale.
- */
-internal fun Int.toLocalString(): String {
- val formatter = NumberFormat.getIntegerInstance()
- // Eliminate any use of delimiters when formatting the integer.
- formatter.isGroupingUsed = false
- return formatter.format(this)
-}
-
internal val RecommendedSizeForAccessibility = 48.dp
internal val MonthYearHeight = 56.dp
internal val DatePickerHorizontalPadding = 12.dp
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Expect.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Expect.kt
new file mode 100644
index 0000000..baf5d71
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Expect.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.compose.material3
+
+/**
+ * Represents a Locale for the calendar. This locale will be used when formatting dates, determining
+ * the input format, and more.
+ *
+ * Note: For JVM based platforms, this would be equivalent to [java.util.Locale].
+ */
+@ExperimentalMaterial3Api
+expect class CalendarLocale
+
+/**
+ * Returns the default [CalendarLocale].
+ *
+ * Note: For JVM based platforms, this would be equivalent to [java.util.Locale.getDefault].
+ */
+@OptIn(ExperimentalMaterial3Api::class)
+internal expect fun defaultLocale(): CalendarLocale
+
+/**
+ * Returns a string representation of an integer for the current Locale.
+ *
+ * @param minDigits sets the minimum number of digits allowed in the integer portion of a number.
+ * If the minDigits value is greater than the [maxDigits] value, then [maxDigits] will also be set
+ * to this value.
+ * @param maxDigits sets the maximum number of digits allowed in the integer portion of a number.
+ * If this maxDigits value is less than the [minDigits] value, then [minDigits] will also be set to
+ * this value.
+ * @param isGroupingUsed set whether or not grouping will be used when formatting into a local
+ * string. By default, this value is false, which eliminates any use of delimiters when formatting
+ * the integer.
+ */
+internal expect fun Int.toLocalString(
+ minDigits: Int = 1,
+ maxDigits: Int = 40,
+ isGroupingUsed: Boolean = false
+): String
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButton.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButton.kt
index 3df269b..42f3f07 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButton.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButton.kt
@@ -49,11 +49,9 @@
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
-import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.semantics.Role
@@ -62,6 +60,9 @@
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.launch
/**
* <a href="https://m3.material.io/components/floating-action-button/overview" class="external" target="_blank">Material Design floating action button</a>.
@@ -504,9 +505,15 @@
@Composable
private fun animateElevation(interactionSource: InteractionSource): State<Dp> {
- val interactions = remember { mutableStateListOf<Interaction>() }
+ val animatable = remember(interactionSource) {
+ Animatable(defaultElevation, Dp.VectorConverter)
+ }
LaunchedEffect(interactionSource) {
+ var animation: Job? = null
+ var lastTargetInteraction: Interaction? = null
+ var lastTarget: Dp? = null
+ val interactions = mutableListOf<Interaction>()
interactionSource.interactions.collect { interaction ->
when (interaction) {
is HoverInteraction.Enter -> {
@@ -531,33 +538,37 @@
interactions.remove(interaction.press)
}
}
+ val targetInteraction = interactions.lastOrNull()
+ val target = when (targetInteraction) {
+ is PressInteraction.Press -> pressedElevation
+ is HoverInteraction.Enter -> hoveredElevation
+ is FocusInteraction.Focus -> focusedElevation
+ else -> defaultElevation
+ }
+ if (lastTarget != target) {
+ lastTarget = target
+ // Cancel any existing animations if we change target
+ animation?.cancelAndJoin()
+ // We need to handle the case where the target has changed, but the animation
+ // was cancelled so quickly that its internal target never got changed - if
+ // this happened and we are back at the same target before the cancelled
+ // animation, we don't want to do anything.
+ if (animatable.targetValue != target) {
+ animation = launch {
+ try {
+ animatable.animateElevation(
+ from = lastTargetInteraction,
+ to = targetInteraction,
+ target = target
+ )
+ } finally {
+ lastTargetInteraction = targetInteraction
+ }
+ }
+ }
+ }
}
}
-
- val interaction = interactions.lastOrNull()
-
- val target = when (interaction) {
- is PressInteraction.Press -> pressedElevation
- is HoverInteraction.Enter -> hoveredElevation
- is FocusInteraction.Focus -> focusedElevation
- else -> defaultElevation
- }
-
- val animatable = remember { Animatable(target, Dp.VectorConverter) }
-
- LaunchedEffect(target) {
- val lastInteraction = when (animatable.targetValue) {
- pressedElevation -> PressInteraction.Press(Offset.Zero)
- hoveredElevation -> HoverInteraction.Enter()
- focusedElevation -> FocusInteraction.Focus()
- else -> null
- }
- animatable.animateElevation(
- from = lastInteraction,
- to = interaction,
- target = target,
- )
- }
return animatable.asState()
}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Surface.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Surface.kt
index 8165a29..5fd5b82 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Surface.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Surface.kt
@@ -468,19 +468,15 @@
backgroundColor: Color,
border: BorderStroke?,
shadowElevation: Dp
-) = this.shadow(shadowElevation, shape, clip = false)
+) = this
+ .shadow(shadowElevation, shape, clip = false)
.then(if (border != null) Modifier.border(border, shape) else Modifier)
.background(color = backgroundColor, shape = shape)
.clip(shape)
@Composable
-private fun surfaceColorAtElevation(color: Color, elevation: Dp): Color {
- return if (color == MaterialTheme.colorScheme.surface) {
- MaterialTheme.colorScheme.surfaceColorAtElevation(elevation)
- } else {
- color
- }
-}
+private fun surfaceColorAtElevation(color: Color, elevation: Dp): Color =
+ MaterialTheme.colorScheme.applyTonalElevation(color, elevation)
/**
* CompositionLocal containing the current absolute elevation provided by [Surface] components. This
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tab.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tab.kt
index b1cbd6f..bc9ab02 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tab.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tab.kt
@@ -136,7 +136,7 @@
* @param selected whether this tab is selected or not
* @param onClick called when this tab is clicked
* @param text the text label displayed in this tab
- * @param icon the icon displayed in this tab
+ * @param icon the icon displayed in this tab. Should be 24.dp.
* @param modifier the [Modifier] to be applied to this tab
* @param enabled controls the enabled state of this tab. When `false`, this component will not
* respond to user input, and it will appear visually disabled and disabled to accessibility
@@ -314,11 +314,7 @@
) { text() }
}
if (icon != null) {
- Box(
- Modifier
- .layoutId("icon")
- .padding(horizontal = HorizontalTextPadding)
- ) { icon() }
+ Box(Modifier.layoutId("icon")) { icon() }
}
}
) { measurables, constraints ->
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TabRow.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TabRow.kt
index 82d1d85..02ebe39 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TabRow.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TabRow.kt
@@ -189,7 +189,9 @@
var contentWidth =
minOf(tabMeasurables[index].maxIntrinsicWidth(tabRowHeight), tabWidth).toDp()
contentWidth -= HorizontalTextPadding * 2
- TabPosition(tabWidth.toDp() * index, tabWidth.toDp(), contentWidth)
+ // Enforce minimum touch target of 24.dp
+ val indicatorWidth = maxOf(contentWidth, 24.dp)
+ TabPosition(tabWidth.toDp() * index, tabWidth.toDp(), indicatorWidth)
}
layout(tabRowWidth, tabRowHeight) {
@@ -372,7 +374,7 @@
* @property left the left edge's x position from the start of the [TabRow]
* @property right the right edge's x position from the start of the [TabRow]
* @property width the width of this tab
- * @property contentWidth the content width of this tab
+ * @property contentWidth the content width of this tab. Should be a minimum of 24.dp
*/
@Immutable
class TabPosition internal constructor(val left: Dp, val width: Dp, val contentWidth: Dp) {
@@ -458,7 +460,7 @@
@Composable
fun PrimaryIndicator(
modifier: Modifier = Modifier,
- width: Dp = 0.dp,
+ width: Dp = 24.dp,
height: Dp = PrimaryNavigationTabTokens.ActiveIndicatorHeight,
color: Color = PrimaryNavigationTabTokens.ActiveIndicatorColor.toColor(),
shape: Shape = PrimaryNavigationTabTokens.ActiveIndicatorShape
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt
index 3764c75..ca5f3c1 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt
@@ -151,7 +151,6 @@
import androidx.compose.ui.unit.center
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
-import java.text.NumberFormat
import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.atan2
@@ -702,10 +701,10 @@
state: TimePickerState,
) {
var hourValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
- mutableStateOf(TextFieldValue(text = state.hourForDisplay.toLocalString(2)))
+ mutableStateOf(TextFieldValue(text = state.hourForDisplay.toLocalString(minDigits = 2)))
}
var minuteValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
- mutableStateOf(TextFieldValue(text = state.minute.toLocalString(2)))
+ mutableStateOf(TextFieldValue(text = state.minute.toLocalString(minDigits = 2)))
}
Row(
@@ -1306,11 +1305,11 @@
number = value
)
- val text = value.toLocalString(minDigits = 1)
+ val text = value.toLocalString()
val selected = if (state.selection == Selection.Minute) {
- state.minute.toLocalString(minDigits = 1) == text
+ state.minute.toLocalString() == text
} else {
- state.hour.toLocalString(minDigits = 1) == text
+ state.hour.toLocalString() == text
}
Box(
@@ -1669,11 +1668,3 @@
return visible == otherModifier.visible
}
}
-
-private fun Int.toLocalString(minDigits: Int): String {
- val formatter = NumberFormat.getIntegerInstance()
- // Eliminate any use of delimiters when formatting the integer.
- formatter.isGroupingUsed = false
- formatter.minimumIntegerDigits = minDigits
- return formatter.format(this)
-}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TonalPalette.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TonalPalette.kt
index b844ddb..de0c458 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TonalPalette.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TonalPalette.kt
@@ -37,16 +37,27 @@
// Ordered from the lightest shade [neutral100] to the darkest shade [neutral0].
val neutral100: Color,
val neutral99: Color,
+ val neutral98: Color,
+ val neutral96: Color,
val neutral95: Color,
+ val neutral94: Color,
+ val neutral92: Color,
val neutral90: Color,
+ val neutral87: Color,
val neutral80: Color,
val neutral70: Color,
val neutral60: Color,
val neutral50: Color,
val neutral40: Color,
val neutral30: Color,
+ val neutral24: Color,
+ val neutral22: Color,
val neutral20: Color,
+ val neutral17: Color,
+ val neutral12: Color,
val neutral10: Color,
+ val neutral6: Color,
+ val neutral4: Color,
val neutral0: Color,
// The neutral variant tonal range, sometimes called "neutral 2", from the
@@ -122,16 +133,27 @@
TonalPalette(
neutral100 = PaletteTokens.Neutral100,
neutral99 = PaletteTokens.Neutral99,
+ neutral98 = PaletteTokens.Neutral98,
+ neutral96 = PaletteTokens.Neutral96,
neutral95 = PaletteTokens.Neutral95,
+ neutral94 = PaletteTokens.Neutral94,
+ neutral92 = PaletteTokens.Neutral92,
neutral90 = PaletteTokens.Neutral90,
+ neutral87 = PaletteTokens.Neutral87,
neutral80 = PaletteTokens.Neutral80,
neutral70 = PaletteTokens.Neutral70,
neutral60 = PaletteTokens.Neutral60,
neutral50 = PaletteTokens.Neutral50,
neutral40 = PaletteTokens.Neutral40,
neutral30 = PaletteTokens.Neutral30,
+ neutral24 = PaletteTokens.Neutral24,
+ neutral22 = PaletteTokens.Neutral22,
neutral20 = PaletteTokens.Neutral20,
+ neutral17 = PaletteTokens.Neutral17,
+ neutral12 = PaletteTokens.Neutral12,
neutral10 = PaletteTokens.Neutral10,
+ neutral6 = PaletteTokens.Neutral6,
+ neutral4 = PaletteTokens.Neutral4,
neutral0 = PaletteTokens.Neutral0,
neutralVariant100 = PaletteTokens.NeutralVariant100,
neutralVariant99 = PaletteTokens.NeutralVariant99,
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorDarkTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorDarkTokens.kt
index 5487613..5943954 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorDarkTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorDarkTokens.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// VERSION: v0_126
+// VERSION: v0_162
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.compose.material3.tokens
@@ -30,22 +30,41 @@
val OnErrorContainer = PaletteTokens.Error90
val OnPrimary = PaletteTokens.Primary20
val OnPrimaryContainer = PaletteTokens.Primary90
+ val OnPrimaryFixed = PaletteTokens.Primary10
+ val OnPrimaryFixedVariant = PaletteTokens.Primary30
val OnSecondary = PaletteTokens.Secondary20
val OnSecondaryContainer = PaletteTokens.Secondary90
+ val OnSecondaryFixed = PaletteTokens.Secondary10
+ val OnSecondaryFixedVariant = PaletteTokens.Secondary30
val OnSurface = PaletteTokens.Neutral90
val OnSurfaceVariant = PaletteTokens.NeutralVariant80
val OnTertiary = PaletteTokens.Tertiary20
val OnTertiaryContainer = PaletteTokens.Tertiary90
+ val OnTertiaryFixed = PaletteTokens.Tertiary10
+ val OnTertiaryFixedVariant = PaletteTokens.Tertiary30
val Outline = PaletteTokens.NeutralVariant60
val OutlineVariant = PaletteTokens.NeutralVariant30
val Primary = PaletteTokens.Primary80
val PrimaryContainer = PaletteTokens.Primary30
+ val PrimaryFixed = PaletteTokens.Primary90
+ val PrimaryFixedDim = PaletteTokens.Primary80
val Scrim = PaletteTokens.Neutral0
val Secondary = PaletteTokens.Secondary80
val SecondaryContainer = PaletteTokens.Secondary30
+ val SecondaryFixed = PaletteTokens.Secondary90
+ val SecondaryFixedDim = PaletteTokens.Secondary80
val Surface = PaletteTokens.Neutral10
+ val SurfaceBright = PaletteTokens.Neutral24
+ val SurfaceContainer = PaletteTokens.Neutral12
+ val SurfaceContainerHigh = PaletteTokens.Neutral17
+ val SurfaceContainerHighest = PaletteTokens.Neutral22
+ val SurfaceContainerLow = PaletteTokens.Neutral10
+ val SurfaceContainerLowest = PaletteTokens.Neutral4
+ val SurfaceDim = PaletteTokens.Neutral6
val SurfaceTint = Primary
val SurfaceVariant = PaletteTokens.NeutralVariant30
val Tertiary = PaletteTokens.Tertiary80
val TertiaryContainer = PaletteTokens.Tertiary30
+ val TertiaryFixed = PaletteTokens.Tertiary90
+ val TertiaryFixedDim = PaletteTokens.Tertiary80
}
\ No newline at end of file
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorLightTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorLightTokens.kt
index 765b65d..1dbbb2f 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorLightTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorLightTokens.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// VERSION: v0_103
+// VERSION: v0_162
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.compose.material3.tokens
@@ -30,22 +30,41 @@
val OnErrorContainer = PaletteTokens.Error10
val OnPrimary = PaletteTokens.Primary100
val OnPrimaryContainer = PaletteTokens.Primary10
+ val OnPrimaryFixed = PaletteTokens.Primary10
+ val OnPrimaryFixedVariant = PaletteTokens.Primary30
val OnSecondary = PaletteTokens.Secondary100
val OnSecondaryContainer = PaletteTokens.Secondary10
+ val OnSecondaryFixed = PaletteTokens.Secondary10
+ val OnSecondaryFixedVariant = PaletteTokens.Secondary30
val OnSurface = PaletteTokens.Neutral10
val OnSurfaceVariant = PaletteTokens.NeutralVariant30
val OnTertiary = PaletteTokens.Tertiary100
val OnTertiaryContainer = PaletteTokens.Tertiary10
+ val OnTertiaryFixed = PaletteTokens.Tertiary10
+ val OnTertiaryFixedVariant = PaletteTokens.Tertiary30
val Outline = PaletteTokens.NeutralVariant50
val OutlineVariant = PaletteTokens.NeutralVariant80
val Primary = PaletteTokens.Primary40
val PrimaryContainer = PaletteTokens.Primary90
+ val PrimaryFixed = PaletteTokens.Primary90
+ val PrimaryFixedDim = PaletteTokens.Primary80
val Scrim = PaletteTokens.Neutral0
val Secondary = PaletteTokens.Secondary40
val SecondaryContainer = PaletteTokens.Secondary90
+ val SecondaryFixed = PaletteTokens.Secondary90
+ val SecondaryFixedDim = PaletteTokens.Secondary80
val Surface = PaletteTokens.Neutral99
+ val SurfaceBright = PaletteTokens.Neutral98
+ val SurfaceContainer = PaletteTokens.Neutral94
+ val SurfaceContainerHigh = PaletteTokens.Neutral92
+ val SurfaceContainerHighest = PaletteTokens.Neutral90
+ val SurfaceContainerLow = PaletteTokens.Neutral96
+ val SurfaceContainerLowest = PaletteTokens.Neutral100
+ val SurfaceDim = PaletteTokens.Neutral87
val SurfaceTint = Primary
val SurfaceVariant = PaletteTokens.NeutralVariant90
val Tertiary = PaletteTokens.Tertiary40
val TertiaryContainer = PaletteTokens.Tertiary90
+ val TertiaryFixed = PaletteTokens.Tertiary90
+ val TertiaryFixedDim = PaletteTokens.Tertiary80
}
\ No newline at end of file
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorSchemeKeyTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorSchemeKeyTokens.kt
index c1c1104..85acb6f 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorSchemeKeyTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorSchemeKeyTokens.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// VERSION: v0_103
+// VERSION: v0_162
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.compose.material3.tokens
@@ -30,22 +30,41 @@
OnErrorContainer,
OnPrimary,
OnPrimaryContainer,
+ OnPrimaryFixed,
+ OnPrimaryFixedVariant,
OnSecondary,
OnSecondaryContainer,
+ OnSecondaryFixed,
+ OnSecondaryFixedVariant,
OnSurface,
OnSurfaceVariant,
OnTertiary,
OnTertiaryContainer,
+ OnTertiaryFixed,
+ OnTertiaryFixedVariant,
Outline,
OutlineVariant,
Primary,
PrimaryContainer,
+ PrimaryFixed,
+ PrimaryFixedDim,
Scrim,
Secondary,
SecondaryContainer,
+ SecondaryFixed,
+ SecondaryFixedDim,
Surface,
+ SurfaceBright,
+ SurfaceContainer,
+ SurfaceContainerHigh,
+ SurfaceContainerHighest,
+ SurfaceContainerLow,
+ SurfaceContainerLowest,
+ SurfaceDim,
SurfaceTint,
SurfaceVariant,
Tertiary,
TertiaryContainer,
+ TertiaryFixed,
+ TertiaryFixedDim,
}
\ No newline at end of file
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/PaletteTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/PaletteTokens.kt
index 4384b14..3a8eb4c 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/PaletteTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/PaletteTokens.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// VERSION: v0_103
+// VERSION: v0_162
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.compose.material3.tokens
@@ -38,15 +38,26 @@
val Neutral0 = Color(red = 0, green = 0, blue = 0)
val Neutral10 = Color(red = 28, green = 27, blue = 31)
val Neutral100 = Color(red = 255, green = 255, blue = 255)
+ val Neutral12 = Color(red = 32, green = 31, blue = 35)
+ val Neutral17 = Color(red = 43, green = 41, blue = 45)
val Neutral20 = Color(red = 49, green = 48, blue = 51)
+ val Neutral22 = Color(red = 49, green = 48, blue = 51)
+ val Neutral24 = Color(red = 49, green = 48, blue = 51)
val Neutral30 = Color(red = 72, green = 70, blue = 73)
+ val Neutral4 = Color(red = 14, green = 14, blue = 17)
val Neutral40 = Color(red = 96, green = 93, blue = 98)
val Neutral50 = Color(red = 120, green = 117, blue = 121)
+ val Neutral6 = Color(red = 20, green = 19, blue = 23)
val Neutral60 = Color(red = 147, green = 144, blue = 148)
val Neutral70 = Color(red = 174, green = 170, blue = 174)
val Neutral80 = Color(red = 201, green = 197, blue = 202)
+ val Neutral87 = Color(red = 221, green = 216, blue = 221)
val Neutral90 = Color(red = 230, green = 225, blue = 229)
+ val Neutral92 = Color(red = 236, green = 231, blue = 236)
+ val Neutral94 = Color(red = 241, green = 236, blue = 241)
val Neutral95 = Color(red = 244, green = 239, blue = 244)
+ val Neutral96 = Color(red = 247, green = 242, blue = 247)
+ val Neutral98 = Color(red = 253, green = 248, blue = 253)
val Neutral99 = Color(red = 255, green = 251, blue = 254)
val NeutralVariant0 = Color(red = 0, green = 0, blue = 0)
val NeutralVariant10 = Color(red = 29, green = 26, blue = 34)
@@ -101,4 +112,4 @@
val Tertiary95 = Color(red = 255, green = 236, blue = 241)
val Tertiary99 = Color(red = 255, green = 251, blue = 250)
val White = Color(red = 255, green = 255, blue = 255)
-}
+}
\ No newline at end of file
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/TypographyTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/TypographyTokens.kt
index 089c598..863fd9a 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/TypographyTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/TypographyTokens.kt
@@ -20,6 +20,7 @@
import androidx.compose.material3.defaultPlatformTextStyle
import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.style.LineHeightStyle
internal object TypographyTokens {
val BodyLarge =
@@ -144,4 +145,12 @@
)
}
-internal val DefaultTextStyle = TextStyle.Default.copy(platformStyle = defaultPlatformTextStyle())
+internal val DefaultLineHeightStyle = LineHeightStyle(
+ alignment = LineHeightStyle.Alignment.Proportional,
+ trim = LineHeightStyle.Trim.None
+)
+
+internal val DefaultTextStyle = TextStyle.Default.copy(
+ platformStyle = defaultPlatformTextStyle(),
+ lineHeightStyle = DefaultLineHeightStyle,
+)
diff --git a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/CalendarModel.desktop.kt b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/CalendarModel.desktop.kt
index d7859f5..7d4e9f2 100644
--- a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/CalendarModel.desktop.kt
+++ b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/CalendarModel.desktop.kt
@@ -16,10 +16,6 @@
package androidx.compose.material3
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.ReadOnlyComposable
-import java.util.Locale
-
/**
* Returns a [CalendarModel] to be used by the date picker.
*/
@@ -31,13 +27,13 @@
*
* @param utcTimeMillis a UTC timestamp to format (milliseconds from epoch)
* @param skeleton a date format skeleton
- * @param locale the [Locale] to use when formatting the given timestamp
+ * @param locale the [CalendarLocale] to use when formatting the given timestamp
*/
@ExperimentalMaterial3Api
actual fun formatWithSkeleton(
utcTimeMillis: Long,
skeleton: String,
- locale: Locale
+ locale: CalendarLocale
): String {
// Note: there is no equivalent in Java for Android's DateFormat.getBestDateTimePattern.
// The JDK SimpleDateFormat expects a pattern, so the results will be "2023Jan7",
@@ -48,11 +44,3 @@
locale = locale
)
}
-
-/**
- * A composable function that returns the default [Locale].
- */
-@Composable
-@ReadOnlyComposable
-@ExperimentalMaterial3Api
-internal actual fun defaultLocale(): Locale = Locale.getDefault()
diff --git a/compose/material3/material3/src/jvmMain/kotlin/androidx/compose/material3/ActualJvm.kt b/compose/material3/material3/src/jvmMain/kotlin/androidx/compose/material3/ActualJvm.kt
index 65a109b..d9972c6 100644
--- a/compose/material3/material3/src/jvmMain/kotlin/androidx/compose/material3/ActualJvm.kt
+++ b/compose/material3/material3/src/jvmMain/kotlin/androidx/compose/material3/ActualJvm.kt
@@ -18,8 +18,36 @@
package androidx.compose.material3
+import java.text.NumberFormat
+
/* Copy of androidx.compose.material.ActualJvm, mirrored from Foundation. This is used for the
M2/M3-internal copy of MutatorMutex.
*/
internal actual typealias InternalAtomicReference<V> =
- java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+ java.util.concurrent.atomic.AtomicReference<V>
+
+/**
+ * Represents a Locale for the calendar. This locale will be used when formatting dates, determining
+ * the input format, and more.
+ */
+actual typealias CalendarLocale = java.util.Locale
+
+/**
+ * Returns the default [CalendarLocale].
+ */
+internal actual fun defaultLocale(): CalendarLocale = java.util.Locale.getDefault()
+
+/**
+ * Returns a string representation of an integer for the current Locale.
+ */
+internal actual fun Int.toLocalString(
+ minDigits: Int,
+ maxDigits: Int,
+ isGroupingUsed: Boolean
+): String {
+ val formatter = NumberFormat.getIntegerInstance()
+ formatter.isGroupingUsed = isGroupingUsed
+ formatter.minimumIntegerDigits = minDigits
+ formatter.maximumIntegerDigits = maxDigits
+ return formatter.format(this)
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/LegacyCalendarModelImpl.kt b/compose/material3/material3/src/jvmMain/kotlin/androidx/compose/material3/LegacyCalendarModelImpl.kt
similarity index 100%
rename from compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/LegacyCalendarModelImpl.kt
rename to compose/material3/material3/src/jvmMain/kotlin/androidx/compose/material3/LegacyCalendarModelImpl.kt
diff --git a/compose/runtime/runtime/api/current.ignore b/compose/runtime/runtime/api/current.ignore
index 1e4b20b..1a1e78f 100644
--- a/compose/runtime/runtime/api/current.ignore
+++ b/compose/runtime/runtime/api/current.ignore
@@ -1,109 +1,3 @@
// Baseline format: 1.0
-AddedAbstractMethod: androidx.compose.runtime.Composer#getCurrentCompositionLocalMap():
- Added method androidx.compose.runtime.Composer.getCurrentCompositionLocalMap()
-
-
-InvalidNullConversion: androidx.compose.runtime.AbstractApplier#AbstractApplier(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter root in androidx.compose.runtime.AbstractApplier(T root)
-InvalidNullConversion: androidx.compose.runtime.AbstractApplier#down(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter node in androidx.compose.runtime.AbstractApplier.down(T node)
-InvalidNullConversion: androidx.compose.runtime.Applier#down(N) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter node in androidx.compose.runtime.Applier.down(N node)
-InvalidNullConversion: androidx.compose.runtime.Applier#insertBottomUp(int, N) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter instance in androidx.compose.runtime.Applier.insertBottomUp(int index, N instance)
-InvalidNullConversion: androidx.compose.runtime.Applier#insertTopDown(int, N) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter instance in androidx.compose.runtime.Applier.insertTopDown(int index, N instance)
-InvalidNullConversion: androidx.compose.runtime.Composer#apply(V, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.Composer.apply(V value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block)
-InvalidNullConversion: androidx.compose.runtime.ProvidableCompositionLocal#provides(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.ProvidableCompositionLocal.provides(T value)
-InvalidNullConversion: androidx.compose.runtime.ProvidableCompositionLocal#providesDefault(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.ProvidableCompositionLocal.providesDefault(T value)
-InvalidNullConversion: androidx.compose.runtime.SnapshotMutationPolicy#equivalent(T, T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter a in androidx.compose.runtime.SnapshotMutationPolicy.equivalent(T a, T b)
-InvalidNullConversion: androidx.compose.runtime.SnapshotMutationPolicy#equivalent(T, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter b in androidx.compose.runtime.SnapshotMutationPolicy.equivalent(T a, T b)
-InvalidNullConversion: androidx.compose.runtime.SnapshotMutationPolicy#merge(T, T, T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter previous in androidx.compose.runtime.SnapshotMutationPolicy.merge(T previous, T current, T applied)
-InvalidNullConversion: androidx.compose.runtime.SnapshotMutationPolicy#merge(T, T, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter current in androidx.compose.runtime.SnapshotMutationPolicy.merge(T previous, T current, T applied)
-InvalidNullConversion: androidx.compose.runtime.SnapshotMutationPolicy#merge(T, T, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter applied in androidx.compose.runtime.SnapshotMutationPolicy.merge(T previous, T current, T applied)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#collectAsState(kotlinx.coroutines.flow.Flow<? extends T>, R, kotlin.coroutines.CoroutineContext) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.runtime.SnapshotStateKt.collectAsState(kotlinx.coroutines.flow.Flow<? extends T> arg1, R initial, kotlin.coroutines.CoroutineContext context)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#mutableStateOf(T, androidx.compose.runtime.SnapshotMutationPolicy<T>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.SnapshotStateKt.mutableStateOf(T value, androidx.compose.runtime.SnapshotMutationPolicy<T> policy)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#produceState(T, Object, Object, Object, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initialValue in androidx.compose.runtime.SnapshotStateKt.produceState(T initialValue, Object key1, Object key2, Object key3, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> producer)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#produceState(T, Object, Object, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initialValue in androidx.compose.runtime.SnapshotStateKt.produceState(T initialValue, Object key1, Object key2, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> producer)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#produceState(T, Object, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initialValue in androidx.compose.runtime.SnapshotStateKt.produceState(T initialValue, Object key1, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> producer)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#produceState(T, Object[], kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initialValue in androidx.compose.runtime.SnapshotStateKt.produceState(T initialValue, Object[] keys, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> producer)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#produceState(T, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initialValue in androidx.compose.runtime.SnapshotStateKt.produceState(T initialValue, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> producer)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#rememberUpdatedState(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter newValue in androidx.compose.runtime.SnapshotStateKt.rememberUpdatedState(T newValue)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#setValue(androidx.compose.runtime.MutableState<T>, Object, kotlin.reflect.KProperty<?>, T) parameter #3:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.SnapshotStateKt.setValue(androidx.compose.runtime.MutableState<T> arg1, Object thisObj, kotlin.reflect.KProperty<?> property, T value)
-InvalidNullConversion: androidx.compose.runtime.Updater#set(V, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.Updater.set(V value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block)
-InvalidNullConversion: androidx.compose.runtime.Updater#update(V, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.Updater.update(V value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#add(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.add(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#add(int, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.add(int index, T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#contains(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.contains(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#fold(R, kotlin.jvm.functions.Function2<? super R,? super T,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.runtime.collection.MutableVector.fold(R initial, kotlin.jvm.functions.Function2<? super R,? super T,? extends R> operation)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#foldIndexed(R, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super R,? super T,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.runtime.collection.MutableVector.foldIndexed(R initial, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super R,? super T,? extends R> operation)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#foldRight(R, kotlin.jvm.functions.Function2<? super T,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.runtime.collection.MutableVector.foldRight(R initial, kotlin.jvm.functions.Function2<? super T,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#foldRightIndexed(R, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super T,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.runtime.collection.MutableVector.foldRightIndexed(R initial, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super T,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#indexOf(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.indexOf(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#lastIndexOf(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.lastIndexOf(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#minusAssign(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.minusAssign(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#plusAssign(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.plusAssign(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#remove(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.remove(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#set(int, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.set(int index, T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#add(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.add(T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#add(int, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.add(int index, T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#contains(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.contains(T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#indexOf(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.indexOf(T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#lastIndexOf(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.lastIndexOf(T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#remove(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.remove(T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#set(int, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.set(int index, T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#containsKey(K) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter key in androidx.compose.runtime.snapshots.SnapshotStateMap.containsKey(K key)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#containsValue(V) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.snapshots.SnapshotStateMap.containsValue(V value)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#get(Object) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter key in androidx.compose.runtime.snapshots.SnapshotStateMap.get(Object key)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#put(K, V) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter key in androidx.compose.runtime.snapshots.SnapshotStateMap.put(K key, V value)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#put(K, V) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.snapshots.SnapshotStateMap.put(K key, V value)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#remove(Object) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter key in androidx.compose.runtime.snapshots.SnapshotStateMap.remove(Object key)
-
-
-RemovedClass: androidx.compose.runtime.SnapshotStateKt:
- Removed class androidx.compose.runtime.SnapshotStateKt
+RemovedClass: androidx.compose.runtime.PrimitiveSnapshotStateKt:
+ Removed class androidx.compose.runtime.PrimitiveSnapshotStateKt
diff --git a/compose/runtime/runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
index 095c02f..a4bf32d 100644
--- a/compose/runtime/runtime/api/current.txt
+++ b/compose/runtime/runtime/api/current.txt
@@ -431,12 +431,6 @@
property public final boolean isPaused;
}
- public final class PrimitiveSnapshotStateKt {
- method public static inline operator float getValue(androidx.compose.runtime.FloatState, Object? thisObj, kotlin.reflect.KProperty<?> property);
- method @androidx.compose.runtime.snapshots.StateFactoryMarker public static androidx.compose.runtime.MutableFloatState mutableFloatStateOf(float value);
- method public static inline operator void setValue(androidx.compose.runtime.MutableFloatState, Object? thisObj, kotlin.reflect.KProperty<?> property, float value);
- }
-
public interface ProduceStateScope<T> extends androidx.compose.runtime.MutableState<T> kotlinx.coroutines.CoroutineScope {
method public suspend Object? awaitDispose(kotlin.jvm.functions.Function0<kotlin.Unit> onDispose, kotlin.coroutines.Continuation<?>);
}
@@ -536,6 +530,12 @@
method public static inline operator void setValue(androidx.compose.runtime.MutableDoubleState, Object? thisObj, kotlin.reflect.KProperty<?> property, double value);
}
+ public final class SnapshotFloatStateKt {
+ method public static inline operator float getValue(androidx.compose.runtime.FloatState, Object? thisObj, kotlin.reflect.KProperty<?> property);
+ method @androidx.compose.runtime.snapshots.StateFactoryMarker public static androidx.compose.runtime.MutableFloatState mutableFloatStateOf(float value);
+ method public static inline operator void setValue(androidx.compose.runtime.MutableFloatState, Object? thisObj, kotlin.reflect.KProperty<?> property, float value);
+ }
+
public final class SnapshotIntStateKt {
method public static inline operator int getValue(androidx.compose.runtime.IntState, Object? thisObj, kotlin.reflect.KProperty<?> property);
method @androidx.compose.runtime.snapshots.StateFactoryMarker public static androidx.compose.runtime.MutableIntState mutableIntStateOf(int value);
diff --git a/compose/runtime/runtime/api/restricted_current.ignore b/compose/runtime/runtime/api/restricted_current.ignore
index 1e4b20b..1a1e78f 100644
--- a/compose/runtime/runtime/api/restricted_current.ignore
+++ b/compose/runtime/runtime/api/restricted_current.ignore
@@ -1,109 +1,3 @@
// Baseline format: 1.0
-AddedAbstractMethod: androidx.compose.runtime.Composer#getCurrentCompositionLocalMap():
- Added method androidx.compose.runtime.Composer.getCurrentCompositionLocalMap()
-
-
-InvalidNullConversion: androidx.compose.runtime.AbstractApplier#AbstractApplier(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter root in androidx.compose.runtime.AbstractApplier(T root)
-InvalidNullConversion: androidx.compose.runtime.AbstractApplier#down(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter node in androidx.compose.runtime.AbstractApplier.down(T node)
-InvalidNullConversion: androidx.compose.runtime.Applier#down(N) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter node in androidx.compose.runtime.Applier.down(N node)
-InvalidNullConversion: androidx.compose.runtime.Applier#insertBottomUp(int, N) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter instance in androidx.compose.runtime.Applier.insertBottomUp(int index, N instance)
-InvalidNullConversion: androidx.compose.runtime.Applier#insertTopDown(int, N) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter instance in androidx.compose.runtime.Applier.insertTopDown(int index, N instance)
-InvalidNullConversion: androidx.compose.runtime.Composer#apply(V, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.Composer.apply(V value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block)
-InvalidNullConversion: androidx.compose.runtime.ProvidableCompositionLocal#provides(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.ProvidableCompositionLocal.provides(T value)
-InvalidNullConversion: androidx.compose.runtime.ProvidableCompositionLocal#providesDefault(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.ProvidableCompositionLocal.providesDefault(T value)
-InvalidNullConversion: androidx.compose.runtime.SnapshotMutationPolicy#equivalent(T, T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter a in androidx.compose.runtime.SnapshotMutationPolicy.equivalent(T a, T b)
-InvalidNullConversion: androidx.compose.runtime.SnapshotMutationPolicy#equivalent(T, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter b in androidx.compose.runtime.SnapshotMutationPolicy.equivalent(T a, T b)
-InvalidNullConversion: androidx.compose.runtime.SnapshotMutationPolicy#merge(T, T, T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter previous in androidx.compose.runtime.SnapshotMutationPolicy.merge(T previous, T current, T applied)
-InvalidNullConversion: androidx.compose.runtime.SnapshotMutationPolicy#merge(T, T, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter current in androidx.compose.runtime.SnapshotMutationPolicy.merge(T previous, T current, T applied)
-InvalidNullConversion: androidx.compose.runtime.SnapshotMutationPolicy#merge(T, T, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter applied in androidx.compose.runtime.SnapshotMutationPolicy.merge(T previous, T current, T applied)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#collectAsState(kotlinx.coroutines.flow.Flow<? extends T>, R, kotlin.coroutines.CoroutineContext) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.runtime.SnapshotStateKt.collectAsState(kotlinx.coroutines.flow.Flow<? extends T> arg1, R initial, kotlin.coroutines.CoroutineContext context)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#mutableStateOf(T, androidx.compose.runtime.SnapshotMutationPolicy<T>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.SnapshotStateKt.mutableStateOf(T value, androidx.compose.runtime.SnapshotMutationPolicy<T> policy)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#produceState(T, Object, Object, Object, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initialValue in androidx.compose.runtime.SnapshotStateKt.produceState(T initialValue, Object key1, Object key2, Object key3, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> producer)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#produceState(T, Object, Object, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initialValue in androidx.compose.runtime.SnapshotStateKt.produceState(T initialValue, Object key1, Object key2, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> producer)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#produceState(T, Object, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initialValue in androidx.compose.runtime.SnapshotStateKt.produceState(T initialValue, Object key1, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> producer)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#produceState(T, Object[], kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initialValue in androidx.compose.runtime.SnapshotStateKt.produceState(T initialValue, Object[] keys, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> producer)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#produceState(T, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initialValue in androidx.compose.runtime.SnapshotStateKt.produceState(T initialValue, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.ProduceStateScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> producer)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#rememberUpdatedState(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter newValue in androidx.compose.runtime.SnapshotStateKt.rememberUpdatedState(T newValue)
-InvalidNullConversion: androidx.compose.runtime.SnapshotStateKt#setValue(androidx.compose.runtime.MutableState<T>, Object, kotlin.reflect.KProperty<?>, T) parameter #3:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.SnapshotStateKt.setValue(androidx.compose.runtime.MutableState<T> arg1, Object thisObj, kotlin.reflect.KProperty<?> property, T value)
-InvalidNullConversion: androidx.compose.runtime.Updater#set(V, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.Updater.set(V value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block)
-InvalidNullConversion: androidx.compose.runtime.Updater#update(V, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.Updater.update(V value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#add(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.add(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#add(int, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.add(int index, T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#contains(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.contains(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#fold(R, kotlin.jvm.functions.Function2<? super R,? super T,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.runtime.collection.MutableVector.fold(R initial, kotlin.jvm.functions.Function2<? super R,? super T,? extends R> operation)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#foldIndexed(R, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super R,? super T,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.runtime.collection.MutableVector.foldIndexed(R initial, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super R,? super T,? extends R> operation)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#foldRight(R, kotlin.jvm.functions.Function2<? super T,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.runtime.collection.MutableVector.foldRight(R initial, kotlin.jvm.functions.Function2<? super T,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#foldRightIndexed(R, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super T,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.runtime.collection.MutableVector.foldRightIndexed(R initial, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super T,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#indexOf(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.indexOf(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#lastIndexOf(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.lastIndexOf(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#minusAssign(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.minusAssign(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#plusAssign(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.plusAssign(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#remove(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.remove(T element)
-InvalidNullConversion: androidx.compose.runtime.collection.MutableVector#set(int, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.collection.MutableVector.set(int index, T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#add(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.add(T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#add(int, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.add(int index, T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#contains(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.contains(T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#indexOf(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.indexOf(T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#lastIndexOf(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.lastIndexOf(T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#remove(T) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.remove(T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateList#set(int, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter element in androidx.compose.runtime.snapshots.SnapshotStateList.set(int index, T element)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#containsKey(K) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter key in androidx.compose.runtime.snapshots.SnapshotStateMap.containsKey(K key)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#containsValue(V) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.snapshots.SnapshotStateMap.containsValue(V value)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#get(Object) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter key in androidx.compose.runtime.snapshots.SnapshotStateMap.get(Object key)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#put(K, V) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter key in androidx.compose.runtime.snapshots.SnapshotStateMap.put(K key, V value)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#put(K, V) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.runtime.snapshots.SnapshotStateMap.put(K key, V value)
-InvalidNullConversion: androidx.compose.runtime.snapshots.SnapshotStateMap#remove(Object) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter key in androidx.compose.runtime.snapshots.SnapshotStateMap.remove(Object key)
-
-
-RemovedClass: androidx.compose.runtime.SnapshotStateKt:
- Removed class androidx.compose.runtime.SnapshotStateKt
+RemovedClass: androidx.compose.runtime.PrimitiveSnapshotStateKt:
+ Removed class androidx.compose.runtime.PrimitiveSnapshotStateKt
diff --git a/compose/runtime/runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
index 6cfdfcb..8f5a242 100644
--- a/compose/runtime/runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -463,12 +463,6 @@
property public final boolean isPaused;
}
- public final class PrimitiveSnapshotStateKt {
- method public static inline operator float getValue(androidx.compose.runtime.FloatState, Object? thisObj, kotlin.reflect.KProperty<?> property);
- method @androidx.compose.runtime.snapshots.StateFactoryMarker public static androidx.compose.runtime.MutableFloatState mutableFloatStateOf(float value);
- method public static inline operator void setValue(androidx.compose.runtime.MutableFloatState, Object? thisObj, kotlin.reflect.KProperty<?> property, float value);
- }
-
public interface ProduceStateScope<T> extends androidx.compose.runtime.MutableState<T> kotlinx.coroutines.CoroutineScope {
method public suspend Object? awaitDispose(kotlin.jvm.functions.Function0<kotlin.Unit> onDispose, kotlin.coroutines.Continuation<?>);
}
@@ -572,6 +566,12 @@
method public static inline operator void setValue(androidx.compose.runtime.MutableDoubleState, Object? thisObj, kotlin.reflect.KProperty<?> property, double value);
}
+ public final class SnapshotFloatStateKt {
+ method public static inline operator float getValue(androidx.compose.runtime.FloatState, Object? thisObj, kotlin.reflect.KProperty<?> property);
+ method @androidx.compose.runtime.snapshots.StateFactoryMarker public static androidx.compose.runtime.MutableFloatState mutableFloatStateOf(float value);
+ method public static inline operator void setValue(androidx.compose.runtime.MutableFloatState, Object? thisObj, kotlin.reflect.KProperty<?> property, float value);
+ }
+
public final class SnapshotIntStateKt {
method public static inline operator int getValue(androidx.compose.runtime.IntState, Object? thisObj, kotlin.reflect.KProperty<?> property);
method @androidx.compose.runtime.snapshots.StateFactoryMarker public static androidx.compose.runtime.MutableIntState mutableIntStateOf(int value);
diff --git a/compose/runtime/runtime/src/androidMain/baseline-prof.txt b/compose/runtime/runtime/src/androidMain/baseline-prof.txt
index 1afd49d..ea25040 100644
--- a/compose/runtime/runtime/src/androidMain/baseline-prof.txt
+++ b/compose/runtime/runtime/src/androidMain/baseline-prof.txt
@@ -53,6 +53,10 @@
HSPLandroidx/compose/runtime/SlotTableKt;->**(**)**
HSPLandroidx/compose/runtime/SlotWriter;->**(**)**
HSPLandroidx/compose/runtime/SnapshotMutableStateImpl**->**(**)**
+HSPLandroidx/compose/runtime/SnapshotDoubleStateKt**->**(**)**
+HSPLandroidx/compose/runtime/SnapshotFloatStateKt**->**(**)**
+HSPLandroidx/compose/runtime/SnapshotIntStateKt**->**(**)**
+HSPLandroidx/compose/runtime/SnapshotLongStateKt**->**(**)**
HSPLandroidx/compose/runtime/SnapshotStateKt**->**(**)**
HSPLandroidx/compose/runtime/SnapshotThreadLocal;->**(**)**
HSPLandroidx/compose/runtime/StaticProvidableCompositionLocal;->**(**)**
diff --git a/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/internal/FloatingPointEquality.android.kt b/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/internal/FloatingPointEquality.android.kt
new file mode 100644
index 0000000..61845d3
--- /dev/null
+++ b/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/internal/FloatingPointEquality.android.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.compose.runtime.internal
+
+import android.os.Build
+
+/**
+ * Returns `true` if the receiver is an expression of [Float.NaN]. There is not one single encoding
+ * of `NaN`. A float encodes NaN if its exponent bits (the 8 most significant bits which follow the
+ * single most significant bit in the float, which encodes the sign) are all set to `1`, and the
+ * significand bits (the 23 least significant bits) are not all zeros.
+ */
+internal val Float.isNan: Boolean
+ get() = (this.toRawBits() and 0x7FFFFFFF) > 0x7F800000
+
+/**
+ * Returns `true` if the receiver is an expression of [Double.NaN]. There is not one single encoding
+ * of `NaN`. A double encodes NaN if its exponent bits (the 11 most significant bits which follow
+ * the single most significant bit in the double, which encodes the sign) are all set to `1`, and
+ * the significand bits (the 53 least significant bits) are not all zeros.
+ */
+internal val Double.isNan: Boolean
+ get() = (this.toRawBits() and 0x7FFFFFFFFFFFFFFF) > 0x7FF0000000000000
+
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun Float.equalsWithNanFix(other: Float): Boolean =
+ if (Build.VERSION.SDK_INT >= 23) {
+ this == other
+ } else {
+ !this.isNan && !other.isNan && this == other
+ }
+
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun Double.equalsWithNanFix(other: Double): Boolean =
+ if (Build.VERSION.SDK_INT >= 23) {
+ this == other
+ } else {
+ !this.isNan && !other.isNan && this == other
+ }
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
index 2164a56..67e81fc 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
@@ -28,5 +28,5 @@
* IMPORTANT: Whenever updating this value, please make sure to also update `versionTable` and
* `minimumRuntimeVersionInt` in `VersionChecker.kt` of the compiler.
*/
- const val version: Int = 10101
+ const val version: Int = 10200
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
index 06356b3..6452429 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
@@ -665,6 +665,12 @@
}
override fun observesAnyOf(values: Set<Any>): Boolean {
+ if (values is IdentityArraySet<Any>) {
+ values.fastForEach { value ->
+ if (value in observations || value in derivedStates) return true
+ }
+ return false
+ }
for (value in values) {
if (value in observations || value in derivedStates) return true
}
@@ -743,7 +749,7 @@
// Record derived state dependency mapping
if (value is DerivedState<*>) {
derivedStates.removeScope(value)
- for (dependency in value.dependencies) {
+ for (dependency in value.currentRecord.dependencies) {
// skip over empty objects from dependency array
if (dependency == null) break
derivedStates.add(dependency, value)
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/DerivedState.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/DerivedState.kt
index a131262..10bc8c4 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/DerivedState.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/DerivedState.kt
@@ -39,17 +39,9 @@
*/
internal interface DerivedState<T> : State<T> {
/**
- * The value of the derived state retrieved without triggering a notification to read observers.
+ * Provides a current [Record].
*/
- val currentValue: T
-
- /**
- * A list of the dependencies used to produce [value] or [currentValue].
- *
- * The [dependencies] list can be used to determine when a [StateObject] appears in the apply
- * observer set, if the state could affect value of this derived state.
- */
- val dependencies: Array<Any?>
+ val currentRecord: Record<T>
/**
* Mutation policy that controls how changes are handled after state dependencies update.
@@ -57,6 +49,21 @@
* produced and it is up to observer to invalidate it correctly.
*/
val policy: SnapshotMutationPolicy<T>?
+
+ interface Record<T> {
+ /**
+ * The value of the derived state retrieved without triggering a notification to read observers.
+ */
+ val currentValue: T
+
+ /**
+ * A list of the dependencies used to produce [value] or [currentValue].
+ *
+ * The [dependencies] list can be used to determine when a [StateObject] appears in the apply
+ * observer set, if the state could affect value of this derived state.
+ */
+ val dependencies: Array<Any?>
+ }
}
private val calculationBlockNestedLevel = SnapshotThreadLocal<Int>()
@@ -67,31 +74,48 @@
) : StateObject, DerivedState<T> {
private var first: ResultRecord<T> = ResultRecord()
- class ResultRecord<T> : StateRecord() {
+ class ResultRecord<T> : StateRecord(), DerivedState.Record<T> {
companion object {
val Unset = Any()
}
- var dependencies: IdentityArrayMap<StateObject, Int>? = null
+ var validSnapshotId: Int = 0
+ var validSnapshotWriteCount: Int = 0
+
+ var _dependencies: IdentityArrayMap<StateObject, Int>? = null
var result: Any? = Unset
var resultHash: Int = 0
override fun assign(value: StateRecord) {
@Suppress("UNCHECKED_CAST")
val other = value as ResultRecord<T>
- dependencies = other.dependencies
+ _dependencies = other._dependencies
result = other.result
resultHash = other.resultHash
}
override fun create(): StateRecord = ResultRecord<T>()
- fun isValid(derivedState: DerivedState<*>, snapshot: Snapshot): Boolean =
- result !== Unset && resultHash == readableHash(derivedState, snapshot)
+ fun isValid(derivedState: DerivedState<*>, snapshot: Snapshot): Boolean {
+ val snapshotChanged = sync {
+ validSnapshotId != snapshot.id || validSnapshotWriteCount != snapshot.writeCount
+ }
+ val isValid = result !== Unset &&
+ (!snapshotChanged || resultHash == readableHash(derivedState, snapshot))
+
+ if (isValid && snapshotChanged) {
+ sync {
+ validSnapshotId = snapshot.id
+ validSnapshotWriteCount = snapshot.writeCount
+ }
+ }
+
+ return isValid
+ }
fun readableHash(derivedState: DerivedState<*>, snapshot: Snapshot): Int {
var hash = 7
- val dependencies = sync { dependencies }
+ val dependencies = sync { _dependencies }
if (dependencies != null) {
notifyObservers(derivedState) {
dependencies.forEach { stateObject, readLevel ->
@@ -117,6 +141,13 @@
}
return hash
}
+
+ override val currentValue: T
+ @Suppress("UNCHECKED_CAST")
+ get() = result as T
+
+ override val dependencies: Array<Any?>
+ get() = _dependencies?.keys ?: emptyArray()
}
/**
@@ -126,7 +157,6 @@
* @return latest state record for the derived state.
*/
fun current(snapshot: Snapshot): StateRecord =
- @Suppress("UNCHECKED_CAST")
currentRecord(current(first, snapshot), snapshot, false, calculation)
private fun currentRecord(
@@ -140,7 +170,7 @@
// for correct invalidation later
if (forceDependencyReads) {
notifyObservers(this) {
- val dependencies = readable.dependencies
+ val dependencies = readable._dependencies
val invalidationNestedLevel = calculationBlockNestedLevel.get() ?: 0
dependencies?.forEach { dependency, nestedLevel ->
calculationBlockNestedLevel.set(nestedLevel + invalidationNestedLevel)
@@ -184,13 +214,17 @@
@Suppress("UNCHECKED_CAST")
policy?.equivalent(result, readable.result as T) == true
) {
- readable.dependencies = newDependencies
+ readable._dependencies = newDependencies
readable.resultHash = readable.readableHash(this, currentSnapshot)
+ readable.validSnapshotId = snapshot.id
+ readable.validSnapshotWriteCount = snapshot.writeCount
readable
} else {
val writable = first.newWritableRecord(this, currentSnapshot)
- writable.dependencies = newDependencies
+ writable._dependencies = newDependencies
writable.resultHash = writable.readableHash(this, currentSnapshot)
+ writable.validSnapshotId = snapshot.id
+ writable.validSnapshotWriteCount = snapshot.writeCount
writable.result = result
writable
}
@@ -224,18 +258,11 @@
}
}
- override val currentValue: T
- get() = first.withCurrent {
- @Suppress("UNCHECKED_CAST")
- currentRecord(it, Snapshot.current, false, calculation).result as T
+ override val currentRecord: DerivedState.Record<T> get() {
+ return first.withCurrent {
+ currentRecord(it, Snapshot.current, false, calculation)
}
-
- override val dependencies: Array<Any?>
- get() = first.withCurrent {
- val record = currentRecord(it, Snapshot.current, false, calculation)
- @Suppress("UNCHECKED_CAST")
- record.dependencies?.keys ?: emptyArray()
- }
+ }
override fun toString(): String = first.withCurrent {
"DerivedState(value=${displayValue()})@${hashCode()}"
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/RecomposeScopeImpl.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/RecomposeScopeImpl.kt
index 38a8945..61f8d70 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/RecomposeScopeImpl.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/RecomposeScopeImpl.kt
@@ -269,7 +269,7 @@
val tracked = trackedDependencies ?: IdentityArrayMap<DerivedState<*>, Any?>().also {
trackedDependencies = it
}
- tracked[instance] = instance.currentValue
+ tracked[instance] = instance.currentRecord.currentValue
}
return false
@@ -299,7 +299,7 @@
@Suppress("UNCHECKED_CAST")
it as DerivedState<Any?>
val policy = it.policy ?: structuralEqualityPolicy()
- policy.equivalent(it.currentValue, trackedDependencies[it])
+ policy.equivalent(it.currentRecord.currentValue, trackedDependencies[it])
}
}
)
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
index faf8739..9f0fbfc 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
@@ -504,6 +504,8 @@
val toApply = mutableListOf<ControlledComposition>()
val toLateApply = mutableSetOf<ControlledComposition>()
val toComplete = mutableSetOf<ControlledComposition>()
+ val modifiedValues = IdentityArraySet<Any>()
+ val alreadyComposed = IdentityArraySet<ControlledComposition>()
fun clearRecompositionState() {
toRecompose.clear()
@@ -511,6 +513,8 @@
toApply.clear()
toLateApply.clear()
toComplete.clear()
+ modifiedValues.clear()
+ alreadyComposed.clear()
}
fun fillToInsert() {
@@ -557,8 +561,8 @@
}
// Perform recomposition for any invalidated composers
- val modifiedValues = IdentityArraySet<Any>()
- val alreadyComposed = IdentityArraySet<ControlledComposition>()
+ modifiedValues.clear()
+ alreadyComposed.clear()
while (toRecompose.isNotEmpty() || toInsert.isNotEmpty()) {
try {
toRecompose.fastForEach { composition ->
@@ -613,7 +617,7 @@
// Perform apply changes
try {
// We could do toComplete += toApply but doing it like below
- // avoids unncessary allocations since toApply is a mutable list
+ // avoids unnecessary allocations since toApply is a mutable list
// toComplete += toApply
toApply.fastForEach { composition ->
toComplete.add(composition)
@@ -669,6 +673,8 @@
// sendApplyNotifications to ensure that objects that were _created_ in this
// snapshot are also considered changed after this point.
Snapshot.notifyObjectsInitialized()
+ alreadyComposed.clear()
+ modifiedValues.clear()
}
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SnapshotDoubleState.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SnapshotDoubleState.kt
index 8521c5a..3868163 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SnapshotDoubleState.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SnapshotDoubleState.kt
@@ -19,6 +19,7 @@
package androidx.compose.runtime
import androidx.compose.runtime.internal.JvmDefaultWithCompatibility
+import androidx.compose.runtime.internal.equalsWithNanFix
import androidx.compose.runtime.snapshots.AutoboxingStateValueProperty
import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.runtime.snapshots.SnapshotMutableState
@@ -136,7 +137,7 @@
override var doubleValue: Double
get() = next.readable(this).value
set(value) = next.withCurrent {
- if (it.value != value) {
+ if (!it.value.equalsWithNanFix(value)) {
next.overwritable(this, it) { this.value = value }
}
}
@@ -161,7 +162,7 @@
): StateRecord? {
val currentRecord = current as DoubleStateStateRecord
val appliedRecord = applied as DoubleStateStateRecord
- return if (currentRecord.value == appliedRecord.value) {
+ return if (currentRecord.value.equalsWithNanFix(appliedRecord.value)) {
current
} else {
null
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SnapshotFloatState.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SnapshotFloatState.kt
index fa6bfe5..7158d09 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SnapshotFloatState.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SnapshotFloatState.kt
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-@file:JvmName("PrimitiveSnapshotStateKt")
+@file:JvmName("SnapshotFloatStateKt")
@file:JvmMultifileClass
package androidx.compose.runtime
+import androidx.compose.runtime.internal.equalsWithNanFix
import androidx.compose.runtime.snapshots.AutoboxingStateValueProperty
import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.runtime.snapshots.SnapshotMutableState
@@ -132,7 +133,7 @@
override var floatValue: Float
get() = next.readable(this).value
set(value) = next.withCurrent {
- if (it.value != value) {
+ if (!it.value.equalsWithNanFix(value)) {
next.overwritable(this, it) { this.value = value }
}
}
@@ -157,7 +158,7 @@
): StateRecord? {
val currentRecord = current as FloatStateStateRecord
val appliedRecord = applied as FloatStateStateRecord
- return if (currentRecord.value == appliedRecord.value) {
+ return if (currentRecord.value.equalsWithNanFix(appliedRecord.value)) {
current
} else {
null
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode.kt
index 74b242f..b6093de2 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode.kt
@@ -347,6 +347,7 @@
}
private fun collisionContainsKey(key: K): Boolean {
+ @Suppress("SteppedForLoop")
for (i in 0 until buffer.size step ENTRY_SIZE) {
if (key == buffer[i]) return true
}
@@ -354,6 +355,7 @@
}
private fun collisionGet(key: K): V? {
+ @Suppress("SteppedForLoop")
for (i in 0 until buffer.size step ENTRY_SIZE) {
if (key == keyAtIndex(i)) {
return valueAtKeyIndex(i)
@@ -363,6 +365,7 @@
}
private fun collisionPut(key: K, value: V): ModificationResult<K, V>? {
+ @Suppress("SteppedForLoop")
for (i in 0 until buffer.size step ENTRY_SIZE) {
if (key == keyAtIndex(i)) {
if (value === valueAtKeyIndex(i)) {
@@ -379,6 +382,7 @@
private fun mutableCollisionPut(key: K, value: V, mutator: PersistentHashMapBuilder<K, V>): TrieNode<K, V> {
// Check if there is an entry with the specified key.
+ @Suppress("SteppedForLoop")
for (i in 0 until buffer.size step ENTRY_SIZE) {
if (key == keyAtIndex(i)) { // found entry with the specified key
mutator.operationResult = valueAtKeyIndex(i)
@@ -404,6 +408,7 @@
}
private fun collisionRemove(key: K): TrieNode<K, V>? {
+ @Suppress("SteppedForLoop")
for (i in 0 until buffer.size step ENTRY_SIZE) {
if (key == keyAtIndex(i)) {
return collisionRemoveEntryAtIndex(i)
@@ -413,6 +418,7 @@
}
private fun mutableCollisionRemove(key: K, mutator: PersistentHashMapBuilder<K, V>): TrieNode<K, V>? {
+ @Suppress("SteppedForLoop")
for (i in 0 until buffer.size step ENTRY_SIZE) {
if (key == keyAtIndex(i)) {
return mutableCollisionRemoveEntryAtIndex(i, mutator)
@@ -422,6 +428,7 @@
}
private fun collisionRemove(key: K, value: V): TrieNode<K, V>? {
+ @Suppress("SteppedForLoop")
for (i in 0 until buffer.size step ENTRY_SIZE) {
if (key == keyAtIndex(i) && value == valueAtKeyIndex(i)) {
return collisionRemoveEntryAtIndex(i)
@@ -431,6 +438,7 @@
}
private fun mutableCollisionRemove(key: K, value: V, mutator: PersistentHashMapBuilder<K, V>): TrieNode<K, V>? {
+ @Suppress("SteppedForLoop")
for (i in 0 until buffer.size step ENTRY_SIZE) {
if (key == keyAtIndex(i) && value == valueAtKeyIndex(i)) {
return mutableCollisionRemoveEntryAtIndex(i, mutator)
@@ -448,6 +456,7 @@
assert(otherNode.dataMap == 0)
val tempBuffer = this.buffer.copyOf(newSize = this.buffer.size + otherNode.buffer.size)
var i = this.buffer.size
+ @Suppress("SteppedForLoop")
for (j in 0 until otherNode.buffer.size step ENTRY_SIZE) {
@Suppress("UNCHECKED_CAST")
if (!this.collisionContainsKey(otherNode.buffer[j] as K)) {
@@ -548,6 +557,7 @@
if (this === otherNode) return true
if (nodeMap != otherNode.nodeMap) return false
if (dataMap != otherNode.dataMap) return false
+ @Suppress("SteppedForLoop")
for (i in 0 until buffer.size) {
if(buffer[i] !== otherNode.buffer[i]) return false
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/FloatingPointEquality.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/FloatingPointEquality.kt
new file mode 100644
index 0000000..0404016
--- /dev/null
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/FloatingPointEquality.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.runtime.internal
+
+/**
+ * A backwards-compatible comparison check which returns true if the receiver and the [other]
+ * operands are equal to each other. Equality as specified in the IEEE-754 standard. If at least
+ * one operand is `NaN`, the result will always be `false`. The sign bit is ignored for operands
+ * that are zero (i.e. +0 and -0 will always be equal to one another). All other comparisons check
+ * the logical value of the float.
+ *
+ * This implementation is needed for proper behavior on x86 builds of Android SDK levels 21 and 22,
+ * which contain a bug where [Float.NaN] is equal to every other [Float] value.
+ *
+ * See [issue 281205384](b/281205384).
+ */
+internal expect inline fun Float.equalsWithNanFix(other: Float): Boolean
+
+/**
+ * A backwards-compatible comparison check which returns true if the receiver and the [other]
+ * operands are equal to each other. Equality as specified in the IEEE-754 standard. If at least
+ * one operand is `NaN`, the result will always be `false`. The sign bit is ignored for operands
+ * that are zero (i.e. +0 and -0 will always be equal to one another). All other comparisons check
+ * the logical value of the double.
+ *
+ * This implementation is needed for proper behavior on x86 builds of Android SDK levels 21 and 22,
+ * which contain a bug where [Double.NaN] is equal to every other [Double] value.
+ *
+ * See [issue 281205384](b/281205384).
+ */
+internal expect inline fun Double.equalsWithNanFix(other: Double): Boolean
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
index 1df196c..93559f9 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
@@ -63,6 +63,13 @@
open var id: Int = id
internal set
+ internal open var writeCount: Int
+ get() = 0
+ @Suppress("UNUSED_PARAMETER")
+ set(value) {
+ error("Updating write count is not supported for this snapshot")
+ }
+
/**
* The root snapshot for this snapshot. For non-nested snapshots this is always `this`. For
* nested snapshot it is the parent's [root].
@@ -505,11 +512,11 @@
advanceGlobalSnapshot(emptyLambda)
sync {
- applyObservers.add(observer)
+ applyObservers += observer
}
return ObserverHandle {
sync {
- applyObservers.remove(observer)
+ applyObservers -= observer
}
}
}
@@ -532,12 +539,12 @@
*/
fun registerGlobalWriteObserver(observer: ((Any) -> Unit)): ObserverHandle {
sync {
- globalWriteObservers.add(observer)
+ globalWriteObservers += observer
}
advanceGlobalSnapshot()
return ObserverHandle {
sync {
- globalWriteObservers.remove(observer)
+ globalWriteObservers -= observer
}
advanceGlobalSnapshot()
}
@@ -726,7 +733,7 @@
takeNewGlobalSnapshot(previousGlobalSnapshot, emptyLambda)
val previousModified = previousGlobalSnapshot.modified
if (!previousModified.isNullOrEmpty()) {
- observers = applyObservers.toMutableList()
+ observers = applyObservers
globalModified = previousModified
}
} else {
@@ -746,7 +753,7 @@
this.modified = null
previousGlobalSnapshot.modified = null
- observers = applyObservers.toMutableList()
+ observers = applyObservers
globalModified = previousModified
}
}
@@ -1021,6 +1028,8 @@
(modified ?: IdentityArraySet<StateObject>().also { modified = it }).add(state)
}
+ override var writeCount: Int = 0
+
override var modified: IdentityArraySet<StateObject>? = null
internal var merged: List<StateObject>? = null
@@ -1311,15 +1320,7 @@
MutableSnapshot(
id, invalid, null,
sync {
- // Take a defensive copy of the globalWriteObservers list. This then avoids having to
- // synchronized access to writerObserver in places it is called and allows the list to
- // change while notifications are being dispatched. Changes to globalWriteObservers force
- // a new global snapshot to be created.
- (
- if (globalWriteObservers.isNotEmpty()) {
- globalWriteObservers.toMutableList()
- } else null
- )?.let {
+ globalWriteObservers.let {
it.singleOrNull() ?: { state: Any ->
it.fastForEach { it(state) }
}
@@ -1501,6 +1502,12 @@
@Suppress("UNUSED_PARAMETER")
set(value) = unsupported()
+ override var writeCount: Int
+ get() = currentSnapshot.writeCount
+ set(value) {
+ currentSnapshot.writeCount = value
+ }
+
override val readOnly: Boolean
get() = currentSnapshot.readOnly
@@ -1731,10 +1738,10 @@
private val extraStateObjects = SnapshotWeakSet<StateObject>()
/** A list of apply observers */
-private val applyObservers = mutableListOf<(Set<Any>, Snapshot) -> Unit>()
+private var applyObservers = emptyList<(Set<Any>, Snapshot) -> Unit>()
/** A list of observers of writes to the global state. */
-private val globalWriteObservers = mutableListOf<((Any) -> Unit)>()
+private var globalWriteObservers = emptyList<(Any) -> Unit>()
private val currentGlobalSnapshot = AtomicReference(
GlobalSnapshot(
@@ -1803,8 +1810,7 @@
// observers.
modified?.let {
try {
- val observers: List<(Set<Any>, Snapshot) -> Unit> =
- sync { applyObservers.toMutableList() }
+ val observers = applyObservers
observers.fastForEach { observer ->
observer(it, previousGlobalSnapshot)
}
@@ -1833,7 +1839,20 @@
}
private fun validateOpen(snapshot: Snapshot) {
- if (!openSnapshots.get(snapshot.id)) error("Snapshot is not open")
+ val openSnapshots = openSnapshots
+ if (!openSnapshots.get(snapshot.id)) {
+ error(
+ "Snapshot is not open: id=${
+ snapshot.id
+ }, disposed=${
+ snapshot.disposed
+ }, applied=${
+ (snapshot as? MutableSnapshot)?.applied ?: "read-only"
+ }, lowestPin=${
+ sync { pinningTable.lowestOrDefault(-1) }
+ }"
+ )
+ }
}
/**
@@ -2119,6 +2138,7 @@
@PublishedApi
internal fun notifyWrite(snapshot: Snapshot, state: StateObject) {
+ snapshot.writeCount += 1
snapshot.writeObserver?.invoke(state)
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
index 43a64f5..9cfcca0 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
@@ -380,7 +380,8 @@
/**
* Counter for skipping reads inside derived states. If count is > 0, read happens inside
* a derived state.
- * Reads for derived states are captured separately through [DerivedState.dependencies].
+ * Reads for derived states are captured separately through
+ * [DerivedState.Record.dependencies].
*/
private var deriveStateScopeCount = 0
@@ -423,10 +424,11 @@
val previousToken = recordedValues.add(value, currentToken)
if (value is DerivedState<*> && previousToken != currentToken) {
+ val record = value.currentRecord
// re-read the value before removing dependencies, in case the new value wasn't read
- recordedDerivedStateValues[value] = value.currentValue
+ recordedDerivedStateValues[value] = record.currentValue
- val dependencies = value.dependencies
+ val dependencies = record.dependencies
val dependencyToDerivedStates = dependencyToDerivedStates
dependencyToDerivedStates.removeScope(value)
@@ -542,7 +544,11 @@
val policy = derivedState.policy ?: structuralEqualityPolicy()
// Invalidate only if currentValue is different than observed on read
- if (!policy.equivalent(derivedState.currentValue, previousValue)) {
+ if (!policy.equivalent(
+ derivedState.currentRecord.currentValue,
+ previousValue
+ )
+ ) {
valueToScopes.forEachScopeOf(derivedState) { scope ->
invalidated.add(scope)
hasValues = true
diff --git a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/internal/FloatingPointEqualityTest.kt b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/internal/FloatingPointEqualityTest.kt
new file mode 100644
index 0000000..978dd87
--- /dev/null
+++ b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/internal/FloatingPointEqualityTest.kt
@@ -0,0 +1,178 @@
+/*
+ * 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.runtime.internal
+
+import kotlin.test.Test
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+
+class FloatingPointEqualityTest {
+
+ @Test
+ fun testFloat_arbitraryValueEquality() {
+ assertEqualsWithNanFix(12345f, 12345f)
+ assertEqualsWithNanFix(-98.076f, -98.076f)
+ assertNotEqualsWithNanFix(12.34f, 12.30f)
+ }
+
+ @Test
+ fun testFloat_inequalityFromLossOfPrecision() {
+ assertNotEqualsWithNanFix(0.5f, 0.01f * 5)
+ }
+
+ @Test
+ fun testFloat_nanConstant_doesNotEqualItself() {
+ assertNotEqualsWithNanFix(Float.NaN, Float.NaN)
+ }
+
+ @Test
+ fun testFloat_nonCanonicalNans_areNotEqual() {
+ val unconventionalNan = Float.fromBits(0x7FC0ABCD)
+ assertNotEqualsWithNanFix(unconventionalNan, unconventionalNan)
+ }
+
+ @Test
+ fun testFloat_negativeZero_doesEqualsPositiveZero() {
+ assertEqualsWithNanFix(Float.NegativeZero, 0f)
+ }
+
+ @Test
+ fun testFloat_negativeZero_equalsNegativeZero() {
+ assertEqualsWithNanFix(Float.NegativeZero, Float.NegativeZero)
+ }
+
+ @Test
+ fun testFloat_positiveZero_equalsPositiveZero() {
+ assertEqualsWithNanFix(0f, 0f)
+ }
+
+ @Test
+ fun testFloat_positiveInfinity_EqualsPositiveInfinity() {
+ assertEqualsWithNanFix(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)
+ }
+
+ @Test
+ fun testFloat_negativeInfinity_doesNotEqualPositiveInfinity() {
+ assertNotEqualsWithNanFix(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY)
+ }
+
+ @Test
+ fun testFloat_negativeInfinity_equalsNegativeInfinity() {
+ assertEqualsWithNanFix(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY)
+ }
+
+ @Test
+ fun testDouble_arbitraryValueEquality() {
+ assertEqualsWithNanFix(12345.0, 12345.0)
+ assertEqualsWithNanFix(-98.076, -98.076)
+ assertNotEqualsWithNanFix(12.34, 12.30)
+ }
+
+ @Test
+ fun testDouble_inequalityFromLossOfPrecision() {
+ assertNotEqualsWithNanFix(0.5, 0.01 * 5)
+ }
+
+ @Test
+ fun testDouble_nanConstant_doesNotEqualItself() {
+ assertNotEqualsWithNanFix(Double.NaN, Double.NaN)
+ }
+
+ @Test
+ fun testDouble_nonCanonicalNans_areNotEqual() {
+ val unconventionalNan = Double.fromBits(0x7FF0ABCDEF123456)
+ assertNotEqualsWithNanFix(unconventionalNan, unconventionalNan)
+ }
+
+ @Test
+ fun testDouble_negativeZero_doesEqualsPositiveZero() {
+ assertEqualsWithNanFix(Double.NegativeZero, 0f)
+ }
+
+ @Test
+ fun testDouble_negativeZero_equalsNegativeZero() {
+ assertEqualsWithNanFix(Double.NegativeZero, Double.NegativeZero)
+ }
+
+ @Test
+ fun testDouble_positiveZero_equalsPositiveZero() {
+ assertEqualsWithNanFix(0f, 0f)
+ }
+
+ @Test
+ fun testDouble_positiveInfinity_EqualsPositiveInfinity() {
+ assertEqualsWithNanFix(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)
+ }
+
+ @Test
+ fun testDouble_negativeInfinity_doesNotEqualPositiveInfinity() {
+ assertNotEqualsWithNanFix(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)
+ }
+
+ @Test
+ fun testDouble_negativeInfinity_equalsNegativeInfinity() {
+ assertEqualsWithNanFix(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY)
+ }
+
+ private fun assertNotEqualsWithNanFix(
+ first: Float,
+ second: Float
+ ) = assertFalse(
+ message = "$first (${first.bitString}) == $second (${second.bitString}) " +
+ "returned true, expected false",
+ actual = first.equalsWithNanFix(second)
+ )
+
+ private fun assertEqualsWithNanFix(
+ first: Float,
+ second: Float
+ ) = assertTrue(
+ message = "$first (${first.bitString}) == $second (${second.bitString}) " +
+ "returned false, expected true",
+ actual = first.equalsWithNanFix(second)
+ )
+
+ private fun assertNotEqualsWithNanFix(
+ first: Double,
+ second: Double
+ ) = assertFalse(
+ message = "$first (${first.bitString}) == $second (${second.bitString}) " +
+ "returned true, expected false",
+ actual = first.equalsWithNanFix(second)
+ )
+
+ private fun assertEqualsWithNanFix(
+ first: Double,
+ second: Double
+ ) = assertTrue(
+ message = "$first (${first.bitString}) == $second (${second.bitString}) " +
+ "returned false, expected true",
+ actual = first.equalsWithNanFix(second)
+ )
+
+ private val Float.bitString
+ get() = "0x" + toBits().toUInt().toString(16).padStart(length = 8, '0')
+
+ private val Double.bitString
+ get() = "0x" + toBits().toULong().toString(16).padStart(length = 16, '0')
+
+ private val Float.Companion.NegativeZero: Float
+ get() = Float.fromBits(0b1 shl 31)
+
+ private val Double.Companion.NegativeZero: Float
+ get() = Float.fromBits(0b1 shl 63)
+}
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/desktopMain/kotlin/androidx/compose/runtime/internal/FloatingPointEquality.desktop.kt b/compose/runtime/runtime/src/desktopMain/kotlin/androidx/compose/runtime/internal/FloatingPointEquality.desktop.kt
new file mode 100644
index 0000000..be9c52f
--- /dev/null
+++ b/compose/runtime/runtime/src/desktopMain/kotlin/androidx/compose/runtime/internal/FloatingPointEquality.desktop.kt
@@ -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.
+ */
+
+package androidx.compose.runtime.internal
+
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun Float.equalsWithNanFix(other: Float): Boolean = (this == other)
+
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun Double.equalsWithNanFix(other: Double): Boolean = (this == other)
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/GroupSizeValidationTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/GroupSizeValidationTests.kt
index edfbac3..6986de3 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/GroupSizeValidationTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/GroupSizeValidationTests.kt
@@ -32,7 +32,7 @@
slotExpect(
name = "SpacerLike",
noMoreGroupsThan = 5,
- noMoreSlotsThan = 9,
+ noMoreSlotsThan = 10,
) {
SpacerLike(Modifier)
}
@@ -43,7 +43,7 @@
slotExpect(
name = "ColumnLike",
noMoreGroupsThan = 6,
- noMoreSlotsThan = 8,
+ noMoreSlotsThan = 9,
) {
ColumnLike { }
}
@@ -65,7 +65,7 @@
slotExpect(
name = "TextLike",
noMoreGroupsThan = 9,
- noMoreSlotsThan = 13
+ noMoreSlotsThan = 14
) {
BasicTextLike("")
}
@@ -76,7 +76,7 @@
slotExpect(
name = "CheckboxLike",
noMoreGroupsThan = 12,
- noMoreSlotsThan = 20
+ noMoreSlotsThan = 21
) {
CheckboxLike(checked = false, onCheckedChange = { })
}
@@ -84,7 +84,7 @@
}
// The following are a sketch of how compose ui uses composition to produce some important
-// composable functions. These are derived from the implementation as of Oct 2022.
+// composable functions. These are derived from the implementation as of May 2023.
// The slot usage should be validated against the actual usage in GroupSizeTests in the
// integration-tests periodically to avoid these skewing too far.
@@ -100,6 +100,7 @@
private object ViewHelper {
val Constructor = ::View
+ val SetCompositeKeyHash: View.(Int) -> Unit = { attributes["compositeKeyHash"] = it }
val SetModifier: View.(Modifier) -> Unit = { attributes["modifier"] = it }
val SetMeasurePolicy: View.(MeasurePolicy) -> Unit = { attributes["measurePolicy"] = it }
val SetDensity: View.(Int) -> Unit = { attributes["density"] = it }
@@ -113,12 +114,14 @@
modifier: Modifier = Modifier,
measurePolicy: MeasurePolicy
) {
+ val compositeKeyHash = currentCompositeKeyHash
val density = LocalDensity.current
val layoutDirection = LocalLayoutDirection.current
val viewConfiguration = LocalViewConfiguration.current
ReusableComposeNode<View, Applier<Any>>(
factory = ViewHelper.Constructor,
update = {
+ set(compositeKeyHash, ViewHelper.SetCompositeKeyHash)
set(modifier, ViewHelper.SetModifier)
set(measurePolicy, ViewHelper.SetMeasurePolicy)
set(density, ViewHelper.SetDensity)
@@ -132,12 +135,14 @@
@Composable
@NonRestartableComposable
private fun LayoutLike(modifier: Modifier, measurePolicy: MeasurePolicy) {
+ val compositeKeyHash = currentCompositeKeyHash
val density = LocalDensity.current
val layoutDirection = LocalLayoutDirection.current
val viewConfiguration = LocalViewConfiguration.current
ReusableComposeNode<View, Applier<Any>>(
factory = ViewHelper.Constructor,
update = {
+ set(compositeKeyHash, ViewHelper.SetCompositeKeyHash)
set(modifier, ViewHelper.SetModifier)
set(measurePolicy, ViewHelper.SetMeasurePolicy)
set(density, ViewHelper.SetDensity)
@@ -647,6 +652,7 @@
return stringOf(this, "")
}
+@Suppress("ConstPropertyName")
private const val MarkerGroup = -340126117
private fun findMarkerGroup(compositionData: CompositionData): CompositionGroup {
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotTests.kt
index 3ec3fb7..dd2cfd1 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotTests.kt
@@ -913,6 +913,52 @@
}
@Test
+ fun cannotApplyASnapshotTwice() {
+ var state by mutableStateOf("initial")
+ val snapshot = takeMutableSnapshot()
+ try {
+ snapshot.enter { state = "mutated" }
+ snapshot.apply().check()
+ snapshot.apply().check()
+ fail("An exception should have been thrown by second apply()")
+ } catch (ise: IllegalStateException) {
+ // Expected exception
+ assertTrue(
+ ise.message?.let {
+ it.contains("Snapshot is not open") &&
+ it.contains("applied=")
+ } == true,
+ "Incorrect message: ${ise.message}"
+ )
+ } finally {
+ snapshot.dispose()
+ }
+ }
+
+ @Test
+ fun cannotApplyAfterADispose() {
+ var state by mutableStateOf("initial")
+ val snapshot = takeMutableSnapshot()
+ try {
+ snapshot.enter { state = "mutated" }
+ snapshot.dispose()
+ snapshot.apply().check()
+ fail("An exception should have been thrown by the apply()")
+ } catch (ise: IllegalStateException) {
+ // Expected exception
+ assertTrue(
+ ise.message?.let {
+ it.contains("Snapshot is not open") &&
+ it.contains("applied=")
+ } == true,
+ "Incorrect message: ${ise.message}"
+ )
+ } finally {
+ snapshot.dispose()
+ }
+ }
+
+ @Test
fun testRecordsAreReusedCorrectly() {
val value = mutableStateOf<Int>(0)
Snapshot.withMutableSnapshot { value.value++ }
@@ -1165,6 +1211,51 @@
assertEquals(1, usedRecords(state3 as StateObject))
}
+ @Test
+ fun testWriteCount() {
+ val state = mutableStateOf<Int>(0)
+ val writtenStates = mutableListOf<Any>()
+ val snapshot = takeMutableSnapshot { write ->
+ writtenStates.add(write)
+ }
+ try {
+ snapshot.enter {
+ assertEquals(0, writtenStates.size)
+ assertEquals(0, snapshot.writeCount)
+ state.value = 2
+ assertEquals(1, writtenStates.size)
+ assertEquals(1, snapshot.writeCount)
+ }
+ } finally {
+ snapshot.dispose()
+ }
+ assertEquals(1, writtenStates.size)
+ assertEquals(state, writtenStates[0])
+ assertEquals(0, current.writeCount)
+ }
+
+ @Test
+ fun testTransparentSnapshotWriteCount() {
+ val state = mutableStateOf<Int>(0)
+ val transparentSnapshot = TransparentObserverMutableSnapshot(
+ parentSnapshot = currentSnapshot() as? MutableSnapshot,
+ specifiedReadObserver = null,
+ specifiedWriteObserver = null,
+ mergeParentObservers = false,
+ ownsParentSnapshot = false
+ )
+ try {
+ transparentSnapshot.enter {
+ assertEquals(0, transparentSnapshot.writeCount)
+ state.value = 2
+ assertEquals(1, transparentSnapshot.writeCount)
+ }
+ } finally {
+ transparentSnapshot.dispose()
+ }
+ assertEquals(1, current.writeCount)
+ }
+
private fun usedRecords(state: StateObject): Int {
var used = 0
var current: StateRecord? = state.firstStateRecord
diff --git a/compose/test-utils/build.gradle b/compose/test-utils/build.gradle
index 46eecc3..582e745 100644
--- a/compose/test-utils/build.gradle
+++ b/compose/test-utils/build.gradle
@@ -40,7 +40,9 @@
}
}
androidMain.dependencies {
- api("androidx.activity:activity:1.2.0")
+ api("androidx.activity:activity:1.7.1")
+ // workaround for https://github.com/gradle/gradle/issues/8489
+ implementation("androidx.lifecycle:lifecycle-common:2.6.1")
implementation "androidx.activity:activity-compose:1.3.1"
api(projectOrArtifact(":compose:ui:ui-test-junit4"))
api(project(":test:screenshot:screenshot"))
diff --git a/compose/test-utils/lint-baseline.xml b/compose/test-utils/lint-baseline.xml
new file mode 100644
index 0000000..a8d3ffc
--- /dev/null
+++ b/compose/test-utils/lint-baseline.xml
@@ -0,0 +1,40 @@
+<?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">
+
+ <issue
+ id="PlatformImportInCommonModule"
+ message="Platform-dependent import in a common module"
+ errorLine1="import android.view.View"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/commonMain/kotlin/androidx/compose/testutils/ComposeExecutionControl.kt"/>
+ </issue>
+
+ <issue
+ id="PlatformImportInCommonModule"
+ message="Platform-dependent import in a common module"
+ errorLine1="import java.io.PrintWriter"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/commonMain/kotlin/androidx/compose/testutils/Expect.kt"/>
+ </issue>
+
+ <issue
+ id="PlatformImportInCommonModule"
+ message="Platform-dependent import in a common module"
+ errorLine1="import java.io.StringWriter"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/commonMain/kotlin/androidx/compose/testutils/Expect.kt"/>
+ </issue>
+
+ <issue
+ id="PlatformImportInCommonModule"
+ message="Platform-dependent import in a common module"
+ errorLine1="import android.annotation.SuppressLint"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/commonMain/kotlin/androidx/compose/testutils/ModifierTestUtils.kt"/>
+ </issue>
+
+</issues>
diff --git a/compose/ui/ui-geometry/api/current.txt b/compose/ui/ui-geometry/api/current.txt
index 5aabfcd..9e2e0ce 100644
--- a/compose/ui/ui-geometry/api/current.txt
+++ b/compose/ui/ui-geometry/api/current.txt
@@ -125,6 +125,7 @@
method public float getWidth();
method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect inflate(float delta);
method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect intersect(androidx.compose.ui.geometry.Rect other);
+ method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect intersect(float otherLeft, float otherTop, float otherRight, float otherBottom);
method public boolean isEmpty();
method public boolean isFinite();
method public boolean isInfinite();
diff --git a/compose/ui/ui-geometry/api/restricted_current.txt b/compose/ui/ui-geometry/api/restricted_current.txt
index 5aabfcd..9e2e0ce 100644
--- a/compose/ui/ui-geometry/api/restricted_current.txt
+++ b/compose/ui/ui-geometry/api/restricted_current.txt
@@ -125,6 +125,7 @@
method public float getWidth();
method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect inflate(float delta);
method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect intersect(androidx.compose.ui.geometry.Rect other);
+ method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect intersect(float otherLeft, float otherTop, float otherRight, float otherBottom);
method public boolean isEmpty();
method public boolean isFinite();
method public boolean isInfinite();
diff --git a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt
index 5230b42..b7f3ebb 100644
--- a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt
+++ b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt
@@ -156,6 +156,22 @@
)
}
+ /**
+ * Returns a new rectangle that is the intersection of the given
+ * rectangle and this rectangle. The two rectangles must overlap
+ * for this to be meaningful. If the two rectangles do not overlap,
+ * then the resulting Rect will have a negative width or height.
+ */
+ @Stable
+ fun intersect(otherLeft: Float, otherTop: Float, otherRight: Float, otherBottom: Float): Rect {
+ return Rect(
+ max(left, otherLeft),
+ max(top, otherTop),
+ min(right, otherRight),
+ min(bottom, otherBottom)
+ )
+ }
+
/** Whether `other` has a nonzero area of overlap with this rectangle. */
fun overlaps(other: Rect): Boolean {
if (right <= other.left || other.right <= left)
diff --git a/compose/ui/ui-graphics/api/current.ignore b/compose/ui/ui-graphics/api/current.ignore
new file mode 100644
index 0000000..dad316b
--- /dev/null
+++ b/compose/ui/ui-graphics/api/current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+RemovedMethod: androidx.compose.ui.graphics.AndroidPaint_androidKt#toComposePaint(android.graphics.Paint):
+ Removed method androidx.compose.ui.graphics.AndroidPaint_androidKt.toComposePaint(android.graphics.Paint)
diff --git a/compose/ui/ui-graphics/api/current.txt b/compose/ui/ui-graphics/api/current.txt
index eb84156..5aee8b7 100644
--- a/compose/ui/ui-graphics/api/current.txt
+++ b/compose/ui/ui-graphics/api/current.txt
@@ -77,7 +77,7 @@
public final class AndroidPaint_androidKt {
method public static androidx.compose.ui.graphics.Paint Paint();
- method public static androidx.compose.ui.graphics.Paint toComposePaint(android.graphics.Paint);
+ method public static androidx.compose.ui.graphics.Paint asComposePaint(android.graphics.Paint);
}
public final class AndroidPath implements androidx.compose.ui.graphics.Path {
@@ -1151,11 +1151,18 @@
}
public interface DrawContext {
- method public androidx.compose.ui.graphics.Canvas getCanvas();
+ method public default androidx.compose.ui.graphics.Canvas getCanvas();
+ method public default androidx.compose.ui.unit.Density getDensity();
+ method public default androidx.compose.ui.unit.LayoutDirection getLayoutDirection();
method public long getSize();
method public androidx.compose.ui.graphics.drawscope.DrawTransform getTransform();
+ method public default void setCanvas(androidx.compose.ui.graphics.Canvas);
+ method public default void setDensity(androidx.compose.ui.unit.Density);
+ method public default void setLayoutDirection(androidx.compose.ui.unit.LayoutDirection);
method public void setSize(long);
- property public abstract androidx.compose.ui.graphics.Canvas canvas;
+ property public default androidx.compose.ui.graphics.Canvas canvas;
+ property public default androidx.compose.ui.unit.Density density;
+ property public default androidx.compose.ui.unit.LayoutDirection layoutDirection;
property public abstract long size;
property public abstract androidx.compose.ui.graphics.drawscope.DrawTransform transform;
}
@@ -1201,6 +1208,7 @@
public final class DrawScopeKt {
method public static inline void clipPath(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.graphics.Path path, optional int clipOp, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void clipRect(androidx.compose.ui.graphics.drawscope.DrawScope, optional float left, optional float top, optional float right, optional float bottom, optional int clipOp, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+ method public static inline void draw(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.unit.Density density, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.graphics.Canvas canvas, long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void drawIntoCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.Canvas,kotlin.Unit> block);
method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, optional float horizontal, optional float vertical, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
diff --git a/compose/ui/ui-graphics/api/restricted_current.ignore b/compose/ui/ui-graphics/api/restricted_current.ignore
new file mode 100644
index 0000000..dad316b
--- /dev/null
+++ b/compose/ui/ui-graphics/api/restricted_current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+RemovedMethod: androidx.compose.ui.graphics.AndroidPaint_androidKt#toComposePaint(android.graphics.Paint):
+ Removed method androidx.compose.ui.graphics.AndroidPaint_androidKt.toComposePaint(android.graphics.Paint)
diff --git a/compose/ui/ui-graphics/api/restricted_current.txt b/compose/ui/ui-graphics/api/restricted_current.txt
index 4aa03ab..a3c6a24 100644
--- a/compose/ui/ui-graphics/api/restricted_current.txt
+++ b/compose/ui/ui-graphics/api/restricted_current.txt
@@ -107,7 +107,7 @@
public final class AndroidPaint_androidKt {
method public static androidx.compose.ui.graphics.Paint Paint();
- method public static androidx.compose.ui.graphics.Paint toComposePaint(android.graphics.Paint);
+ method public static androidx.compose.ui.graphics.Paint asComposePaint(android.graphics.Paint);
}
public final class AndroidPath implements androidx.compose.ui.graphics.Path {
@@ -1210,11 +1210,18 @@
}
public interface DrawContext {
- method public androidx.compose.ui.graphics.Canvas getCanvas();
+ method public default androidx.compose.ui.graphics.Canvas getCanvas();
+ method public default androidx.compose.ui.unit.Density getDensity();
+ method public default androidx.compose.ui.unit.LayoutDirection getLayoutDirection();
method public long getSize();
method public androidx.compose.ui.graphics.drawscope.DrawTransform getTransform();
+ method public default void setCanvas(androidx.compose.ui.graphics.Canvas);
+ method public default void setDensity(androidx.compose.ui.unit.Density);
+ method public default void setLayoutDirection(androidx.compose.ui.unit.LayoutDirection);
method public void setSize(long);
- property public abstract androidx.compose.ui.graphics.Canvas canvas;
+ property public default androidx.compose.ui.graphics.Canvas canvas;
+ property public default androidx.compose.ui.unit.Density density;
+ property public default androidx.compose.ui.unit.LayoutDirection layoutDirection;
property public abstract long size;
property public abstract androidx.compose.ui.graphics.drawscope.DrawTransform transform;
}
@@ -1260,6 +1267,7 @@
public final class DrawScopeKt {
method public static inline void clipPath(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.graphics.Path path, optional int clipOp, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void clipRect(androidx.compose.ui.graphics.drawscope.DrawScope, optional float left, optional float top, optional float right, optional float bottom, optional int clipOp, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+ method public static inline void draw(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.unit.Density density, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.graphics.Canvas canvas, long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void drawIntoCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.Canvas,kotlin.Unit> block);
method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, optional float horizontal, optional float vertical, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
diff --git a/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/DrawScopeSample.kt b/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/DrawScopeSample.kt
index 302414d..9e4f005 100644
--- a/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/DrawScopeSample.kt
+++ b/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/DrawScopeSample.kt
@@ -18,16 +18,21 @@
import androidx.annotation.Sampled
import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawscope.draw
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.drawscope.inset
import androidx.compose.ui.graphics.drawscope.rotate
import androidx.compose.ui.graphics.drawscope.withTransform
+import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.unit.dp
/**
@@ -104,4 +109,31 @@
size = Size(size.width - 20f, size.height - 20f)
)
}
+}
+
+@Sampled
+@Composable
+fun DrawScopeRetargetingSample() {
+ Box(modifier = Modifier.size(120.dp)
+ .drawWithCache {
+ // Example that shows how to redirect rendering to an Android Picture and then
+ // draw the picture into the original destination
+ // Note:
+ // Canvas#drawPicture is supported with hardware acceleration on Android API 23+
+ // Check https://developer.android.com/topic/performance/hardware-accel#drawing-support
+ // for details of which drawing operations are supported with hardware acceleration
+ val picture = android.graphics.Picture()
+ val width = this.size.width.toInt()
+ val height = this.size.height.toInt()
+ onDrawWithContent {
+ val pictureCanvas =
+ androidx.compose.ui.graphics.Canvas(picture.beginRecording(width, height))
+ draw(this, this.layoutDirection, pictureCanvas, this.size) {
+ this@onDrawWithContent.drawContent()
+ }
+ picture.endRecording()
+
+ drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) }
+ }
+ })
}
\ No newline at end of file
diff --git a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/PaintTest.kt b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/PaintTest.kt
index 2c61d09..0ed17ef 100644
--- a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/PaintTest.kt
+++ b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/PaintTest.kt
@@ -66,7 +66,7 @@
@Test
fun testToComposePaintForColor() {
val nativePaint = android.graphics.Paint()
- val composePaint = nativePaint.toComposePaint()
+ val composePaint = nativePaint.asComposePaint()
composePaint.color = Color(android.graphics.Color.GREEN)
assertEquals(nativePaint.color, android.graphics.Color.GREEN)
}
@@ -74,7 +74,7 @@
@Test
fun testToComposePaintForShader() {
val nativePaint = android.graphics.Paint()
- val composePaint = nativePaint.toComposePaint()
+ val composePaint = nativePaint.asComposePaint()
val green = android.graphics.Color.GREEN
val red = android.graphics.Color.RED
val shader = android.graphics.LinearGradient(
diff --git a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
index 213e383..55a81a0 100644
--- a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
+++ b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
@@ -37,6 +37,7 @@
import androidx.compose.ui.graphics.SweepGradientShader
import androidx.compose.ui.graphics.TileMode
import androidx.compose.ui.graphics.compositeOver
+import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.graphics.toPixelMap
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntSize
@@ -1691,6 +1692,84 @@
)
}
+ @Test
+ fun testDrawScopeRetargeting() {
+ val width = 30
+ val height = 20
+
+ val pictureWidth = 20
+ val pictureHeight = 10
+
+ val bitmap = ImageBitmap(width, height)
+ val bitmapCanvas = Canvas(bitmap)
+ val density = Density(2.0f, 3.0f)
+ val drawScope: DrawScope = CanvasDrawScope()
+ drawScope.draw(
+ density,
+ LayoutDirection.Ltr,
+ bitmapCanvas,
+ Size(width.toFloat(), height.toFloat())
+ ) {
+ assertEquals(density.density, this.density)
+ assertEquals(density.fontScale, this.fontScale)
+ assertEquals(LayoutDirection.Ltr, this.layoutDirection)
+ assertEquals(width.toFloat(), this.size.width)
+ assertEquals(height.toFloat(), this.size.height)
+ drawIntoCanvas { canvas -> assertTrue(bitmapCanvas === canvas) }
+
+ drawRect(color = Color.Red)
+
+ val picture = android.graphics.Picture()
+ val pictureCanvas = Canvas(picture.beginRecording(pictureWidth, pictureHeight))
+ val pictureDensity = Density(5.0f, 10f)
+ draw(
+ pictureDensity,
+ LayoutDirection.Rtl,
+ pictureCanvas,
+ Size(pictureWidth.toFloat(), pictureHeight.toFloat())
+ ) {
+ // Verify that while retargeting the draw scope, the parameters match that of the
+ // new configuration
+ assertEquals(pictureDensity.density, this.density)
+ assertEquals(pictureDensity.fontScale, this.fontScale)
+ assertEquals(LayoutDirection.Rtl, this.layoutDirection)
+ assertEquals(pictureWidth.toFloat(), this.size.width)
+ assertEquals(pictureHeight.toFloat(), this.size.height)
+ drawIntoCanvas { canvas -> assertTrue(pictureCanvas === canvas) }
+
+ drawRect(color = Color.Blue)
+ }
+ picture.endRecording()
+ drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) }
+
+ // Verify that the draw scope configuration is reset outside of the retargeting of the
+ // canvas
+ assertEquals(density.density, this.density)
+ assertEquals(density.fontScale, this.fontScale)
+ assertEquals(LayoutDirection.Ltr, this.layoutDirection)
+ assertEquals(width.toFloat(), this.size.width)
+ assertEquals(height.toFloat(), this.size.height)
+ drawIntoCanvas { canvas -> assertTrue(bitmapCanvas === canvas) }
+ }
+
+ with(bitmap.toPixelMap()) {
+ assertEquals(Color.Blue, this[0, 0])
+ assertEquals(Color.Blue, this[pictureWidth - 1, 0])
+ assertEquals(Color.Blue, this[0, pictureHeight - 1])
+ assertEquals(Color.Blue, this[pictureWidth - 1, pictureHeight - 1])
+ assertEquals(Color.Blue, this[pictureWidth / 2, pictureHeight / 2])
+
+ assertEquals(Color.Red, this[pictureWidth + 1, 0])
+ assertEquals(Color.Red, this[width - 1, 0])
+ assertEquals(Color.Red, this[pictureWidth + 1, pictureHeight])
+ assertEquals(Color.Red, this[pictureWidth + 1, pictureHeight + 1])
+ assertEquals(Color.Red, this[pictureWidth, pictureHeight + 1])
+ assertEquals(Color.Red, this[0, height - 1])
+ assertEquals(Color.Red, this[0, pictureHeight + 1])
+ assertEquals(Color.Red, this[width - 1, height - 1])
+ }
+ }
+
private inline fun testDrawTransformDefault(block: WrappedDrawTransform.() -> Unit) {
val width = 100
val height = 150
@@ -1783,8 +1862,19 @@
set(value) {
drawScope.drawContext.size = value
}
- override val canvas: Canvas
+ override var canvas: Canvas
get() = drawScope.drawContext.canvas
+ set(value) {
+ drawScope.drawContext.canvas = value
+ }
+
+ override var layoutDirection: LayoutDirection
+ get() = drawScope.drawContext.layoutDirection
+ set(value) { drawScope.drawContext.layoutDirection = value }
+ override var density: Density
+ get() = drawScope.drawContext.density
+ set(value) { drawScope.drawContext.density = value }
+
override val transform: DrawTransform =
WrappedDrawTransform(drawScope.drawContext.transform)
}
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPaint.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPaint.android.kt
index aee6ddb..2f76400 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPaint.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPaint.android.kt
@@ -27,10 +27,19 @@
/**
* Convert an [android.graphics.Paint] instance into a Compose-compatible Paint
*/
-fun android.graphics.Paint.toComposePaint(): Paint = AndroidPaint(this)
+fun android.graphics.Paint.asComposePaint(): Paint = AndroidPaint(this)
+/**
+ * Create a Compose [Paint] instance backed by an [android.graphics.Paint] object to be
+ * consumed by Compose applications running on the Android platform
+ *
+ * @param internalPaint [android.graphics.Paint] to be wrapped by the [AndroidPaint] instance
+ */
class AndroidPaint(private var internalPaint: android.graphics.Paint) : Paint {
+ /**
+ * Create a new [AndroidPaint] instance backed by a newly created [android.graphics.Paint]
+ */
constructor() : this(makeNativePaint())
private var _blendMode = BlendMode.SrcOver
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Lab.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Lab.kt
index 1298e6d..415e66c 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Lab.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Lab.kt
@@ -64,7 +64,7 @@
override fun toXy(v0: Float, v1: Float, v2: Float): Long {
val v00 = v0.coerceIn(0.0f, 100.0f)
- val v10 = v0.coerceIn(-128.0f, 128.0f)
+ val v10 = v1.coerceIn(-128.0f, 128.0f)
val fy = (v00 + 16.0f) / 116.0f
val fx = fy + (v10 * 0.002f)
@@ -137,4 +137,4 @@
private const val C = 4.0f / 29.0f
private const val D = 6.0f / 29.0f
}
-}
\ No newline at end of file
+}
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/CanvasDrawScope.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/CanvasDrawScope.kt
index b104b53..5367870 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/CanvasDrawScope.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/CanvasDrawScope.kt
@@ -41,15 +41,6 @@
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.unit.center
-
-/**
- * Default density value that is used as a stub to provide a non-null
- * density parameter within CanvasDrawScope.
- * Density is provided as a parameter as part of the draw call to
- * issue drawing commands into a target canvas so this Density value is never consumed
- */
-private val DefaultDensity = Density(1.0f, 1.0f)
/**
* Implementation of [DrawScope] that issues drawing commands
@@ -69,8 +60,9 @@
get() = drawParams.density.fontScale
override val drawContext = object : DrawContext {
- override val canvas: Canvas
+ override var canvas: Canvas
get() = drawParams.canvas
+ set(value) { drawParams.canvas = value }
override var size: Size
get() = drawParams.size
@@ -79,6 +71,13 @@
}
override val transform: DrawTransform = asDrawTransform()
+
+ override var layoutDirection: LayoutDirection
+ get() = drawParams.layoutDirection
+ set(value) { drawParams.layoutDirection = value }
+ override var density: Density
+ get() = drawParams.density
+ set(value) { drawParams.density = value }
}
/**
@@ -539,6 +538,9 @@
* Draws into the provided [Canvas] with the commands specified in the lambda with this
* [DrawScope] as a receiver
*
+ * @param density [Density] used to assist in conversions of density independent pixels to raw
+ * pixels to draw
+ * @param layoutDirection [LayoutDirection] of the layout being drawn in.
* @param canvas target canvas to render into
* @param size bounds relative to the current canvas translation in which the [DrawScope]
* should draw within
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawContext.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawContext.kt
index 306e3f2..baea999 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawContext.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawContext.kt
@@ -18,6 +18,16 @@
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Canvas
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+
+/**
+ * Default density value that is used as a stub to provide a non-null
+ * density parameter within CanvasDrawScope.
+ * Density is provided as a parameter as part of the draw call to
+ * issue drawing commands into a target canvas so this Density value is never consumed
+ */
+internal val DefaultDensity = Density(1.0f, 1.0f)
/**
* Object that provides the dependencies to support a [DrawScope] drawing environment.
@@ -40,10 +50,26 @@
/**
* The target canvas to issue drawing commands
*/
- val canvas: Canvas
+ var canvas: Canvas
+ get() = EmptyCanvas()
+ set(_) {}
/**
* The controller for issuing transformations to the drawing environment
*/
val transform: DrawTransform
+
+ /**
+ * [LayoutDirection] of the layout being drawn in.
+ */
+ var layoutDirection: LayoutDirection
+ get() = LayoutDirection.Ltr
+ set(_) {}
+
+ /**
+ * [Density] used to assist in conversions of density independent pixels to raw pixels to draw
+ */
+ var density: Density
+ get() = DefaultDensity
+ set(_) {}
}
\ No newline at end of file
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
index 15f30fe..5649083 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
@@ -271,6 +271,52 @@
}
/**
+ * Draws into the provided [Canvas] with the commands specified in the lambda with this
+ * [DrawScope] as a receiver
+ *
+ * @sample androidx.compose.ui.graphics.samples.DrawScopeRetargetingSample
+ *
+ * @param density [Density] used to assist in conversions of density independent pixels to raw
+ * pixels to draw
+ * @param layoutDirection [LayoutDirection] of the layout being drawn in.
+ * @param canvas target canvas to render into
+ * @param size bounds relative to the current canvas translation in which the [DrawScope]
+ * should draw within
+ * @param block lambda that is called to issue drawing commands on this [DrawScope]
+ */
+inline fun DrawScope.draw(
+ density: Density,
+ layoutDirection: LayoutDirection,
+ canvas: Canvas,
+ size: Size,
+ block: DrawScope.() -> Unit
+) {
+ // Remember the previous drawing parameters in case we are temporarily re-directing our
+ // drawing to a separate Layer/RenderNode only to draw that content back into the original
+ // Canvas. If there is no previous canvas that was being drawing into, this ends up
+ // resetting these parameters back to defaults defensively
+ val prevDensity = drawContext.density
+ val prevLayoutDirection = drawContext.layoutDirection
+ val prevCanvas = drawContext.canvas
+ val prevSize = drawContext.size
+ drawContext.apply {
+ this.density = density
+ this.layoutDirection = layoutDirection
+ this.canvas = canvas
+ this.size = size
+ }
+ canvas.save()
+ this.block()
+ canvas.restore()
+ drawContext.apply {
+ this.density = prevDensity
+ this.layoutDirection = prevLayoutDirection
+ this.canvas = prevCanvas
+ this.size = prevSize
+ }
+}
+
+/**
* Creates a scoped drawing environment with the provided [Canvas]. This provides a
* declarative, stateless API to draw shapes and paths without requiring
* consumers to maintain underlying [Canvas] state information.
diff --git a/compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/ColorTest.kt b/compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/ColorTest.kt
index cb7c60c..4adb50b 100644
--- a/compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/ColorTest.kt
+++ b/compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/ColorTest.kt
@@ -558,6 +558,16 @@
}
}
+ @Test
+ fun convertCieLab() {
+ val green = Color(100, 180, 50)
+ val cieGreen = green.convert(ColorSpaces.CieLab)
+ val srgbGreen = cieGreen.convert(ColorSpaces.Srgb)
+ assertEquals(100f / 255f, srgbGreen.red, 0.01f)
+ assertEquals(180f / 255f, srgbGreen.green, 0.01f)
+ assertEquals(50f / 255f, srgbGreen.blue, 0.01f)
+ }
+
companion object {
fun Int.toHexString() = "0x${toUInt().toString(16).padStart(8, '0')}"
}
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
index d68d55d..dcccbb0 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
@@ -177,6 +177,7 @@
text = "helloworld",
color = Color.Green,
fontSize = 10.sp,
+ lineHeight = 10.sp,
fontFamily = fontFamily
)
// width: 24.dp, height: 24.dp
@@ -185,7 +186,12 @@
// minwidth: 64.dp, height: 42.dp
Button(onClick = {}) {
// width: 20.dp, height: 10.dp
- Text(text = "ok", fontSize = 10.sp, fontFamily = fontFamily)
+ Text(
+ text = "ok",
+ fontSize = 10.sp,
+ lineHeight = 10.sp,
+ fontFamily = fontFamily
+ )
}
}
}
diff --git a/compose/ui/ui-test-junit4/src/test/kotlin/androidx/compose/ui/test/junit4/RobolectricComposeTest.kt b/compose/ui/ui-test-junit4/src/test/kotlin/androidx/compose/ui/test/junit4/RobolectricComposeTest.kt
index db3efc8..15df0b3 100644
--- a/compose/ui/ui-test-junit4/src/test/kotlin/androidx/compose/ui/test/junit4/RobolectricComposeTest.kt
+++ b/compose/ui/ui-test-junit4/src/test/kotlin/androidx/compose/ui/test/junit4/RobolectricComposeTest.kt
@@ -18,12 +18,15 @@
import android.os.Handler
import android.os.Looper
+import android.view.MotionEvent
+import android.view.View
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.LocalOverscrollConfiguration
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.ScrollScope
+import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@@ -50,7 +53,13 @@
import androidx.compose.testutils.WithTouchSlop
import androidx.compose.testutils.expectError
import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.findRootCoordinates
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.assertIsDisplayed
@@ -66,14 +75,17 @@
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
+import androidx.test.core.view.MotionEventBuilder
import androidx.test.espresso.AppNotIdleException
import androidx.test.espresso.IdlingPolicies
import androidx.test.espresso.IdlingPolicy
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
import org.junit.After
+import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -360,4 +372,368 @@
onNodeWithTag("MenuContent").assertIsDisplayed()
}
+
+ /*
+ * Two tests properly demonstrating how to properly advance the clock (advanceTimeBy()) while
+ * testing pointer input events using performTouchInput() with espresso and/or Robolectric).
+ */
+ @Test
+ fun areTwoTapsFired_dispatchTwoDelayedTapsWithPerformTouchInput_assertTrue() =
+ runComposeUiTest {
+ var composableTouchCount = 0
+ var composableTapCount = 0
+ var composableDoubleTapCount = 0
+ var composableLongTapCount = 0
+
+ val setupLatch = CountDownLatch(1)
+ val tapLatch = CountDownLatch(2)
+
+ setContent {
+ Box(
+ modifier = Modifier
+ .testTag("mainBox")
+ .fillMaxSize()
+ .pointerInput(Unit) {
+ detectTapGestures(
+ onPress = {
+ ++composableTouchCount
+ },
+ onTap = {
+ tapLatch.countDown()
+ ++composableTapCount
+ },
+ onDoubleTap = {
+ ++composableDoubleTapCount
+ },
+ onLongPress = {
+ ++composableLongTapCount
+ }
+ )
+ }
+ .onGloballyPositioned {
+ setupLatch.countDown()
+ }
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ )
+ }
+ }
+ assertTrue(setupLatch.await(10, TimeUnit.SECONDS))
+
+ onNodeWithTag("mainBox").assertIsDisplayed()
+
+ runOnIdle {
+ onNodeWithTag("mainBox").performTouchInput {
+ down(center)
+ up()
+ }
+ }
+
+ // In testing (Espresso, Robolectric, etc.), it's important to move the clock forward
+ // when using detectTapGestures {} as parts of it rely on changes in the clock
+ // (double tap, etc.).
+ mainClock.advanceTimeBy(400)
+
+ runOnIdle {
+ onNodeWithTag("mainBox").performTouchInput {
+ down(center)
+ up()
+ }
+ }
+
+ // Delay again to trigger second single tap (times out double tap detector)
+ mainClock.advanceTimeBy(400)
+
+ assertTrue(tapLatch.await(10, TimeUnit.SECONDS))
+
+ assertThat(composableTouchCount).isEqualTo(2)
+ assertThat(composableTapCount).isEqualTo(2)
+ assertThat(composableDoubleTapCount).isEqualTo(0)
+ assertThat(composableLongTapCount).isEqualTo(0)
+ }
+
+ @Test
+ fun isDoubleTapFired_dispatchTwoTapsWithPerformTouchInput_assertTrue() = runComposeUiTest {
+ var composableTouchCount = 0
+ var composableTapCount = 0
+ var composableDoubleTapCount = 0
+ var composableLongTapCount = 0
+
+ val setupLatch = CountDownLatch(1)
+ val doubleTapLatch = CountDownLatch(1)
+
+ setContent {
+ Box(
+ modifier = Modifier
+ .testTag("mainBox")
+ .fillMaxSize()
+ .pointerInput(Unit) {
+ detectTapGestures(
+ onPress = {
+ ++composableTouchCount
+ },
+ onTap = {
+ ++composableTapCount
+ },
+ onDoubleTap = {
+ doubleTapLatch.countDown()
+ ++composableDoubleTapCount
+ },
+ onLongPress = {
+ ++composableLongTapCount
+ }
+ )
+ }
+ .onGloballyPositioned {
+ setupLatch.countDown()
+ }
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ )
+ }
+ }
+ assertTrue(setupLatch.await(10, TimeUnit.SECONDS))
+
+ onNodeWithTag("mainBox").assertIsDisplayed()
+
+ runOnIdle {
+ onNodeWithTag("mainBox").performTouchInput {
+ down(center)
+ up()
+ }
+ }
+
+ // In testing (Espresso, Robolectric, etc.), it's important to move the clock forward when
+ // using detectTapGestures {} as parts of it rely on changes in the clock (double tap, etc.)
+ mainClock.advanceTimeBy(100)
+
+ runOnIdle {
+ onNodeWithTag("mainBox").performTouchInput { down(center) }
+ onNodeWithTag("mainBox").performTouchInput { up() }
+ }
+
+ // Delay but just enough to stay inside double tap timeframe
+ mainClock.advanceTimeBy(100)
+
+ assertTrue(doubleTapLatch.await(10, TimeUnit.SECONDS))
+
+ assertThat(composableTouchCount).isEqualTo(2)
+ assertThat(composableTapCount).isEqualTo(0)
+ assertThat(composableDoubleTapCount).isEqualTo(1)
+ assertThat(composableLongTapCount).isEqualTo(0)
+ }
+
+ /*
+ * Two tests properly demonstrating how to properly advance the clock (advanceTimeBy()) while
+ * testing pointer input events using manually created MotionEvents with espresso and/or
+ * Robolectric).
+ */
+ @Test
+ fun isTapFired_dispatchTapWithMotionEvents_assertTrue() = runComposeUiTest {
+ var composableTouchCount = 0
+ var composableTapCount = 0
+ var composableDoubleTapCount = 0
+ var composableLongTapCount = 0
+
+ val setupLatch = CountDownLatch(1)
+ val tapLatch = CountDownLatch(1)
+
+ var bottomBoxInnerCoordinates: LayoutCoordinates? = null
+ var topLevelContainerView: View? = null
+
+ setContent {
+ topLevelContainerView = LocalView.current
+
+ Box(
+ modifier = Modifier
+ .testTag("mainBox")
+ .fillMaxSize()
+ .pointerInput(Unit) {
+ detectTapGestures(
+ onPress = {
+ ++composableTouchCount
+ },
+ onTap = {
+ tapLatch.countDown()
+ ++composableTapCount
+ },
+ onDoubleTap = {
+ ++composableDoubleTapCount
+ },
+ onLongPress = {
+ ++composableLongTapCount
+ }
+ )
+ }
+ .onGloballyPositioned {
+ setupLatch.countDown()
+ bottomBoxInnerCoordinates = it
+ }
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ )
+ }
+ }
+ assertTrue(setupLatch.await(10, TimeUnit.SECONDS))
+
+ onNodeWithTag("mainBox").assertIsDisplayed()
+
+ val root = bottomBoxInnerCoordinates!!.findRootCoordinates()
+ val topBoxOffset = root.localPositionOf(bottomBoxInnerCoordinates!!, Offset.Zero)
+ val topBoxFingerPointerPropertiesId = 0
+ val topBoxPointerProperties =
+ MotionEvent.PointerProperties().also {
+ it.id = topBoxFingerPointerPropertiesId
+ it.toolType = MotionEvent.TOOL_TYPE_FINGER
+ }
+ val coords = MotionEvent.PointerCoords()
+ coords.x = topBoxOffset.x
+ coords.y = topBoxOffset.y
+
+ val motionEventDown = MotionEventBuilder.newBuilder()
+ .setEventTime(0)
+ .setAction(MotionEvent.ACTION_DOWN)
+ .setActionIndex(0)
+ .setPointer(topBoxPointerProperties, coords)
+ .build()
+
+ val motionEventUp = MotionEventBuilder.newBuilder()
+ .setEventTime(100)
+ .setAction(MotionEvent.ACTION_UP)
+ .setActionIndex(0)
+ .setPointer(topBoxPointerProperties, coords)
+ .build()
+
+ topLevelContainerView?.dispatchTouchEvent(motionEventDown)
+ topLevelContainerView?.dispatchTouchEvent(motionEventUp)
+
+ // In testing (Espresso, Robolectric, etc.), it's important to move the clock forward when
+ // using detectTapGestures {} as parts of it rely on changes in the clock (double tap, etc.)
+ // Delay to trigger second single tap (times out double tap detector)
+ mainClock.advanceTimeBy(400)
+
+ assertTrue(tapLatch.await(10, TimeUnit.SECONDS))
+
+ assertThat(composableTouchCount).isEqualTo(1)
+ assertThat(composableTapCount).isEqualTo(1)
+ assertThat(composableDoubleTapCount).isEqualTo(0)
+ assertThat(composableLongTapCount).isEqualTo(0)
+ }
+
+ @Test
+ fun isDoubleTapFired_dispatchTwoTapsWithMotionEvents_assertTrue() = runComposeUiTest {
+ var composableTouchCount = 0
+ var composableTapCount = 0
+ var composableDoubleTapCount = 0
+ var composableLongTapCount = 0
+
+ val setupLatch = CountDownLatch(1)
+ val doubleTapLatch = CountDownLatch(1)
+
+ var bottomBoxInnerCoordinates: LayoutCoordinates? = null
+ var topLevelContainerView: View? = null
+
+ setContent {
+ topLevelContainerView = LocalView.current
+
+ Box(
+ modifier = Modifier
+ .testTag("mainBox")
+ .fillMaxSize()
+ .pointerInput(Unit) {
+ detectTapGestures(
+ onPress = {
+ ++composableTouchCount
+ },
+ onTap = {
+ ++composableTapCount
+ },
+ onDoubleTap = {
+ doubleTapLatch.countDown()
+ ++composableDoubleTapCount
+ },
+ onLongPress = {
+ ++composableLongTapCount
+ }
+ )
+ }
+ .onGloballyPositioned {
+ setupLatch.countDown()
+ bottomBoxInnerCoordinates = it
+ }
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ )
+ }
+ }
+ assertTrue(setupLatch.await(10, TimeUnit.SECONDS))
+
+ val root = bottomBoxInnerCoordinates!!.findRootCoordinates()
+ val topBoxOffset = root.localPositionOf(bottomBoxInnerCoordinates!!, Offset.Zero)
+ val topBoxFingerPointerPropertiesId = 0
+ val topBoxPointerProperties =
+ MotionEvent.PointerProperties().also {
+ it.id = topBoxFingerPointerPropertiesId
+ it.toolType = MotionEvent.TOOL_TYPE_FINGER
+ }
+ val coords = MotionEvent.PointerCoords()
+ coords.x = topBoxOffset.x
+ coords.y = topBoxOffset.y
+
+ val motionEventDown1 = MotionEventBuilder.newBuilder()
+ .setEventTime(0)
+ .setAction(MotionEvent.ACTION_DOWN)
+ .setActionIndex(0)
+ .setPointer(topBoxPointerProperties, coords)
+ .build()
+
+ val motionEventUp1 = MotionEventBuilder.newBuilder()
+ .setEventTime(50)
+ .setAction(MotionEvent.ACTION_UP)
+ .setActionIndex(0)
+ .setPointer(topBoxPointerProperties, coords)
+ .build()
+
+ topLevelContainerView?.dispatchTouchEvent(motionEventDown1)
+ topLevelContainerView?.dispatchTouchEvent(motionEventUp1)
+
+ // In testing (Espresso, Robolectric, etc.), it's important to move the clock forward when
+ // using detectTapGestures {} as parts of it rely on changes in the clock (double tap, etc.)
+ mainClock.advanceTimeBy(100)
+
+ val motionEventDown2 = MotionEventBuilder.newBuilder()
+ .setEventTime(100)
+ .setAction(MotionEvent.ACTION_DOWN)
+ .setActionIndex(0)
+ .setPointer(topBoxPointerProperties, coords)
+ .build()
+
+ val motionEventUp2 = MotionEventBuilder.newBuilder()
+ .setEventTime(150)
+ .setAction(MotionEvent.ACTION_UP)
+ .setActionIndex(0)
+ .setPointer(topBoxPointerProperties, coords)
+ .build()
+
+ topLevelContainerView?.dispatchTouchEvent(motionEventDown2)
+ topLevelContainerView?.dispatchTouchEvent(motionEventUp2)
+
+ // Delay but just enough to stay inside double tap timeframe
+ mainClock.advanceTimeBy(100)
+
+ assertTrue(doubleTapLatch.await(2, TimeUnit.SECONDS))
+
+ assertThat(composableTouchCount).isEqualTo(2)
+ assertThat(composableTapCount).isEqualTo(0)
+ assertThat(composableDoubleTapCount).isEqualTo(1)
+ assertThat(composableLongTapCount).isEqualTo(0)
+ }
}
diff --git a/compose/ui/ui-test/api/current.ignore b/compose/ui/ui-test/api/current.ignore
deleted file mode 100644
index 3e871ce1..0000000
--- a/compose/ui/ui-test/api/current.ignore
+++ /dev/null
@@ -1,15 +0,0 @@
-// Baseline format: 1.0
-ChangedType: androidx.compose.ui.test.ActionsKt#performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>, kotlin.jvm.functions.Function1<? super T,kotlin.Unit>):
- Method androidx.compose.ui.test.ActionsKt.performSemanticsAction has changed return type from androidx.compose.ui.test.SemanticsNodeInteraction to void
-ChangedType: androidx.compose.ui.test.ActionsKt#performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>>):
- Method androidx.compose.ui.test.ActionsKt.performSemanticsAction has changed return type from androidx.compose.ui.test.SemanticsNodeInteraction to void
-
-
-InvalidNullConversion: androidx.compose.ui.test.SemanticsMatcher.Companion#expectValue(androidx.compose.ui.semantics.SemanticsPropertyKey<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter expectedValue in androidx.compose.ui.test.SemanticsMatcher.Companion.expectValue(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T expectedValue)
-
-
-RemovedDeprecatedMethod: androidx.compose.ui.test.ActionsKt#performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit>):
- Removed deprecated method androidx.compose.ui.test.ActionsKt.performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction,androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>,kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit>)
-RemovedDeprecatedMethod: androidx.compose.ui.test.ActionsKt#performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>>):
- Removed deprecated method androidx.compose.ui.test.ActionsKt.performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction,androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>>)
diff --git a/compose/ui/ui-test/api/restricted_current.ignore b/compose/ui/ui-test/api/restricted_current.ignore
deleted file mode 100644
index 3e871ce1..0000000
--- a/compose/ui/ui-test/api/restricted_current.ignore
+++ /dev/null
@@ -1,15 +0,0 @@
-// Baseline format: 1.0
-ChangedType: androidx.compose.ui.test.ActionsKt#performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>, kotlin.jvm.functions.Function1<? super T,kotlin.Unit>):
- Method androidx.compose.ui.test.ActionsKt.performSemanticsAction has changed return type from androidx.compose.ui.test.SemanticsNodeInteraction to void
-ChangedType: androidx.compose.ui.test.ActionsKt#performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>>):
- Method androidx.compose.ui.test.ActionsKt.performSemanticsAction has changed return type from androidx.compose.ui.test.SemanticsNodeInteraction to void
-
-
-InvalidNullConversion: androidx.compose.ui.test.SemanticsMatcher.Companion#expectValue(androidx.compose.ui.semantics.SemanticsPropertyKey<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter expectedValue in androidx.compose.ui.test.SemanticsMatcher.Companion.expectValue(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T expectedValue)
-
-
-RemovedDeprecatedMethod: androidx.compose.ui.test.ActionsKt#performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit>):
- Removed deprecated method androidx.compose.ui.test.ActionsKt.performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction,androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>,kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit>)
-RemovedDeprecatedMethod: androidx.compose.ui.test.ActionsKt#performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>>):
- Removed deprecated method androidx.compose.ui.test.ActionsKt.performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction,androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>>)
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/ErrorMessagesTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/ErrorMessagesTest.kt
index dd27f9d..4596f86 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/ErrorMessagesTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/ErrorMessagesTest.kt
@@ -223,7 +223,7 @@
The node is no longer in the tree, last known semantics:
Node #X at (l=X, t=X, r=X, b=X)px
Text = '[Hello]'
- Actions = [GetTextLayoutResult]
+ Actions = [SetTextSubstitution, ShowTextSubstitution, ClearTextSubstitution, GetTextLayoutResult]
Has 1 sibling
Original selector: Text + EditableText contains 'Hello' (ignoreCase: false)
""".trimIndent()
@@ -251,7 +251,7 @@
The node is no longer in the tree, last known semantics:
Node #X at (l=X, t=X, r=X, b=X)px
Text = '[Hello]'
- Actions = [GetTextLayoutResult]
+ Actions = [SetTextSubstitution, ShowTextSubstitution, ClearTextSubstitution, GetTextLayoutResult]
Has 1 sibling
Original selector: Text + EditableText contains 'Hello' (ignoreCase: false)
""".trimIndent()
@@ -279,7 +279,7 @@
The node is no longer in the tree, last known semantics:
Node #X at (l=X, t=X, r=X, b=X)px
Text = '[Hello]'
- Actions = [GetTextLayoutResult]
+ Actions = [SetTextSubstitution, ShowTextSubstitution, ClearTextSubstitution, GetTextLayoutResult]
Has 1 sibling
Original selector: Text + EditableText contains 'Hello' (ignoreCase: false)
""".trimIndent()
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/PrintToStringTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/PrintToStringTest.kt
index 5d24c91..e8b9d96 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/PrintToStringTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/PrintToStringTest.kt
@@ -73,7 +73,7 @@
Printing with useUnmergedTree = 'false'
Node #X at (l=X, t=X, r=X, b=X)px
Text = '[Hello]'
- Actions = [GetTextLayoutResult]
+ Actions = [SetTextSubstitution, ShowTextSubstitution, ClearTextSubstitution, GetTextLayoutResult]
Has 1 sibling
""".trimIndent()
)
@@ -94,11 +94,11 @@
Printing with useUnmergedTree = 'false'
1) Node #X at (l=X, t=X, r=X, b=X)px
Text = '[Hello]'
- Actions = [GetTextLayoutResult]
+ Actions = [SetTextSubstitution, ShowTextSubstitution, ClearTextSubstitution, GetTextLayoutResult]
Has 1 sibling
2) Node #X at (l=X, t=X, r=X, b=X)px
Text = '[World]'
- Actions = [GetTextLayoutResult]
+ Actions = [SetTextSubstitution, ShowTextSubstitution, ClearTextSubstitution, GetTextLayoutResult]
Has 1 sibling
""".trimIndent()
)
@@ -132,11 +132,11 @@
| Focused = 'false'
| Role = 'Button'
| Text = '[Button]'
- | Actions = [OnClick, RequestFocus, GetTextLayoutResult]
+ | Actions = [OnClick, RequestFocus, SetTextSubstitution, ShowTextSubstitution, ClearTextSubstitution, GetTextLayoutResult]
| MergeDescendants = 'true'
|-Node #X at (l=X, t=X, r=X, b=X)px
Text = '[Hello]'
- Actions = [GetTextLayoutResult]
+ Actions = [SetTextSubstitution, ShowTextSubstitution, ClearTextSubstitution, GetTextLayoutResult]
""".trimIndent()
)
}
@@ -240,7 +240,7 @@
Printing with useUnmergedTree = 'false'
Node #X at (l=X, t=X, r=X, b=X)px
Text = '[first, second]'
- Actions = [GetTextLayoutResult]
+ Actions = [SetTextSubstitution, ShowTextSubstitution, ClearTextSubstitution, GetTextLayoutResult]
MergeDescendants = 'true'
""".trimIndent()
)
@@ -266,10 +266,10 @@
MergeDescendants = 'true'
|-Node #X at (l=X, t=X, r=X, b=X)px
| Text = '[first]'
- | Actions = [GetTextLayoutResult]
+ | Actions = [SetTextSubstitution, ShowTextSubstitution, ClearTextSubstitution, GetTextLayoutResult]
|-Node #X at (l=X, t=X, r=X, b=X)px
Text = '[second]'
- Actions = [GetTextLayoutResult]
+ Actions = [SetTextSubstitution, ShowTextSubstitution, ClearTextSubstitution, GetTextLayoutResult]
""".trimIndent()
)
}
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/TextActionsTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/TextActionsTest.kt
index f91c060..6be0f40 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/TextActionsTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/TextActionsTest.kt
@@ -27,7 +27,7 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.insertTextAtCursor
-import androidx.compose.ui.semantics.performImeAction
+import androidx.compose.ui.semantics.onImeAction
import androidx.compose.ui.semantics.requestFocus
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.setText
@@ -280,7 +280,7 @@
setText { true }
requestFocus { true }
insertTextAtCursor { true }
- performImeAction(ImeAction.Done) { false }
+ onImeAction(ImeAction.Done) { false }
})
}
@@ -314,7 +314,7 @@
rule.setContent {
BoundaryNode(testTag = "node", Modifier.semantics {
setText { true }
- performImeAction(ImeAction.Done) { true }
+ onImeAction(ImeAction.Done) { true }
})
}
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Filters.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Filters.kt
index d6fdb5a..abec397 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Filters.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Filters.kt
@@ -397,9 +397,9 @@
* Returns whether the node defines a semantics action to perform the
* [IME action][SemanticsProperties.ImeAction] on it.
*
- * @see SemanticsActions.PerformImeAction
+ * @see SemanticsActions.OnImeAction
*/
-fun hasPerformImeAction() = hasKey(SemanticsActions.PerformImeAction)
+fun hasPerformImeAction() = hasKey(SemanticsActions.OnImeAction)
/**
* Returns whether the node defines a semantics action to request focus.
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TextActions.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TextActions.kt
index 9cdb6fc..53c81a7 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TextActions.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TextActions.kt
@@ -17,11 +17,11 @@
package androidx.compose.ui.test
import androidx.compose.ui.semantics.SemanticsActions
-import androidx.compose.ui.semantics.SemanticsActions.PerformImeAction
+import androidx.compose.ui.semantics.SemanticsActions.OnImeAction
import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.semantics.SemanticsProperties
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
-import androidx.compose.ui.semantics.performImeAction
+import androidx.compose.ui.semantics.onImeAction
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.ImeAction
@@ -76,12 +76,12 @@
* Sends to this node the IME action associated with it in a similar way to the IME.
*
* The node needs to define its IME action in semantics via
- * [SemanticsPropertyReceiver.performImeAction].
+ * [SemanticsPropertyReceiver.onImeAction].
*
* @throws AssertionError if the node does not support input or does not define IME action.
* @throws IllegalStateException if the node did is not an editor or would not be able to establish
* an input connection (e.g. does not define [ImeAction][SemanticsProperties.ImeAction] or
- * [PerformImeAction] or is not focused).
+ * [OnImeAction] or is not focused).
*/
fun SemanticsNodeInteraction.performImeAction() {
val errorOnFail = "Failed to perform IME action."
@@ -90,7 +90,7 @@
val node = getNodeAndFocus(errorOnFail)
wrapAssertionErrorsWithNodeInfo(selector, node) {
- performSemanticsAction(PerformImeAction) {
+ performSemanticsAction(OnImeAction) {
assert(it()) {
buildGeneralErrorMessage(
"Failed to perform IME action, handler returned false.",
diff --git a/compose/ui/ui-text/CHANGELOG.md b/compose/ui/ui-text/CHANGELOG.md
new file mode 100644
index 0000000..b40c020
--- /dev/null
+++ b/compose/ui/ui-text/CHANGELOG.md
@@ -0,0 +1,21 @@
+# Log for changes in the Compose ui-text library
+#
+# `Added`: for new features
+# `Changed`: for changes in existing functionality
+# `Deprecated`: for soon to be removed functionality
+# `Removed`: for now removed feature
+# `Fixed`: for any bug fixes
+# `Security`: in case of vulnerabilities
+#
+# Possible headings:
+# API Changes
+# Bug Fixes
+# Dependency Updates
+# Behavior Change
+# External Contributions
+
+## Unreleased
+
+### New Features
+
+### Bug Fixes
diff --git a/compose/ui/ui-text/api/current.ignore b/compose/ui/ui-text/api/current.ignore
index bf842f8..fe35567 100644
--- a/compose/ui/ui-text/api/current.ignore
+++ b/compose/ui/ui-text/api/current.ignore
@@ -1,19 +1,11 @@
// Baseline format: 1.0
-AddedAbstractMethod: androidx.compose.ui.text.Paragraph#paint(androidx.compose.ui.graphics.Canvas, androidx.compose.ui.graphics.Brush, float, androidx.compose.ui.graphics.Shadow, androidx.compose.ui.text.style.TextDecoration, androidx.compose.ui.graphics.drawscope.DrawStyle, int):
- Added method androidx.compose.ui.text.Paragraph.paint(androidx.compose.ui.graphics.Canvas,androidx.compose.ui.graphics.Brush,float,androidx.compose.ui.graphics.Shadow,androidx.compose.ui.text.style.TextDecoration,androidx.compose.ui.graphics.drawscope.DrawStyle,int)
-AddedAbstractMethod: androidx.compose.ui.text.Paragraph#paint(androidx.compose.ui.graphics.Canvas, long, androidx.compose.ui.graphics.Shadow, androidx.compose.ui.text.style.TextDecoration, androidx.compose.ui.graphics.drawscope.DrawStyle, int):
- Added method androidx.compose.ui.text.Paragraph.paint(androidx.compose.ui.graphics.Canvas,long,androidx.compose.ui.graphics.Shadow,androidx.compose.ui.text.style.TextDecoration,androidx.compose.ui.graphics.drawscope.DrawStyle,int)
+AddedAbstractMethod: androidx.compose.ui.text.Paragraph#fillBoundingBoxes(long, float[], int):
+ Added method androidx.compose.ui.text.Paragraph.fillBoundingBoxes(long,float[],int)
-ChangedType: androidx.compose.ui.text.AnnotatedString.Builder#append(char):
- Method androidx.compose.ui.text.AnnotatedString.Builder.append has changed return type from androidx.compose.ui.text.AnnotatedString.Builder to void
-
-
-InvalidNullConversion: androidx.compose.ui.text.AnnotatedString.Range#Range(T, int, int) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter item in androidx.compose.ui.text.AnnotatedString.Range(T item, int start, int end)
-InvalidNullConversion: androidx.compose.ui.text.AnnotatedString.Range#Range(T, int, int, String) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter item in androidx.compose.ui.text.AnnotatedString.Range(T item, int start, int end, String tag)
-
-
-RemovedDeprecatedMethod: androidx.compose.ui.text.AnnotatedString.Builder#deprecated_append_returning_void(char):
- Removed deprecated method androidx.compose.ui.text.AnnotatedString.Builder.deprecated_append_returning_void(char)
+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 #0:
+ Attempted to change parameter name from fallbackFontFamilyResolver to defaultFontFamilyResolver 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 #1:
+ 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
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index b203bb5..e93dd1d 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -111,6 +111,7 @@
ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, long constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.FontFamily.Resolver fontFamilyResolver, optional java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, optional int maxLines, optional boolean ellipsis);
ctor @Deprecated public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, optional int maxLines, optional boolean ellipsis, float width);
ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, long constraints, optional int maxLines, optional boolean ellipsis);
+ method public float[] fillBoundingBoxes(long range, float[] array, int arrayStart);
method public androidx.compose.ui.text.style.ResolvedTextDirection getBidiRunDirection(int offset);
method public androidx.compose.ui.geometry.Rect getBoundingBox(int offset);
method public androidx.compose.ui.geometry.Rect getCursorRect(int offset);
@@ -172,6 +173,7 @@
}
public sealed interface Paragraph {
+ method public void fillBoundingBoxes(long range, float[] array, int arrayStart);
method public androidx.compose.ui.text.style.ResolvedTextDirection getBidiRunDirection(int offset);
method public androidx.compose.ui.geometry.Rect getBoundingBox(int offset);
method public androidx.compose.ui.geometry.Rect getCursorRect(int offset);
@@ -476,7 +478,7 @@
}
@androidx.compose.runtime.Immutable public final class TextMeasurer {
- ctor public TextMeasurer(androidx.compose.ui.text.font.FontFamily.Resolver fallbackFontFamilyResolver, androidx.compose.ui.unit.Density fallbackDensity, androidx.compose.ui.unit.LayoutDirection fallbackLayoutDirection, optional int cacheSize);
+ ctor public TextMeasurer(androidx.compose.ui.text.font.FontFamily.Resolver defaultFontFamilyResolver, androidx.compose.ui.unit.Density defaultDensity, androidx.compose.ui.unit.LayoutDirection defaultLayoutDirection, optional int cacheSize);
method @androidx.compose.runtime.Stable public androidx.compose.ui.text.TextLayoutResult measure(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.text.TextStyle style, optional int overflow, optional boolean softWrap, optional int maxLines, optional java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, optional long constraints, optional androidx.compose.ui.unit.LayoutDirection layoutDirection, optional androidx.compose.ui.unit.Density density, optional androidx.compose.ui.text.font.FontFamily.Resolver fontFamilyResolver, optional boolean skipCache);
method @androidx.compose.runtime.Stable public androidx.compose.ui.text.TextLayoutResult measure(String text, optional androidx.compose.ui.text.TextStyle style, optional int overflow, optional boolean softWrap, optional int maxLines, optional long constraints, optional androidx.compose.ui.unit.LayoutDirection layoutDirection, optional androidx.compose.ui.unit.Density density, optional androidx.compose.ui.text.font.FontFamily.Resolver fontFamilyResolver, optional boolean skipCache);
}
@@ -1083,21 +1085,21 @@
property public final char mask;
}
- @androidx.compose.ui.text.ExperimentalTextApi public sealed interface PlatformTextInput {
+ public sealed interface PlatformTextInput {
method public void releaseInputFocus();
method public void requestInputFocus();
}
- @androidx.compose.ui.text.ExperimentalTextApi public interface PlatformTextInputAdapter {
+ public interface PlatformTextInputAdapter {
method public android.view.inputmethod.InputConnection? createInputConnection(android.view.inputmethod.EditorInfo outAttrs);
method public default void onDisposed();
}
- @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public fun interface PlatformTextInputPlugin<T extends androidx.compose.ui.text.input.PlatformTextInputAdapter> {
+ @androidx.compose.runtime.Immutable public fun interface PlatformTextInputPlugin<T extends androidx.compose.ui.text.input.PlatformTextInputAdapter> {
method public T createAdapter(androidx.compose.ui.text.input.PlatformTextInput platformTextInput, android.view.View view);
}
- @androidx.compose.runtime.Stable @androidx.compose.ui.text.ExperimentalTextApi public sealed interface PlatformTextInputPluginRegistry {
+ @androidx.compose.runtime.Stable public sealed interface PlatformTextInputPluginRegistry {
method @androidx.compose.runtime.Composable public <T extends androidx.compose.ui.text.input.PlatformTextInputAdapter> T rememberAdapter(androidx.compose.ui.text.input.PlatformTextInputPlugin<T> plugin);
}
diff --git a/compose/ui/ui-text/api/restricted_current.ignore b/compose/ui/ui-text/api/restricted_current.ignore
index bf842f8..fe35567 100644
--- a/compose/ui/ui-text/api/restricted_current.ignore
+++ b/compose/ui/ui-text/api/restricted_current.ignore
@@ -1,19 +1,11 @@
// Baseline format: 1.0
-AddedAbstractMethod: androidx.compose.ui.text.Paragraph#paint(androidx.compose.ui.graphics.Canvas, androidx.compose.ui.graphics.Brush, float, androidx.compose.ui.graphics.Shadow, androidx.compose.ui.text.style.TextDecoration, androidx.compose.ui.graphics.drawscope.DrawStyle, int):
- Added method androidx.compose.ui.text.Paragraph.paint(androidx.compose.ui.graphics.Canvas,androidx.compose.ui.graphics.Brush,float,androidx.compose.ui.graphics.Shadow,androidx.compose.ui.text.style.TextDecoration,androidx.compose.ui.graphics.drawscope.DrawStyle,int)
-AddedAbstractMethod: androidx.compose.ui.text.Paragraph#paint(androidx.compose.ui.graphics.Canvas, long, androidx.compose.ui.graphics.Shadow, androidx.compose.ui.text.style.TextDecoration, androidx.compose.ui.graphics.drawscope.DrawStyle, int):
- Added method androidx.compose.ui.text.Paragraph.paint(androidx.compose.ui.graphics.Canvas,long,androidx.compose.ui.graphics.Shadow,androidx.compose.ui.text.style.TextDecoration,androidx.compose.ui.graphics.drawscope.DrawStyle,int)
+AddedAbstractMethod: androidx.compose.ui.text.Paragraph#fillBoundingBoxes(long, float[], int):
+ Added method androidx.compose.ui.text.Paragraph.fillBoundingBoxes(long,float[],int)
-ChangedType: androidx.compose.ui.text.AnnotatedString.Builder#append(char):
- Method androidx.compose.ui.text.AnnotatedString.Builder.append has changed return type from androidx.compose.ui.text.AnnotatedString.Builder to void
-
-
-InvalidNullConversion: androidx.compose.ui.text.AnnotatedString.Range#Range(T, int, int) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter item in androidx.compose.ui.text.AnnotatedString.Range(T item, int start, int end)
-InvalidNullConversion: androidx.compose.ui.text.AnnotatedString.Range#Range(T, int, int, String) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter item in androidx.compose.ui.text.AnnotatedString.Range(T item, int start, int end, String tag)
-
-
-RemovedDeprecatedMethod: androidx.compose.ui.text.AnnotatedString.Builder#deprecated_append_returning_void(char):
- Removed deprecated method androidx.compose.ui.text.AnnotatedString.Builder.deprecated_append_returning_void(char)
+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 #0:
+ Attempted to change parameter name from fallbackFontFamilyResolver to defaultFontFamilyResolver 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 #1:
+ 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
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index b203bb5..e93dd1d 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -111,6 +111,7 @@
ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, long constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.FontFamily.Resolver fontFamilyResolver, optional java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, optional int maxLines, optional boolean ellipsis);
ctor @Deprecated public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, optional int maxLines, optional boolean ellipsis, float width);
ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, long constraints, optional int maxLines, optional boolean ellipsis);
+ method public float[] fillBoundingBoxes(long range, float[] array, int arrayStart);
method public androidx.compose.ui.text.style.ResolvedTextDirection getBidiRunDirection(int offset);
method public androidx.compose.ui.geometry.Rect getBoundingBox(int offset);
method public androidx.compose.ui.geometry.Rect getCursorRect(int offset);
@@ -172,6 +173,7 @@
}
public sealed interface Paragraph {
+ method public void fillBoundingBoxes(long range, float[] array, int arrayStart);
method public androidx.compose.ui.text.style.ResolvedTextDirection getBidiRunDirection(int offset);
method public androidx.compose.ui.geometry.Rect getBoundingBox(int offset);
method public androidx.compose.ui.geometry.Rect getCursorRect(int offset);
@@ -476,7 +478,7 @@
}
@androidx.compose.runtime.Immutable public final class TextMeasurer {
- ctor public TextMeasurer(androidx.compose.ui.text.font.FontFamily.Resolver fallbackFontFamilyResolver, androidx.compose.ui.unit.Density fallbackDensity, androidx.compose.ui.unit.LayoutDirection fallbackLayoutDirection, optional int cacheSize);
+ ctor public TextMeasurer(androidx.compose.ui.text.font.FontFamily.Resolver defaultFontFamilyResolver, androidx.compose.ui.unit.Density defaultDensity, androidx.compose.ui.unit.LayoutDirection defaultLayoutDirection, optional int cacheSize);
method @androidx.compose.runtime.Stable public androidx.compose.ui.text.TextLayoutResult measure(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.text.TextStyle style, optional int overflow, optional boolean softWrap, optional int maxLines, optional java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, optional long constraints, optional androidx.compose.ui.unit.LayoutDirection layoutDirection, optional androidx.compose.ui.unit.Density density, optional androidx.compose.ui.text.font.FontFamily.Resolver fontFamilyResolver, optional boolean skipCache);
method @androidx.compose.runtime.Stable public androidx.compose.ui.text.TextLayoutResult measure(String text, optional androidx.compose.ui.text.TextStyle style, optional int overflow, optional boolean softWrap, optional int maxLines, optional long constraints, optional androidx.compose.ui.unit.LayoutDirection layoutDirection, optional androidx.compose.ui.unit.Density density, optional androidx.compose.ui.text.font.FontFamily.Resolver fontFamilyResolver, optional boolean skipCache);
}
@@ -1083,21 +1085,21 @@
property public final char mask;
}
- @androidx.compose.ui.text.ExperimentalTextApi public sealed interface PlatformTextInput {
+ public sealed interface PlatformTextInput {
method public void releaseInputFocus();
method public void requestInputFocus();
}
- @androidx.compose.ui.text.ExperimentalTextApi public interface PlatformTextInputAdapter {
+ public interface PlatformTextInputAdapter {
method public android.view.inputmethod.InputConnection? createInputConnection(android.view.inputmethod.EditorInfo outAttrs);
method public default void onDisposed();
}
- @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public fun interface PlatformTextInputPlugin<T extends androidx.compose.ui.text.input.PlatformTextInputAdapter> {
+ @androidx.compose.runtime.Immutable public fun interface PlatformTextInputPlugin<T extends androidx.compose.ui.text.input.PlatformTextInputAdapter> {
method public T createAdapter(androidx.compose.ui.text.input.PlatformTextInput platformTextInput, android.view.View view);
}
- @androidx.compose.runtime.Stable @androidx.compose.ui.text.ExperimentalTextApi public sealed interface PlatformTextInputPluginRegistry {
+ @androidx.compose.runtime.Stable public sealed interface PlatformTextInputPluginRegistry {
method @androidx.compose.runtime.Composable public <T extends androidx.compose.ui.text.input.PlatformTextInputAdapter> T rememberAdapter(androidx.compose.ui.text.input.PlatformTextInputPlugin<T> plugin);
}
diff --git a/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/TextMeasurerBenchmark.kt b/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/TextMeasurerBenchmark.kt
index 993ebf5..27e9cb6 100644
--- a/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/TextMeasurerBenchmark.kt
+++ b/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/TextMeasurerBenchmark.kt
@@ -96,9 +96,9 @@
fun text_measurer_no_cache() {
textBenchmarkRule.generator { textGenerator ->
val textMeasurer = TextMeasurer(
- fallbackFontFamilyResolver = createFontFamilyResolver(instrumentationContext),
- fallbackDensity = Density(instrumentationContext),
- fallbackLayoutDirection = LayoutDirection.Ltr,
+ defaultFontFamilyResolver = createFontFamilyResolver(instrumentationContext),
+ defaultDensity = Density(instrumentationContext),
+ defaultLayoutDirection = LayoutDirection.Ltr,
cacheSize = 0
)
val text = text(textGenerator)
@@ -116,9 +116,9 @@
fun text_measurer_cached() {
textBenchmarkRule.generator { textGenerator ->
val textMeasurer = TextMeasurer(
- fallbackFontFamilyResolver = createFontFamilyResolver(instrumentationContext),
- fallbackDensity = Density(instrumentationContext),
- fallbackLayoutDirection = LayoutDirection.Ltr,
+ defaultFontFamilyResolver = createFontFamilyResolver(instrumentationContext),
+ defaultDensity = Density(instrumentationContext),
+ defaultLayoutDirection = LayoutDirection.Ltr,
cacheSize = 16
)
val text = text(textGenerator)
@@ -136,9 +136,9 @@
fun drawText_TextLayoutResult_no_change() {
textBenchmarkRule.generator { textGenerator ->
val textMeasurer = TextMeasurer(
- fallbackFontFamilyResolver = createFontFamilyResolver(instrumentationContext),
- fallbackDensity = Density(instrumentationContext),
- fallbackLayoutDirection = LayoutDirection.Ltr,
+ defaultFontFamilyResolver = createFontFamilyResolver(instrumentationContext),
+ defaultDensity = Density(instrumentationContext),
+ defaultLayoutDirection = LayoutDirection.Ltr,
cacheSize = 16
)
val textLayoutResult = textMeasurer.measure(
@@ -167,9 +167,9 @@
fun drawText_TextLayoutResult_color_override() {
textBenchmarkRule.generator { textGenerator ->
val textMeasurer = TextMeasurer(
- fallbackFontFamilyResolver = createFontFamilyResolver(instrumentationContext),
- fallbackDensity = Density(instrumentationContext),
- fallbackLayoutDirection = LayoutDirection.Ltr,
+ defaultFontFamilyResolver = createFontFamilyResolver(instrumentationContext),
+ defaultDensity = Density(instrumentationContext),
+ defaultLayoutDirection = LayoutDirection.Ltr,
cacheSize = 16
)
val textLayoutResult = textMeasurer.measure(
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphFillBoundingBoxesTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphFillBoundingBoxesTest.kt
new file mode 100644
index 0000000..8e10bd4
--- /dev/null
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphFillBoundingBoxesTest.kt
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.compose.ui.text
+
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.text.FontTestData.Companion.BASIC_MEASURE_FONT
+import androidx.compose.ui.text.font.createFontFamilyResolver
+import androidx.compose.ui.text.font.toFontFamily
+import androidx.compose.ui.text.matchers.assertThat
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.sp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class MultiParagraphFillBoundingBoxesTest {
+ private val fontFamilyMeasureFont = BASIC_MEASURE_FONT.toFontFamily()
+ val fontFamilyResolver = createFontFamilyResolver(
+ InstrumentationRegistry.getInstrumentation().context
+ )
+ private val defaultDensity = Density(density = 1f)
+ private val fontSize = 10.sp
+ private val fontSizeInPx = with(defaultDensity) { fontSize.toPx() }
+
+ @Test
+ fun singleParagraphLtr() {
+ val text = createAnnotatedString("ab")
+ val paragraph = simpleMultiParagraph(text)
+
+ val result = paragraph.getBoundingBoxes(TextRange(0, text.length))
+
+ assertThat(result).isEqualToWithTolerance(
+ ltrCharacterBoundariesForTestFont(text.text)
+ )
+ }
+
+ @Test
+ fun singleParagraphRtl() {
+ val text = createAnnotatedString("\u05D0\u05D1")
+ val width = fontSizeInPx * 3
+ val paragraph = simpleMultiParagraph(text, width = width)
+
+ val result = paragraph.getBoundingBoxes(TextRange(0, text.length))
+
+ assertThat(result).isEqualToWithTolerance(
+ rtlCharacterBoundariesForTestFont(text.text, width)
+ )
+ }
+
+ @Test
+ fun ltr() {
+ val paragraph1 = "a"
+ val paragraph2 = "b"
+ val text = createAnnotatedString(paragraph1, paragraph2)
+ val paragraph = simpleMultiParagraph(text)
+
+ val result = paragraph.getBoundingBoxes(TextRange(0, text.length))
+
+ val paragraph1Rects = ltrCharacterBoundariesForTestFont(paragraph1)
+ val paragraph2Rects = ltrCharacterBoundariesForTestFont(paragraph2)
+ assertThat(result).isEqualToWithTolerance(
+ paragraph1Rects.offsetVerticalAndAppend(paragraph2Rects)
+ )
+ }
+
+ @Test
+ fun rtl() {
+ val paragraph1 = "\u05D0"
+ val paragraph2 = "\u05D1"
+ val text = createAnnotatedString(paragraph1, paragraph2)
+ val width = fontSizeInPx * 3
+ val paragraph = simpleMultiParagraph(text, width = width)
+
+ val result = paragraph.getBoundingBoxes(TextRange(0, text.length))
+
+ val paragraph1Rects = rtlCharacterBoundariesForTestFont(paragraph1, width)
+ val paragraph2Rects = rtlCharacterBoundariesForTestFont(paragraph2, width)
+ assertThat(result).isEqualToWithTolerance(
+ paragraph1Rects.offsetVerticalAndAppend(paragraph2Rects)
+ )
+ }
+
+ @Test
+ fun multiLineLtr() {
+ val paragraph1 = "a\nb"
+ val paragraph2 = "c\nd"
+ val text = createAnnotatedString(paragraph1, paragraph2)
+ val paragraph = simpleMultiParagraph(text)
+
+ val result = paragraph.getBoundingBoxes(TextRange(0, text.length))
+
+ val paragraph1Rects = ltrCharacterBoundariesForTestFont(paragraph1)
+ val paragraph2Rects = ltrCharacterBoundariesForTestFont(paragraph2)
+ assertThat(result).isEqualToWithTolerance(
+ paragraph1Rects.offsetVerticalAndAppend(paragraph2Rects)
+ )
+ }
+
+ @Test
+ fun multiLineRtl() {
+ val paragraph1 = "\u05D0\n\u05D1"
+ val paragraph2 = "\u05D2\n\u05D3"
+ val text = createAnnotatedString(paragraph1, paragraph2)
+ val width = fontSizeInPx * 3
+ val paragraph = simpleMultiParagraph(text, width = width)
+
+ val result = paragraph.getBoundingBoxes(TextRange(0, text.length))
+
+ val paragraph1Rects = rtlCharacterBoundariesForTestFont(paragraph1, width)
+ val paragraph2Rects = rtlCharacterBoundariesForTestFont(paragraph2, width)
+ assertThat(result).isEqualToWithTolerance(
+ paragraph1Rects.offsetVerticalAndAppend(paragraph2Rects)
+ )
+ }
+
+ @Test
+ fun ltrAndRtlParagraphs() {
+ val paragraph1 = "a\nb"
+ var paragraph2 = "\u05D0\n\u05D1"
+ val text = createAnnotatedString(paragraph1, paragraph2)
+ val width = fontSizeInPx * 3
+ val paragraph = simpleMultiParagraph(text, width = width)
+
+ val result = paragraph.getBoundingBoxes(TextRange(0, text.length))
+
+ val paragraph1Rects = ltrCharacterBoundariesForTestFont(paragraph1)
+ val paragraph2Rects = rtlCharacterBoundariesForTestFont(paragraph2, width)
+ assertThat(result).isEqualTo(
+ paragraph1Rects.offsetVerticalAndAppend(paragraph2Rects)
+ )
+ }
+
+ private fun MultiParagraph.getBoundingBoxes(range: TextRange): Array<Rect> {
+ val arraySize = range.length * 4
+ val array = FloatArray(arraySize)
+ fillBoundingBoxes(range, array, 0)
+ return array.asRectArray()
+ }
+
+ /**
+ * Updates the vertical positions of the [other] rectangle array based on the bottom of this
+ * rectangle array; then appends to the current one.
+ */
+ private fun Array<Rect>.offsetVerticalAndAppend(other: Array<Rect>): Array<Rect> {
+ return this + other.offsetVerticalBy(this.last().bottom)
+ }
+
+ /**
+ * Offsets top and bottom positions of rectangles in this array with [value].
+ */
+ private fun Array<Rect>.offsetVerticalBy(value: Float): Array<Rect> {
+ return this.map {
+ Rect(it.left, it.top + value, it.right, it.bottom + value)
+ }.toTypedArray()
+ }
+
+ private fun ltrCharacterBoundariesForTestFont(text: String): Array<Rect> =
+ getLtrCharacterBoundariesForTestFont(text, fontSizeInPx)
+
+ private fun rtlCharacterBoundariesForTestFont(text: String, width: Float): Array<Rect> =
+ getRtlCharacterBoundariesForTestFont(text, width, fontSizeInPx)
+
+ private fun createAnnotatedString(vararg paragraphs: String) =
+ createAnnotatedString(paragraphs.toList())
+
+ private fun createAnnotatedString(paragraphs: List<String>): AnnotatedString {
+ return buildAnnotatedString {
+ for (paragraph in paragraphs) {
+ pushStyle(ParagraphStyle())
+ append(paragraph)
+ pop()
+ }
+ }
+ }
+
+ private fun simpleMultiParagraph(
+ text: AnnotatedString,
+ width: Float = Float.MAX_VALUE
+ ): MultiParagraph {
+ return MultiParagraph(
+ annotatedString = text,
+ style = TextStyle(
+ fontFamily = fontFamilyMeasureFont,
+ fontSize = fontSize
+ ),
+ constraints = Constraints(maxWidth = width.ceilToInt()),
+ density = defaultDensity,
+ fontFamilyResolver = fontFamilyResolver
+ )
+ }
+}
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextTestExtensions.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextTestExtensions.kt
index 102ce80a..2799025 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextTestExtensions.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextTestExtensions.kt
@@ -167,6 +167,17 @@
PlatformFontFamilyTypefaceAdapter()
)
+fun MultiParagraph.bitmap(): Bitmap {
+ val bitmap = Bitmap.createBitmap(
+ width.toIntPx(),
+ height.toIntPx(),
+ Bitmap.Config.ARGB_8888
+ )
+ val canvas = androidx.compose.ui.graphics.Canvas(Canvas(bitmap))
+ this.paint(canvas)
+ return bitmap
+}
+
fun Float.toIntPx(): Int = ceil(this).roundToInt()
internal fun FloatArray.asRectArray(): Array<Rect> {
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidParagraph.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidParagraph.android.kt
index 677b664..1eb166c 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidParagraph.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidParagraph.android.kt
@@ -342,7 +342,7 @@
* @param arrayStart the inclusive start index in the array where the function will start
* filling in the values from
*/
- fun fillBoundingBoxes(
+ override fun fillBoundingBoxes(
range: TextRange,
array: FloatArray,
arrayStart: Int
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidTextStyle.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidTextStyle.android.kt
index 3744926..5aef6b2 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidTextStyle.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidTextStyle.android.kt
@@ -16,7 +16,7 @@
package androidx.compose.ui.text
-internal const val DefaultIncludeFontPadding = true
+internal const val DefaultIncludeFontPadding = false
/**
* Provides Android specific [TextStyle] configuration options for styling and compatibility.
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/Paragraph.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/Paragraph.android.kt
index 83ba3cb..2a0538e 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/Paragraph.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/Paragraph.android.kt
@@ -56,6 +56,7 @@
actual fun getLineForVerticalPosition(vertical: Float): Int
actual fun getOffsetForPosition(position: Offset): Int
actual fun getBoundingBox(offset: Int): Rect
+ actual fun fillBoundingBoxes(range: TextRange, array: FloatArray, arrayStart: Int)
actual fun getWordBoundary(offset: Int): TextRange
actual fun paint(canvas: Canvas, color: Color, shadow: Shadow?, textDecoration: TextDecoration?)
actual fun paint(
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/input/PlatformTextInputAdapter.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/input/PlatformTextInputAdapter.android.kt
index 99b70b4..c7b92b1 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/input/PlatformTextInputAdapter.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/input/PlatformTextInputAdapter.android.kt
@@ -20,7 +20,6 @@
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import androidx.compose.runtime.Immutable
-import androidx.compose.ui.text.ExperimentalTextApi
/**
* Defines a plugin to the Compose text input system. Instances of this interface should be
@@ -36,7 +35,6 @@
* Implementations are intended to be used only by your text editor implementation, and probably not
* exposed as public API.
*/
-@ExperimentalTextApi
@Immutable
actual fun interface PlatformTextInputPlugin<T : PlatformTextInputAdapter> {
/**
@@ -70,7 +68,6 @@
* exposed as public API. Your adapter can define whatever internal API it needs to communicate with
* the rest of your text editor code.
*/
-@ExperimentalTextApi
actual interface PlatformTextInputAdapter {
// TODO(b/267235947) When fleshing out the desktop actual, we might want to pull some of these
// members up into the expect interface (e.g. maybe inputForTests).
@@ -85,7 +82,6 @@
fun onDisposed() {}
}
-@OptIn(ExperimentalTextApi::class)
internal actual fun PlatformTextInputAdapter.dispose() {
onDisposed()
}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidTextPaint.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidTextPaint.android.kt
index 7a190ac..cc7c683 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidTextPaint.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidTextPaint.android.kt
@@ -28,12 +28,12 @@
import androidx.compose.ui.graphics.ShaderBrush
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.asComposePaint
import androidx.compose.ui.graphics.drawscope.DrawStyle
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.isSpecified
import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.graphics.toComposePaint
import androidx.compose.ui.text.platform.extensions.correctBlurRadius
import androidx.compose.ui.text.style.TextDecoration
import kotlin.math.roundToInt
@@ -44,7 +44,7 @@
}
// A wrapper to use Compose Paint APIs on this TextPaint
- private val composePaint: Paint = this.toComposePaint()
+ private val composePaint: Paint = this.asComposePaint()
private var textDecoration: TextDecoration = TextDecoration.None
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
index c0fb6f3..7043425 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
@@ -442,14 +442,9 @@
if (start == end) return Path()
- val paragraphIndex = findParagraphByIndex(paragraphInfoList, start)
val path = Path()
-
- for (i in paragraphIndex until paragraphInfoList.size) {
- val p = paragraphInfoList[i]
- if (p.startIndex >= end) break
- if (p.startIndex == p.endIndex) continue
- with(p) {
+ findParagraphsByRange(paragraphInfoList, TextRange(start, end)) { paragraphInfo ->
+ with(paragraphInfo) {
path.addPath(
path = paragraph.getPathForRange(
start = start.toLocalIndex(),
@@ -458,6 +453,7 @@
)
}
}
+
return path
}
@@ -513,6 +509,66 @@
}
/**
+ * Fills the bounding boxes for characters provided in the [range] into [array]. The array is
+ * filled starting from [arrayStart] (inclusive). The coordinates are in local text layout
+ * coordinates.
+ *
+ * The returned information consists of left/right of a character; line top and bottom for the
+ * same character.
+ *
+ * For the grapheme consists of multiple code points, e.g. ligatures, combining marks, the first
+ * character has the total width and the remaining are returned as zero-width.
+ *
+ * The array divided into segments of four where each index in that segment represents left,
+ * top, right, bottom of the character.
+ *
+ * The size of the provided [array] should be greater or equal than the four times * [TextRange]
+ * length.
+ *
+ * The final order of characters in the [array] is from [TextRange.min] to [TextRange.max].
+ *
+ * @param range the [TextRange] representing the start and end indices in the [Paragraph].
+ * @param array the array to fill in the values. The array divided into segments of four where
+ * each index in that segment represents left, top, right, bottom of the character.
+ * @param arrayStart the inclusive start index in the array where the function will start
+ * filling in the values from
+ */
+ fun fillBoundingBoxes(
+ range: TextRange,
+ array: FloatArray,
+ arrayStart: Int
+ ): FloatArray {
+ requireIndexInRange(range.min)
+ requireIndexInRangeInclusiveEnd(range.max)
+
+ var currentArrayStart = arrayStart
+ var currentHeight = 0f
+ findParagraphsByRange(paragraphInfoList, range) { paragraphInfo ->
+ with(paragraphInfo) {
+ val paragraphStart = if (startIndex > range.min) startIndex else range.min
+ val paragraphEnd = if (endIndex < range.max) endIndex else range.max
+ val finalRange = TextRange(
+ paragraphStart.toLocalIndex(),
+ paragraphEnd.toLocalIndex()
+ )
+ paragraph.fillBoundingBoxes(finalRange, array, currentArrayStart)
+ val currentArrayEnd = currentArrayStart + finalRange.length * 4
+ var arrayIndex = currentArrayStart
+ while (arrayIndex < currentArrayEnd) {
+ // update top and bottom
+ array[arrayIndex + 1] += currentHeight
+ array[arrayIndex + 3] += currentHeight
+ arrayIndex += 4
+ }
+ currentArrayStart = currentArrayEnd
+ currentHeight += paragraphInfo.paragraph.height
+ }
+ }
+
+ return array
+ }
+
+ /**
* Compute the horizontal position where a newly inserted character at [offset] would be.
*
* If the inserted character at [offset] is within a LTR/RTL run, the returned position will be
@@ -828,6 +884,20 @@
}
}
+internal fun findParagraphsByRange(
+ paragraphInfoList: List<ParagraphInfo>,
+ range: TextRange,
+ action: (ParagraphInfo) -> Unit
+) {
+ val paragraphIndex = findParagraphByIndex(paragraphInfoList, range.min)
+ for (i in paragraphIndex until paragraphInfoList.size) {
+ val paragraph = paragraphInfoList[i]
+ if (paragraph.startIndex >= range.max) break
+ if (paragraph.startIndex == paragraph.endIndex) continue
+ action(paragraph)
+ }
+}
+
/**
* Given an line index in [MultiParagraph], find the corresponding [ParagraphInfo] which
* covers the provided line index.
@@ -979,4 +1049,4 @@
fun TextRange.toGlobal(): TextRange {
return TextRange(start = start.toGlobalIndex(), end = end.toGlobalIndex())
}
-}
\ No newline at end of file
+}
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt
index b3653ef..8cbe75b 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt
@@ -230,6 +230,37 @@
fun getBoundingBox(offset: Int): Rect
/**
+ * Fills the bounding boxes for characters provided in the [range] into [array]. The array is
+ * filled starting from [arrayStart] (inclusive). The coordinates are in local text layout
+ * coordinates.
+ *
+ * The returned information consists of left/right of a character; line top and bottom for the
+ * same character.
+ *
+ * For the grapheme consists of multiple code points, e.g. ligatures, combining marks, the first
+ * character has the total width and the remaining are returned as zero-width.
+ *
+ * The array divided into segments of four where each index in that segment represents left,
+ * top, right, bottom of the character.
+ *
+ * The size of the provided [array] should be greater or equal than the four times * [TextRange]
+ * length.
+ *
+ * The final order of characters in the [array] is from [TextRange.min] to [TextRange.max].
+ *
+ * @param range the [TextRange] representing the start and end indices in the [Paragraph].
+ * @param array the array to fill in the values. The array divided into segments of four where
+ * each index in that segment represents left, top, right, bottom of the character.
+ * @param arrayStart the inclusive start index in the array where the function will start
+ * filling in the values from
+ */
+ fun fillBoundingBoxes(
+ range: TextRange,
+ array: FloatArray,
+ arrayStart: Int
+ )
+
+ /**
* Returns the TextRange of the word at the given character offset. Characters not
* part of a word, such as spaces, symbols, and punctuation, have word breaks
* on both sides. In such cases, this method will return TextRange(offset, offset).
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurer.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurer.kt
index 61ac3a6..eb8cef9 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurer.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurer.kt
@@ -64,13 +64,13 @@
*
* [FontFamily.Resolver], [LayoutDirection], and [Density] are required parameters to construct a
* text layout but they have no safe fallbacks outside of composition. These parameters must be
- * provided during the construction of a [TextMeasurer] to be used as default values when they
+ * provided during the construction of a TextMeasurer to be used as default values when they
* are skipped in [TextMeasurer.measure] call.
*
- * @param fallbackFontFamilyResolver to be used to load fonts given in [TextStyle] and [SpanStyle]s
+ * @param defaultFontFamilyResolver to be used to load fonts given in [TextStyle] and [SpanStyle]s
* in [AnnotatedString].
- * @param fallbackLayoutDirection layout direction of the measurement environment.
- * @param fallbackDensity density of the measurement environment. Density controls the scaling
+ * @param defaultLayoutDirection layout direction of the measurement environment.
+ * @param defaultDensity density of the measurement environment. Density controls the scaling
* factor for fonts.
* @param cacheSize Capacity of internal cache inside TextMeasurer. Size unit is the number of
* unique text layout inputs that are measured. Value of this parameter highly depends on the
@@ -81,9 +81,9 @@
*/
@Immutable
class TextMeasurer constructor(
- private val fallbackFontFamilyResolver: FontFamily.Resolver,
- private val fallbackDensity: Density,
- private val fallbackLayoutDirection: LayoutDirection,
+ private val defaultFontFamilyResolver: FontFamily.Resolver,
+ private val defaultDensity: Density,
+ private val defaultLayoutDirection: LayoutDirection,
private val cacheSize: Int = DefaultCacheSize
) {
private val textLayoutCache: TextLayoutCache? = if (cacheSize > 0) {
@@ -145,9 +145,9 @@
maxLines: Int = Int.MAX_VALUE,
placeholders: List<AnnotatedString.Range<Placeholder>> = emptyList(),
constraints: Constraints = Constraints(),
- layoutDirection: LayoutDirection = this.fallbackLayoutDirection,
- density: Density = this.fallbackDensity,
- fontFamilyResolver: FontFamily.Resolver = this.fallbackFontFamilyResolver,
+ layoutDirection: LayoutDirection = this.defaultLayoutDirection,
+ density: Density = this.defaultDensity,
+ fontFamilyResolver: FontFamily.Resolver = this.defaultFontFamilyResolver,
skipCache: Boolean = false
): TextLayoutResult {
val requestedTextLayoutInput = TextLayoutInput(
@@ -234,9 +234,9 @@
softWrap: Boolean = true,
maxLines: Int = Int.MAX_VALUE,
constraints: Constraints = Constraints(),
- layoutDirection: LayoutDirection = this.fallbackLayoutDirection,
- density: Density = this.fallbackDensity,
- fontFamilyResolver: FontFamily.Resolver = this.fallbackFontFamilyResolver,
+ layoutDirection: LayoutDirection = this.defaultLayoutDirection,
+ density: Density = this.defaultDensity,
+ fontFamilyResolver: FontFamily.Resolver = this.defaultFontFamilyResolver,
skipCache: Boolean = false
): TextLayoutResult {
return measure(
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/PlatformTextInputAdapter.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/PlatformTextInputAdapter.kt
index c2f3ac6..4e98c77 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/PlatformTextInputAdapter.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/PlatformTextInputAdapter.kt
@@ -36,13 +36,13 @@
/** See kdoc on actual interfaces. */
// Experimental in desktop.
-@ExperimentalTextApi
+@OptIn(ExperimentalTextApi::class)
@Immutable
expect interface PlatformTextInputPlugin<T : PlatformTextInputAdapter>
/** See kdoc on actual interfaces. */
// Experimental in desktop.
-@ExperimentalTextApi
+@OptIn(ExperimentalTextApi::class)
expect interface PlatformTextInputAdapter
/**
@@ -58,7 +58,6 @@
* methods that allow adapters to interact with it. Instances are passed to
* [PlatformTextInputPlugin.createAdapter].
*/
-@ExperimentalTextApi
sealed interface PlatformTextInput {
/**
* Requests that the platform input be connected to this receiver until either:
@@ -91,7 +90,6 @@
*/
// Implementation note: this is separated as a sealed interface + impl pair to avoid exposing
// @InternalTextApi members to code reading LocalPlatformTextInputAdapterProvider.
-@ExperimentalTextApi
@Stable
sealed interface PlatformTextInputPluginRegistry {
/**
diff --git a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/Paragraph.skiko.kt b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/Paragraph.skiko.kt
index 83ba3cb..2a0538e 100644
--- a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/Paragraph.skiko.kt
+++ b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/Paragraph.skiko.kt
@@ -56,6 +56,7 @@
actual fun getLineForVerticalPosition(vertical: Float): Int
actual fun getOffsetForPosition(position: Offset): Int
actual fun getBoundingBox(offset: Int): Rect
+ actual fun fillBoundingBoxes(range: TextRange, array: FloatArray, arrayStart: Int)
actual fun getWordBoundary(offset: Int): TextRange
actual fun paint(canvas: Canvas, color: Color, shadow: Shadow?, textDecoration: TextDecoration?)
actual fun paint(
diff --git a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/SkiaParagraph.skiko.kt b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/SkiaParagraph.skiko.kt
index 1dde5de..babb31c 100644
--- a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/SkiaParagraph.skiko.kt
+++ b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/SkiaParagraph.skiko.kt
@@ -279,6 +279,14 @@
return box.rect.toComposeRect()
}
+ override fun fillBoundingBoxes(
+ range: TextRange,
+ array: FloatArray,
+ arrayStart: Int
+ ) {
+ // TODO(siyamed) needs fillBoundingBoxes
+ }
+
override fun getWordBoundary(offset: Int): TextRange {
return when {
(text[offset].isLetterOrDigit()) -> para.getWordBoundary(offset).let {
diff --git a/compose/ui/ui-tooling-preview/lint-baseline.xml b/compose/ui/ui-tooling-preview/lint-baseline.xml
deleted file mode 100644
index 5a8706a..0000000
--- a/compose/ui/ui-tooling-preview/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="annotation class UiMode"
- errorLine2=" ~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/tooling/preview/UiMode.kt"/>
- </issue>
-
-</issues>
diff --git a/compose/ui/ui-tooling-preview/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/UiMode.kt b/compose/ui/ui-tooling-preview/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/UiMode.kt
index 13e53cb..5ea037f 100644
--- a/compose/ui/ui-tooling-preview/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/UiMode.kt
+++ b/compose/ui/ui-tooling-preview/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/UiMode.kt
@@ -31,11 +31,12 @@
import android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET
import android.content.res.Configuration.UI_MODE_TYPE_WATCH
import androidx.annotation.IntDef
+import androidx.annotation.RestrictTo
/**
* Annotation of setting uiMode in [Preview].
- * @hide
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY)
@SuppressLint("UniqueConstants") // UI_MODE_NIGHT_UNDEFINED == UI_MODE_TYPE_UNDEFINED
@Retention(AnnotationRetention.SOURCE)
@IntDef(
diff --git a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/ComposeInvokerTest.kt b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/ComposeInvokerTest.kt
index e1233ef..ecc4200 100644
--- a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/ComposeInvokerTest.kt
+++ b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/ComposeInvokerTest.kt
@@ -20,6 +20,9 @@
import androidx.compose.runtime.currentComposer
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import java.lang.reflect.InvocationTargetException
import org.junit.Assert.fail
import org.junit.Rule
@@ -44,6 +47,28 @@
}
@Test
+ fun composableWithBooleanPreviewParams() {
+ rule.setContent {
+ ComposableInvoker.invokeComposable(
+ "androidx.compose.ui.tooling.MyTestComposableWithBooleanPreviewParams",
+ "TestContent",
+ currentComposer
+ )
+ }
+ }
+
+ @Test
+ fun composableWithIntPreviewParams() {
+ rule.setContent {
+ ComposableInvoker.invokeComposable(
+ "androidx.compose.ui.tooling.MyTestComposableWithIntPreviewParams",
+ "TestContent",
+ currentComposer
+ )
+ }
+ }
+
+ @Test
fun composableClassNotFound() {
try {
rule.setContent {
@@ -95,10 +120,51 @@
class MyTestComposables {
@Composable
- fun MyWorkingComposable() {}
+ fun MyWorkingComposable() {
+ }
@Composable
fun MyThrowExceptionComposable() {
throw Exception("An Exception")
}
+}
+
+class MyTestComposableWithBooleanPreviewParams {
+
+ @Composable
+ fun TestContent() {
+ }
+
+ @Preview
+ @Composable
+ private fun TestContent(
+ @PreviewParameter(TestContentParameterProviderBoolean::class)
+ @Suppress("UNUSED_PARAMETER")
+ valueParameter: Boolean
+ ) {
+ }
+
+ private class TestContentParameterProviderBoolean : PreviewParameterProvider<Boolean> {
+ override val values = sequenceOf(true, false)
+ }
+}
+
+class MyTestComposableWithIntPreviewParams {
+
+ @Composable
+ fun TestContent() {
+ }
+
+ @Preview
+ @Composable
+ private fun TestContent(
+ @PreviewParameter(TestContentParameterProviderInt::class)
+ @Suppress("UNUSED_PARAMETER")
+ valueParameter: Int
+ ) {
+ }
+
+ private class TestContentParameterProviderInt : PreviewParameterProvider<Int> {
+ override val values = sequenceOf(42, 45, 92)
+ }
}
\ No newline at end of file
diff --git a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/ComposeViewAdapterTest.kt b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/ComposeViewAdapterTest.kt
index 22efa75..a8dfc85 100644
--- a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/ComposeViewAdapterTest.kt
+++ b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/ComposeViewAdapterTest.kt
@@ -542,6 +542,14 @@
}
@Test
+ fun PreviewParametersComposableTest() {
+ assertRendersCorrectly(
+ "androidx.compose.ui.tooling.SimpleComposablePreviewKt",
+ "PreviewParametersComposablePreview"
+ )
+ }
+
+ @Test
fun previewInClass() {
assertRendersCorrectly(
"androidx.compose.ui.tooling.TestGroup",
diff --git a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/SimpleComposablePreview.kt b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/SimpleComposablePreview.kt
index eabc75a..12bde52 100644
--- a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/SimpleComposablePreview.kt
+++ b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/SimpleComposablePreview.kt
@@ -29,6 +29,8 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
@@ -152,3 +154,17 @@
Text("Hello world")
}
}
+
+class TestContentParameterProviderBoolean : PreviewParameterProvider<Boolean> {
+ override val values: Sequence<Boolean>
+ get() = sequenceOf(false, true)
+}
+
+@Preview
+@Composable
+fun PreviewParametersComposablePreview(
+ @PreviewParameter(TestContentParameterProviderBoolean::class)
+ valueParameter: Boolean
+) {
+ Text(valueParameter.toString())
+}
diff --git a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/Utils.kt b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/Utils.kt
index 78d8fd0..9cb987b 100644
--- a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/Utils.kt
+++ b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/Utils.kt
@@ -84,9 +84,10 @@
content()
}
}
- this.runOnUiThread {
- val groups = slotTableRecord.store.map { it.asTree() }
- .flatMap { tree -> tree.findAll { it.location != null } }
+ this.runOnIdle {
+ val groups = slotTableRecord.store.map {
+ it.asTree()
+ }.flatMap { tree -> tree.findAll { true } }
search.addAnimations(groups)
additionalSearch?.addAnimations(groups)
}
diff --git a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/AnimationSearch.kt b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/AnimationSearch.kt
index 74f9023..268394b 100644
--- a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/AnimationSearch.kt
+++ b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/AnimationSearch.kt
@@ -40,7 +40,8 @@
private const val REMEMBER = "remember"
private const val REMEMBER_INFINITE_TRANSITION = "rememberInfiniteTransition"
private const val REMEMBER_UPDATED_STATE = "rememberUpdatedState"
-private const val SIZE_ANIMATION_MODIFIER = "androidx.compose.animation.SizeAnimationModifier"
+private const val SIZE_ANIMATION_MODIFIER =
+ "androidx.compose.animation.SizeAnimationModifierElement"
/** Find first data with type [T] within all remember calls. */
@OptIn(UiToolingDataApi::class)
@@ -136,8 +137,8 @@
// table as the one containing the `@Composable` being previewed, e.g. when they're
// defined using sub-composition.
slotTrees.forEach { tree ->
- val groupsWithLocation = tree.findAll { it.location != null }
- setToSearch.forEach { it.addAnimations(groupsWithLocation) }
+ val groups = tree.findAll { true }
+ setToSearch.forEach { it.addAnimations(groups) }
// Remove all AnimatedVisibility parent transitions from the transitions list,
// otherwise we'd duplicate them in the Android Studio Animation Preview because we
// will track them separately.
@@ -158,7 +159,7 @@
/** Search for animations with type [T]. */
open class Search<T : Any>(private val trackAnimation: (T) -> Unit) {
val animations = mutableSetOf<T>()
- open fun addAnimations(groupsWithLocation: Collection<Group>) {}
+ open fun addAnimations(groups: Collection<Group>) {}
fun hasAnimations() = animations.isNotEmpty()
fun track() {
// Animations are found in reversed order in the tree,
@@ -172,7 +173,8 @@
private val clazz: KClass<T>,
trackAnimation: (T) -> Unit
) : Search<T>(trackAnimation) {
- override fun addAnimations(groupsWithLocation: Collection<Group>) {
+ override fun addAnimations(groups: Collection<Group>) {
+ val groupsWithLocation = groups.filter { it.location != null }
animations.addAll(groupsWithLocation.findRememberCallWithType(clazz).toSet())
}
@@ -199,7 +201,8 @@
class InfiniteTransitionSearch(trackAnimation: (InfiniteTransitionSearchInfo) -> Unit) :
Search<InfiniteTransitionSearchInfo>(trackAnimation) {
- override fun addAnimations(groupsWithLocation: Collection<Group>) {
+ override fun addAnimations(groups: Collection<Group>) {
+ val groupsWithLocation = groups.filter { it.location != null }
animations.addAll(findAnimations(groupsWithLocation))
}
@@ -234,7 +237,8 @@
/** Search for animateXAsState() and animateValueAsState() animations. */
class AnimateXAsStateSearch(trackAnimation: (AnimateXAsStateSearchInfo<*, *>) -> Unit) :
Search<AnimateXAsStateSearchInfo<*, *>>(trackAnimation) {
- override fun addAnimations(groupsWithLocation: Collection<Group>) {
+ override fun addAnimations(groups: Collection<Group>) {
+ val groupsWithLocation = groups.filter { it.location != null }
animations.addAll(findAnimations<Any?>(groupsWithLocation))
}
@@ -288,22 +292,31 @@
/** Search for animateContentSize() animations. */
class AnimateContentSizeSearch(trackAnimation: (Any) -> Unit) :
Search<Any>(trackAnimation) {
- override fun addAnimations(groupsWithLocation: Collection<Group>) {
- animations.addAll(groupsWithLocation.filter { call -> call.name == REMEMBER }
- .mapNotNull {
- // SizeAnimationModifier is currently private.
- it.data.firstOrNull { data ->
- data?.javaClass?.name == SIZE_ANIMATION_MODIFIER
+ // It's important not to pre-filter the groups by location, as there's no guarantee
+ // that the group containing the modifierInfo we are looking for has a non-null location.
+ override fun addAnimations(groups: Collection<Group>) {
+ groups.filter {
+ it.modifierInfo.isNotEmpty()
+ }.forEach { group ->
+ group.modifierInfo.forEach {
+ it.modifier.any { mod ->
+ if (mod.javaClass.name == SIZE_ANIMATION_MODIFIER) {
+ animations.add(mod)
+ true
+ } else
+ false
}
- }.toSet())
+ }
+ }
}
}
/** Search for updateTransition() animations. */
class TransitionSearch(trackAnimation: (Transition<*>) -> Unit) :
Search<Transition<*>>(trackAnimation) {
- override fun addAnimations(groupsWithLocation: Collection<Group>) {
+ override fun addAnimations(groups: Collection<Group>) {
// Find `updateTransition` calls.
+ val groupsWithLocation = groups.filter { it.location != null }
animations.addAll(groupsWithLocation.filter {
it.name == UPDATE_TRANSITION
}.findRememberedData())
@@ -313,9 +326,10 @@
/** Search for AnimatedVisibility animations. */
class AnimatedVisibilitySearch(trackAnimation: (Transition<*>) -> Unit) :
Search<Transition<*>>(trackAnimation) {
- override fun addAnimations(groupsWithLocation: Collection<Group>) {
+ override fun addAnimations(groups: Collection<Group>) {
// Find `AnimatedVisibility` calls.
// Then, find the underlying `updateTransition` it uses.
+ val groupsWithLocation = groups.filter { it.location != null }
animations.addAll(groupsWithLocation.filter { it.name == ANIMATED_VISIBILITY }
.mapNotNull {
it.children.firstOrNull { updateTransitionCall ->
@@ -328,7 +342,8 @@
/** Search for AnimatedContent animations. */
class AnimatedContentSearch(trackAnimation: (Transition<*>) -> Unit) :
Search<Transition<*>>(trackAnimation) {
- override fun addAnimations(groupsWithLocation: Collection<Group>) {
+ override fun addAnimations(groups: Collection<Group>) {
+ val groupsWithLocation = groups.filter { it.location != null }
animations.addAll(groupsWithLocation.filter { it.name == ANIMATED_CONTENT }
.mapNotNull {
it.children.firstOrNull { updateTransitionCall ->
diff --git a/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt b/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt
index 24f2f87..0d93c86 100644
--- a/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt
+++ b/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt
@@ -38,13 +38,29 @@
actualTypes: Array<Class<*>>
): Boolean =
methodTypes.size == actualTypes.size &&
- methodTypes.mapIndexed { index, clazz -> clazz.isAssignableFrom(actualTypes[index]) }
+ methodTypes.mapIndexed { index, clazz ->
+ val actualType = actualTypes[index]
+ if (clazz.isPrimitive || actualType.isPrimitive) {
+ // We can't use [isAssignableFrom] if we have java primitives.
+ // Java primitives aren't equal to Java classes:
+ // comparing int with kotlin.Int or java.lang.Integer will return false.
+ // However, if we convert them both to a KClass they can be compared:
+ // int and java.lang.Integer will be both converted to Int
+ // see more: https://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class)
+ clazz.kotlin == actualType.kotlin
+ } else {
+ clazz.isAssignableFrom(actualType)
+ }
+ }
.all { it }
/**
* Same as [Class#getDeclaredMethod] but it accounts for compatible types so the signature does
* not need to exactly match. This allows finding method calls that use subclasses as parameters
* instead of the exact types.
+ *
+ * @return the compatible [Method] with the name [methodName]
+ * @throws NoSuchMethodException if the method is not found
*/
private fun Class<*>.getDeclaredCompatibleMethod(
methodName: String,
@@ -66,9 +82,11 @@
/**
* Find the given method by name. If the method has parameters, this function will try to find
* the version that accepts default parameters.
+ *
+ * @return null if the composable method is not found. Returns the [Method] otherwise.
*/
- private fun Class<*>.findComposableMethod(methodName: String, vararg args: Any?): Method {
- val method = try {
+ private fun Class<*>.findComposableMethod(methodName: String, vararg args: Any?): Method? {
+ return try {
// without defaults
val changedParams = changedParamCount(args.size, 0)
getDeclaredCompatibleMethod(
@@ -88,9 +106,7 @@
} catch (e: ReflectiveOperationException) {
null
}
- } ?: throw NoSuchMethodException("$name.$methodName")
-
- return method
+ }
}
/**
@@ -196,6 +212,7 @@
val composableClass = Class.forName(className)
val method = composableClass.findComposableMethod(methodName, *args)
+ ?: throw NoSuchMethodException("Composable $className.$methodName not found")
method.isAccessible = true
if (Modifier.isStatic(method.modifiers)) {
@@ -207,10 +224,8 @@
val instance = composableClass.getConstructor().newInstance()
method.invokeComposableMethod(instance, composer, *args)
}
- } catch (e: ReflectiveOperationException) {
- PreviewLogger.logWarning(
- "Failed to invoke Composable Method '$className.$methodName'"
- )
+ } catch (e: Exception) {
+ PreviewLogger.logWarning("Failed to invoke Composable Method '$className.$methodName'")
throw e
}
}
diff --git a/compose/ui/ui-util/src/test/kotlin/androidx/compose/ui/util/InlineClassHelperTest.kt b/compose/ui/ui-util/src/test/kotlin/androidx/compose/ui/util/InlineClassHelperTest.kt
index 9cf3ad6..7f52124 100644
--- a/compose/ui/ui-util/src/test/kotlin/androidx/compose/ui/util/InlineClassHelperTest.kt
+++ b/compose/ui/ui-util/src/test/kotlin/androidx/compose/ui/util/InlineClassHelperTest.kt
@@ -34,6 +34,33 @@
}
@Test
+ fun packAndUnpackNegativeAndPositiveFloats() {
+ val first = -50f
+ val second = 100f
+ val packed = packFloats(first, second)
+ assertEquals(first, unpackFloat1(packed))
+ assertEquals(second, unpackFloat2(packed))
+ }
+
+ @Test
+ fun packAndUnpackPositiveAndNegativeFloats() {
+ val first = 50f
+ val second = -100f
+ val packed = packFloats(first, second)
+ assertEquals(first, unpackFloat1(packed))
+ assertEquals(second, unpackFloat2(packed))
+ }
+
+ @Test
+ fun packAndUnpackNegativeFloats() {
+ val first = -50f
+ val second = -100f
+ val packed = packFloats(first, second)
+ assertEquals(first, unpackFloat1(packed))
+ assertEquals(second, unpackFloat2(packed))
+ }
+
+ @Test
fun packAndUnpackInts() {
val first = Int.MAX_VALUE
val second = Int.MIN_VALUE
@@ -41,4 +68,31 @@
assertEquals(first, unpackInt1(packed))
assertEquals(second, unpackInt2(packed))
}
+
+ @Test
+ fun packAndUnpackNegativeAndPositiveInts() {
+ val first = -50
+ val second = 100
+ val packed = packInts(first, second)
+ assertEquals(first, unpackInt1(packed))
+ assertEquals(second, unpackInt2(packed))
+ }
+
+ @Test
+ fun packAndUnpackPositiveAndNegativeInts() {
+ val first = 50
+ val second = -100
+ val packed = packInts(first, second)
+ assertEquals(first, unpackInt1(packed))
+ assertEquals(second, unpackInt2(packed))
+ }
+
+ @Test
+ fun packAndUnpackNegativeInts() {
+ val first = -50
+ val second = -100
+ val packed = packInts(first, second)
+ assertEquals(first, unpackInt1(packed))
+ assertEquals(second, unpackInt2(packed))
+ }
}
\ No newline at end of file
diff --git a/compose/ui/ui/api/1.5.0-beta01.txt b/compose/ui/ui/api/1.5.0-beta01.txt
index 434d4ce..ad58ecf 100644
--- a/compose/ui/ui/api/1.5.0-beta01.txt
+++ b/compose/ui/ui/api/1.5.0-beta01.txt
@@ -2405,9 +2405,6 @@
method public boolean retainAll(kotlin.jvm.functions.Function1<java.lang.Object,java.lang.Boolean> predicate);
}
- public final class TestModifierUpdaterKt {
- }
-
public final class VerticalAlignmentLine extends androidx.compose.ui.layout.AlignmentLine {
ctor public VerticalAlignmentLine(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,java.lang.Integer> merger);
}
diff --git a/compose/ui/ui/api/current.ignore b/compose/ui/ui/api/current.ignore
index 7c34c25..a07538b 100644
--- a/compose/ui/ui/api/current.ignore
+++ b/compose/ui/ui/api/current.ignore
@@ -1,37 +1,21 @@
// Baseline format: 1.0
-BecameUnchecked: Field NestedScrollSource.Companion.Relocate:
- Removed Field NestedScrollSource.Companion.Relocate from compatibility checked API surface
-BecameUnchecked: androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion#getRelocate():
- Removed method androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion.getRelocate() from compatibility checked API surface
+ChangedType: androidx.compose.ui.draw.DrawModifierKt#CacheDrawModifierNode(kotlin.jvm.functions.Function1<? super androidx.compose.ui.draw.CacheDrawScope,androidx.compose.ui.draw.DrawResult>):
+ Method androidx.compose.ui.draw.DrawModifierKt.CacheDrawModifierNode has changed return type from androidx.compose.ui.node.CacheDrawModifierNode to androidx.compose.ui.draw.CacheDrawModifierNode
-InvalidNullConversion: androidx.compose.ui.CombinedModifier#foldIn(R, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.CombinedModifier.foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.CombinedModifier#foldOut(R, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.CombinedModifier.foldOut(R initial, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier#foldIn(R, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier#foldOut(R, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.foldOut(R initial, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier.Companion#foldIn(R, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.Companion.foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier.Companion#foldOut(R, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.Companion.foldOut(R initial, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier.Element#foldIn(R, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.Element.foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier.Element#foldOut(R, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.Element.foldOut(R initial, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.graphics.vector.VectorConfig#getOrDefault(androidx.compose.ui.graphics.vector.VectorProperty<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter defaultValue in androidx.compose.ui.graphics.vector.VectorConfig.getOrDefault(androidx.compose.ui.graphics.vector.VectorProperty<T> property, T defaultValue)
-InvalidNullConversion: androidx.compose.ui.semantics.SemanticsConfiguration#set(androidx.compose.ui.semantics.SemanticsPropertyKey<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.ui.semantics.SemanticsConfiguration.set(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T value)
-InvalidNullConversion: androidx.compose.ui.semantics.SemanticsPropertyKey#merge(T, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter childValue in androidx.compose.ui.semantics.SemanticsPropertyKey.merge(T parentValue, T childValue)
-InvalidNullConversion: androidx.compose.ui.semantics.SemanticsPropertyKey#setValue(androidx.compose.ui.semantics.SemanticsPropertyReceiver, kotlin.reflect.KProperty<?>, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.ui.semantics.SemanticsPropertyKey.setValue(androidx.compose.ui.semantics.SemanticsPropertyReceiver thisRef, kotlin.reflect.KProperty<?> property, T value)
-InvalidNullConversion: androidx.compose.ui.semantics.SemanticsPropertyReceiver#set(androidx.compose.ui.semantics.SemanticsPropertyKey<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.ui.semantics.SemanticsPropertyReceiver.set(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T value)
+RemovedClass: androidx.compose.ui.focus.FocusTargetNode:
+ Removed class androidx.compose.ui.focus.FocusTargetNode
+RemovedClass: androidx.compose.ui.layout.RelocationModifierKt:
+ Removed class androidx.compose.ui.layout.RelocationModifierKt
+RemovedClass: androidx.compose.ui.layout.RelocationRequesterModifierKt:
+ Removed class androidx.compose.ui.layout.RelocationRequesterModifierKt
-RemovedClass: androidx.compose.ui.platform.AndroidComposeView_androidKt:
- Removed class androidx.compose.ui.platform.AndroidComposeView_androidKt
+RemovedInterface: androidx.compose.ui.node.CacheDrawModifierNode:
+ Removed class androidx.compose.ui.node.CacheDrawModifierNode
+
+
+RemovedMethod: androidx.compose.ui.semantics.SemanticsActions#getPerformImeAction():
+ Removed method androidx.compose.ui.semantics.SemanticsActions.getPerformImeAction()
+RemovedMethod: androidx.compose.ui.semantics.SemanticsPropertiesKt#performImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int, String, kotlin.jvm.functions.Function0<java.lang.Boolean>):
+ Removed method androidx.compose.ui.semantics.SemanticsPropertiesKt.performImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver,int,String,kotlin.jvm.functions.Function0<java.lang.Boolean>)
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index 434d4ce..121b23d 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -291,6 +291,10 @@
property public abstract long size;
}
+ public sealed interface CacheDrawModifierNode extends androidx.compose.ui.node.DrawModifierNode {
+ method public void invalidateDrawCache();
+ }
+
public final class CacheDrawScope implements androidx.compose.ui.unit.Density {
method public float getDensity();
method public float getFontScale();
@@ -318,7 +322,7 @@
}
public final class DrawModifierKt {
- method public static androidx.compose.ui.node.CacheDrawModifierNode CacheDrawModifierNode(kotlin.jvm.functions.Function1<? super androidx.compose.ui.draw.CacheDrawScope,androidx.compose.ui.draw.DrawResult> onBuildDrawCache);
+ method public static androidx.compose.ui.draw.CacheDrawModifierNode CacheDrawModifierNode(kotlin.jvm.functions.Function1<? super androidx.compose.ui.draw.CacheDrawScope,androidx.compose.ui.draw.DrawResult> onBuildDrawCache);
method public static androidx.compose.ui.Modifier drawBehind(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> onDraw);
method public static androidx.compose.ui.Modifier drawWithCache(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.draw.CacheDrawScope,androidx.compose.ui.draw.DrawResult> onBuildDrawCache);
method public static androidx.compose.ui.Modifier drawWithContent(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.ContentDrawScope,kotlin.Unit> onDraw);
@@ -551,11 +555,13 @@
property public abstract boolean isFocused;
}
- public final class FocusTargetNode extends androidx.compose.ui.Modifier.Node implements androidx.compose.ui.modifier.ModifierLocalModifierNode androidx.compose.ui.node.ObserverModifierNode {
- ctor public FocusTargetNode();
+ public sealed interface FocusTargetModifierNode extends androidx.compose.ui.node.DelegatableNode {
method public androidx.compose.ui.focus.FocusState getFocusState();
- method public void onObservedReadsChanged();
- property public final androidx.compose.ui.focus.FocusState focusState;
+ property public abstract androidx.compose.ui.focus.FocusState focusState;
+ }
+
+ public final class FocusTargetModifierNodeKt {
+ method public static androidx.compose.ui.focus.FocusTargetModifierNode FocusTargetModifierNode();
}
}
@@ -1628,9 +1634,11 @@
method public int getDrag();
method public int getFling();
method @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public int getRelocate();
+ method public int getWheel();
property public final int Drag;
property public final int Fling;
property @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public final int Relocate;
+ property public final int Wheel;
}
}
@@ -2068,8 +2076,8 @@
public interface IntrinsicMeasureScope extends androidx.compose.ui.unit.Density {
method public androidx.compose.ui.unit.LayoutDirection getLayoutDirection();
- method @androidx.compose.ui.ExperimentalComposeUiApi public default boolean isLookingAhead();
- property @androidx.compose.ui.ExperimentalComposeUiApi public default boolean isLookingAhead;
+ method public default boolean isLookingAhead();
+ property public default boolean isLookingAhead;
property public abstract androidx.compose.ui.unit.LayoutDirection layoutDirection;
}
@@ -2311,24 +2319,6 @@
property protected abstract int parentWidth;
}
- @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi @kotlin.jvm.JvmDefaultWithCompatibility public interface RelocationModifier extends androidx.compose.ui.Modifier.Element {
- method @Deprecated public androidx.compose.ui.geometry.Rect computeDestination(androidx.compose.ui.geometry.Rect source, androidx.compose.ui.layout.LayoutCoordinates layoutCoordinates);
- method @Deprecated public suspend Object? performRelocation(androidx.compose.ui.geometry.Rect source, androidx.compose.ui.geometry.Rect destination, kotlin.coroutines.Continuation<? super kotlin.Unit>);
- }
-
- public final class RelocationModifierKt {
- method @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier onRelocationRequest(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function2<? super androidx.compose.ui.geometry.Rect,? super androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Rect> onProvideDestination, kotlin.jvm.functions.Function3<? super androidx.compose.ui.geometry.Rect,? super androidx.compose.ui.geometry.Rect,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onPerformRelocation);
- }
-
- @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public final class RelocationRequester {
- ctor @Deprecated public RelocationRequester();
- method @Deprecated public suspend Object? bringIntoView(optional androidx.compose.ui.geometry.Rect? rect, optional kotlin.coroutines.Continuation<? super kotlin.Unit>);
- }
-
- public final class RelocationRequesterModifierKt {
- method @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier relocationRequester(androidx.compose.ui.Modifier, Object relocationRequester);
- }
-
public interface Remeasurement {
method public void forceRemeasure();
}
@@ -2405,9 +2395,6 @@
method public boolean retainAll(kotlin.jvm.functions.Function1<java.lang.Object,java.lang.Boolean> predicate);
}
- public final class TestModifierUpdaterKt {
- }
-
public final class VerticalAlignmentLine extends androidx.compose.ui.layout.AlignmentLine {
ctor public VerticalAlignmentLine(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,java.lang.Integer> merger);
}
@@ -2472,10 +2459,6 @@
package androidx.compose.ui.node {
- public interface CacheDrawModifierNode extends androidx.compose.ui.node.DrawModifierNode {
- method public void invalidateDrawCache();
- }
-
public interface CompositionLocalConsumerModifierNode extends androidx.compose.ui.node.DelegatableNode {
}
@@ -2717,7 +2700,7 @@
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.hapticfeedback.HapticFeedback> getLocalHapticFeedback();
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.input.InputModeManager> getLocalInputModeManager();
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.LayoutDirection> getLocalLayoutDirection();
- method @androidx.compose.ui.text.ExperimentalTextApi public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.PlatformTextInputPluginRegistry> getLocalPlatformTextInputPluginRegistry();
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.PlatformTextInputPluginRegistry> getLocalPlatformTextInputPluginRegistry();
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.TextInputService> getLocalTextInputService();
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.TextToolbar> getLocalTextToolbar();
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.UriHandler> getLocalUriHandler();
@@ -2733,7 +2716,7 @@
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.hapticfeedback.HapticFeedback> LocalHapticFeedback;
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.input.InputModeManager> LocalInputModeManager;
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.LayoutDirection> LocalLayoutDirection;
- property @androidx.compose.ui.text.ExperimentalTextApi public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.PlatformTextInputPluginRegistry> LocalPlatformTextInputPluginRegistry;
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.PlatformTextInputPluginRegistry> LocalPlatformTextInputPluginRegistry;
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.TextInputService> LocalTextInputService;
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.TextToolbar> LocalTextToolbar;
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.UriHandler> LocalUriHandler;
@@ -2987,6 +2970,10 @@
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static int integerResource(@IntegerRes int id);
}
+ public final class ResourceResolutionException extends java.lang.RuntimeException {
+ ctor public ResourceResolutionException(String message, Throwable cause);
+ }
+
public final class StringResources_androidKt {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String pluralStringResource(@PluralsRes int id, int count);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String pluralStringResource(@PluralsRes int id, int count, java.lang.Object... formatArgs);
@@ -3099,6 +3086,7 @@
}
public final class SemanticsActions {
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getClearTextSubstitution();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getCollapse();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getCopyText();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction>> getCustomActions();
@@ -3108,19 +3096,22 @@
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.util.List<androidx.compose.ui.text.TextLayoutResult>,java.lang.Boolean>>> getGetTextLayoutResult();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> getInsertTextAtCursor();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getOnClick();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getOnImeAction();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getOnLongClick();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPageDown();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPageLeft();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPageRight();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPageUp();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPasteText();
- method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPerformImeAction();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getRequestFocus();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function2<java.lang.Float,java.lang.Float,java.lang.Boolean>>> getScrollBy();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Integer,java.lang.Boolean>>> getScrollToIndex();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Boolean>>> getSetProgress();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function3<java.lang.Integer,java.lang.Integer,java.lang.Boolean,java.lang.Boolean>>> getSetSelection();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> getSetText();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> getSetTextSubstitution();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Boolean,java.lang.Boolean>>> getShowTextSubstitution();
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> ClearTextSubstitution;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> Collapse;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> CopyText;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction>> CustomActions;
@@ -3130,19 +3121,21 @@
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.util.List<androidx.compose.ui.text.TextLayoutResult>,java.lang.Boolean>>> GetTextLayoutResult;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> InsertTextAtCursor;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> OnClick;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> OnImeAction;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> OnLongClick;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PageDown;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PageLeft;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PageRight;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PageUp;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PasteText;
- property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PerformImeAction;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> RequestFocus;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function2<java.lang.Float,java.lang.Float,java.lang.Boolean>>> ScrollBy;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Integer,java.lang.Boolean>>> ScrollToIndex;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Boolean>>> SetProgress;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function3<java.lang.Integer,java.lang.Integer,java.lang.Boolean,java.lang.Boolean>>> SetSelection;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> SetText;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> SetTextSubstitution;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Boolean,java.lang.Boolean>>> ShowTextSubstitution;
field public static final androidx.compose.ui.semantics.SemanticsActions INSTANCE;
}
@@ -3238,8 +3231,10 @@
method @Deprecated public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getIsContainer();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsDialog();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsPopup();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getIsShowingTextSubstitution();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getIsTraversalGroup();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.LiveRegionMode> getLiveRegion();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> getOriginalText();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> getPaneTitle();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getPassword();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.ProgressBarRangeInfo> getProgressBarRangeInfo();
@@ -3268,8 +3263,10 @@
property @Deprecated public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> IsContainer;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsDialog;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsPopup;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> IsShowingTextSubstitution;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> IsTraversalGroup;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.LiveRegionMode> LiveRegion;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> OriginalText;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> PaneTitle;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Password;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.ProgressBarRangeInfo> ProgressBarRangeInfo;
@@ -3293,6 +3290,7 @@
}
public final class SemanticsPropertiesKt {
+ method public static void clearTextSubstitution(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void collapse(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void copyText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void cutText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
@@ -3310,6 +3308,7 @@
method public static androidx.compose.ui.semantics.ScrollAxisRange getHorizontalScrollAxisRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method @Deprecated public static int getImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static int getLiveRegion(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static androidx.compose.ui.text.AnnotatedString getOriginalText(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static String getPaneTitle(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static androidx.compose.ui.semantics.ProgressBarRangeInfo getProgressBarRangeInfo(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static int getRole(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
@@ -3327,8 +3326,10 @@
method public static void insertTextAtCursor(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>? action);
method @androidx.compose.ui.ExperimentalComposeUiApi public static void invisibleToUser(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method @Deprecated public static boolean isContainer(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static boolean isShowingTextSubstitution(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static boolean isTraversalGroup(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void onClick(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
+ method public static void onImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int imeActionType, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void onLongClick(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void pageDown(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void pageLeft(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
@@ -3336,7 +3337,6 @@
method public static void pageUp(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void password(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void pasteText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
- method public static void performImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int imeActionType, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void popup(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void requestFocus(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void scrollBy(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function2<? super java.lang.Float,? super java.lang.Float,java.lang.Boolean>? action);
@@ -3352,21 +3352,25 @@
method public static void setHorizontalScrollAxisRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.ScrollAxisRange);
method @Deprecated public static void setImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int);
method public static void setLiveRegion(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int);
+ method public static void setOriginalText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.AnnotatedString);
method public static void setPaneTitle(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String);
method public static void setProgress(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Boolean>? action);
method public static void setProgressBarRangeInfo(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.ProgressBarRangeInfo);
method public static void setRole(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int);
method public static void setSelected(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean);
method public static void setSelection(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Boolean,java.lang.Boolean>? action);
+ method public static void setShowingTextSubstitution(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean);
method public static void setStateDescription(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String);
method public static void setTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String);
method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.AnnotatedString);
method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>? action);
method public static void setTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, long);
+ method public static void setTextSubstitution(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>? action);
method public static void setToggleableState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.state.ToggleableState);
method public static void setTraversalGroup(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean);
method public static void setTraversalIndex(androidx.compose.ui.semantics.SemanticsPropertyReceiver, float);
method public static void setVerticalScrollAxisRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.ScrollAxisRange);
+ method public static void showTextSubstitution(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function1<? super java.lang.Boolean,java.lang.Boolean>? action);
}
public final class SemanticsProperties_androidKt {
diff --git a/compose/ui/ui/api/restricted_1.5.0-beta01.txt b/compose/ui/ui/api/restricted_1.5.0-beta01.txt
index f9c6abc..d24ac94 100644
--- a/compose/ui/ui/api/restricted_1.5.0-beta01.txt
+++ b/compose/ui/ui/api/restricted_1.5.0-beta01.txt
@@ -2412,9 +2412,6 @@
method public boolean retainAll(kotlin.jvm.functions.Function1<java.lang.Object,java.lang.Boolean> predicate);
}
- public final class TestModifierUpdaterKt {
- }
-
public final class VerticalAlignmentLine extends androidx.compose.ui.layout.AlignmentLine {
ctor public VerticalAlignmentLine(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,java.lang.Integer> merger);
}
diff --git a/compose/ui/ui/api/restricted_current.ignore b/compose/ui/ui/api/restricted_current.ignore
index 7c34c25..a07538b 100644
--- a/compose/ui/ui/api/restricted_current.ignore
+++ b/compose/ui/ui/api/restricted_current.ignore
@@ -1,37 +1,21 @@
// Baseline format: 1.0
-BecameUnchecked: Field NestedScrollSource.Companion.Relocate:
- Removed Field NestedScrollSource.Companion.Relocate from compatibility checked API surface
-BecameUnchecked: androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion#getRelocate():
- Removed method androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion.getRelocate() from compatibility checked API surface
+ChangedType: androidx.compose.ui.draw.DrawModifierKt#CacheDrawModifierNode(kotlin.jvm.functions.Function1<? super androidx.compose.ui.draw.CacheDrawScope,androidx.compose.ui.draw.DrawResult>):
+ Method androidx.compose.ui.draw.DrawModifierKt.CacheDrawModifierNode has changed return type from androidx.compose.ui.node.CacheDrawModifierNode to androidx.compose.ui.draw.CacheDrawModifierNode
-InvalidNullConversion: androidx.compose.ui.CombinedModifier#foldIn(R, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.CombinedModifier.foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.CombinedModifier#foldOut(R, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.CombinedModifier.foldOut(R initial, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier#foldIn(R, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier#foldOut(R, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.foldOut(R initial, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier.Companion#foldIn(R, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.Companion.foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier.Companion#foldOut(R, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.Companion.foldOut(R initial, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier.Element#foldIn(R, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.Element.foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.compose.ui.Modifier.Element,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.Modifier.Element#foldOut(R, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R>) parameter #0:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter initial in androidx.compose.ui.Modifier.Element.foldOut(R initial, kotlin.jvm.functions.Function2<? super androidx.compose.ui.Modifier.Element,? super R,? extends R> operation)
-InvalidNullConversion: androidx.compose.ui.graphics.vector.VectorConfig#getOrDefault(androidx.compose.ui.graphics.vector.VectorProperty<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter defaultValue in androidx.compose.ui.graphics.vector.VectorConfig.getOrDefault(androidx.compose.ui.graphics.vector.VectorProperty<T> property, T defaultValue)
-InvalidNullConversion: androidx.compose.ui.semantics.SemanticsConfiguration#set(androidx.compose.ui.semantics.SemanticsPropertyKey<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.ui.semantics.SemanticsConfiguration.set(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T value)
-InvalidNullConversion: androidx.compose.ui.semantics.SemanticsPropertyKey#merge(T, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter childValue in androidx.compose.ui.semantics.SemanticsPropertyKey.merge(T parentValue, T childValue)
-InvalidNullConversion: androidx.compose.ui.semantics.SemanticsPropertyKey#setValue(androidx.compose.ui.semantics.SemanticsPropertyReceiver, kotlin.reflect.KProperty<?>, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.ui.semantics.SemanticsPropertyKey.setValue(androidx.compose.ui.semantics.SemanticsPropertyReceiver thisRef, kotlin.reflect.KProperty<?> property, T value)
-InvalidNullConversion: androidx.compose.ui.semantics.SemanticsPropertyReceiver#set(androidx.compose.ui.semantics.SemanticsPropertyKey<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.compose.ui.semantics.SemanticsPropertyReceiver.set(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T value)
+RemovedClass: androidx.compose.ui.focus.FocusTargetNode:
+ Removed class androidx.compose.ui.focus.FocusTargetNode
+RemovedClass: androidx.compose.ui.layout.RelocationModifierKt:
+ Removed class androidx.compose.ui.layout.RelocationModifierKt
+RemovedClass: androidx.compose.ui.layout.RelocationRequesterModifierKt:
+ Removed class androidx.compose.ui.layout.RelocationRequesterModifierKt
-RemovedClass: androidx.compose.ui.platform.AndroidComposeView_androidKt:
- Removed class androidx.compose.ui.platform.AndroidComposeView_androidKt
+RemovedInterface: androidx.compose.ui.node.CacheDrawModifierNode:
+ Removed class androidx.compose.ui.node.CacheDrawModifierNode
+
+
+RemovedMethod: androidx.compose.ui.semantics.SemanticsActions#getPerformImeAction():
+ Removed method androidx.compose.ui.semantics.SemanticsActions.getPerformImeAction()
+RemovedMethod: androidx.compose.ui.semantics.SemanticsPropertiesKt#performImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int, String, kotlin.jvm.functions.Function0<java.lang.Boolean>):
+ Removed method androidx.compose.ui.semantics.SemanticsPropertiesKt.performImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver,int,String,kotlin.jvm.functions.Function0<java.lang.Boolean>)
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index f9c6abc..b3e4a7c 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -291,6 +291,10 @@
property public abstract long size;
}
+ public sealed interface CacheDrawModifierNode extends androidx.compose.ui.node.DrawModifierNode {
+ method public void invalidateDrawCache();
+ }
+
public final class CacheDrawScope implements androidx.compose.ui.unit.Density {
method public float getDensity();
method public float getFontScale();
@@ -318,7 +322,7 @@
}
public final class DrawModifierKt {
- method public static androidx.compose.ui.node.CacheDrawModifierNode CacheDrawModifierNode(kotlin.jvm.functions.Function1<? super androidx.compose.ui.draw.CacheDrawScope,androidx.compose.ui.draw.DrawResult> onBuildDrawCache);
+ method public static androidx.compose.ui.draw.CacheDrawModifierNode CacheDrawModifierNode(kotlin.jvm.functions.Function1<? super androidx.compose.ui.draw.CacheDrawScope,androidx.compose.ui.draw.DrawResult> onBuildDrawCache);
method public static androidx.compose.ui.Modifier drawBehind(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> onDraw);
method public static androidx.compose.ui.Modifier drawWithCache(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.draw.CacheDrawScope,androidx.compose.ui.draw.DrawResult> onBuildDrawCache);
method public static androidx.compose.ui.Modifier drawWithContent(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.ContentDrawScope,kotlin.Unit> onDraw);
@@ -551,11 +555,13 @@
property public abstract boolean isFocused;
}
- public final class FocusTargetNode extends androidx.compose.ui.Modifier.Node implements androidx.compose.ui.modifier.ModifierLocalModifierNode androidx.compose.ui.node.ObserverModifierNode {
- ctor public FocusTargetNode();
+ public sealed interface FocusTargetModifierNode extends androidx.compose.ui.node.DelegatableNode {
method public androidx.compose.ui.focus.FocusState getFocusState();
- method public void onObservedReadsChanged();
- property public final androidx.compose.ui.focus.FocusState focusState;
+ property public abstract androidx.compose.ui.focus.FocusState focusState;
+ }
+
+ public final class FocusTargetModifierNodeKt {
+ method public static androidx.compose.ui.focus.FocusTargetModifierNode FocusTargetModifierNode();
}
}
@@ -1628,9 +1634,11 @@
method public int getDrag();
method public int getFling();
method @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public int getRelocate();
+ method public int getWheel();
property public final int Drag;
property public final int Fling;
property @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public final int Relocate;
+ property public final int Wheel;
}
}
@@ -2068,8 +2076,8 @@
public interface IntrinsicMeasureScope extends androidx.compose.ui.unit.Density {
method public androidx.compose.ui.unit.LayoutDirection getLayoutDirection();
- method @androidx.compose.ui.ExperimentalComposeUiApi public default boolean isLookingAhead();
- property @androidx.compose.ui.ExperimentalComposeUiApi public default boolean isLookingAhead;
+ method public default boolean isLookingAhead();
+ property public default boolean isLookingAhead;
property public abstract androidx.compose.ui.unit.LayoutDirection layoutDirection;
}
@@ -2318,24 +2326,6 @@
property protected abstract int parentWidth;
}
- @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi @kotlin.jvm.JvmDefaultWithCompatibility public interface RelocationModifier extends androidx.compose.ui.Modifier.Element {
- method @Deprecated public androidx.compose.ui.geometry.Rect computeDestination(androidx.compose.ui.geometry.Rect source, androidx.compose.ui.layout.LayoutCoordinates layoutCoordinates);
- method @Deprecated public suspend Object? performRelocation(androidx.compose.ui.geometry.Rect source, androidx.compose.ui.geometry.Rect destination, kotlin.coroutines.Continuation<? super kotlin.Unit>);
- }
-
- public final class RelocationModifierKt {
- method @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier onRelocationRequest(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function2<? super androidx.compose.ui.geometry.Rect,? super androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Rect> onProvideDestination, kotlin.jvm.functions.Function3<? super androidx.compose.ui.geometry.Rect,? super androidx.compose.ui.geometry.Rect,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onPerformRelocation);
- }
-
- @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public final class RelocationRequester {
- ctor @Deprecated public RelocationRequester();
- method @Deprecated public suspend Object? bringIntoView(optional androidx.compose.ui.geometry.Rect? rect, optional kotlin.coroutines.Continuation<? super kotlin.Unit>);
- }
-
- public final class RelocationRequesterModifierKt {
- method @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier relocationRequester(androidx.compose.ui.Modifier, Object relocationRequester);
- }
-
public interface Remeasurement {
method public void forceRemeasure();
}
@@ -2412,9 +2402,6 @@
method public boolean retainAll(kotlin.jvm.functions.Function1<java.lang.Object,java.lang.Boolean> predicate);
}
- public final class TestModifierUpdaterKt {
- }
-
public final class VerticalAlignmentLine extends androidx.compose.ui.layout.AlignmentLine {
ctor public VerticalAlignmentLine(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,java.lang.Integer> merger);
}
@@ -2479,23 +2466,22 @@
package androidx.compose.ui.node {
- public interface CacheDrawModifierNode extends androidx.compose.ui.node.DrawModifierNode {
- method public void invalidateDrawCache();
- }
-
@kotlin.PublishedApi internal interface ComposeUiNode {
+ method public int getCompositeKeyHash();
method public androidx.compose.runtime.CompositionLocalMap getCompositionLocalMap();
method public androidx.compose.ui.unit.Density getDensity();
method public androidx.compose.ui.unit.LayoutDirection getLayoutDirection();
method public androidx.compose.ui.layout.MeasurePolicy getMeasurePolicy();
method public androidx.compose.ui.Modifier getModifier();
method public androidx.compose.ui.platform.ViewConfiguration getViewConfiguration();
+ method public void setCompositeKeyHash(int);
method public void setCompositionLocalMap(androidx.compose.runtime.CompositionLocalMap);
method public void setDensity(androidx.compose.ui.unit.Density);
method public void setLayoutDirection(androidx.compose.ui.unit.LayoutDirection);
method public void setMeasurePolicy(androidx.compose.ui.layout.MeasurePolicy);
method public void setModifier(androidx.compose.ui.Modifier);
method public void setViewConfiguration(androidx.compose.ui.platform.ViewConfiguration);
+ property public abstract int compositeKeyHash;
property public abstract androidx.compose.runtime.CompositionLocalMap compositionLocalMap;
property public abstract androidx.compose.ui.unit.Density density;
property public abstract androidx.compose.ui.unit.LayoutDirection layoutDirection;
@@ -2507,6 +2493,7 @@
public static final class ComposeUiNode.Companion {
method public kotlin.jvm.functions.Function0<androidx.compose.ui.node.ComposeUiNode> getConstructor();
+ method @androidx.compose.ui.ExperimentalComposeUiApi public kotlin.jvm.functions.Function2<androidx.compose.ui.node.ComposeUiNode,java.lang.Integer,kotlin.Unit> getSetCompositeKeyHash();
method public kotlin.jvm.functions.Function2<androidx.compose.ui.node.ComposeUiNode,androidx.compose.ui.unit.Density,kotlin.Unit> getSetDensity();
method public kotlin.jvm.functions.Function2<androidx.compose.ui.node.ComposeUiNode,androidx.compose.ui.unit.LayoutDirection,kotlin.Unit> getSetLayoutDirection();
method public kotlin.jvm.functions.Function2<androidx.compose.ui.node.ComposeUiNode,androidx.compose.ui.layout.MeasurePolicy,kotlin.Unit> getSetMeasurePolicy();
@@ -2515,6 +2502,7 @@
method public kotlin.jvm.functions.Function2<androidx.compose.ui.node.ComposeUiNode,androidx.compose.ui.platform.ViewConfiguration,kotlin.Unit> getSetViewConfiguration();
method public kotlin.jvm.functions.Function0<androidx.compose.ui.node.ComposeUiNode> getVirtualConstructor();
property public final kotlin.jvm.functions.Function0<androidx.compose.ui.node.ComposeUiNode> Constructor;
+ property @androidx.compose.ui.ExperimentalComposeUiApi public final kotlin.jvm.functions.Function2<androidx.compose.ui.node.ComposeUiNode,java.lang.Integer,kotlin.Unit> SetCompositeKeyHash;
property public final kotlin.jvm.functions.Function2<androidx.compose.ui.node.ComposeUiNode,androidx.compose.ui.unit.Density,kotlin.Unit> SetDensity;
property public final kotlin.jvm.functions.Function2<androidx.compose.ui.node.ComposeUiNode,androidx.compose.ui.unit.LayoutDirection,kotlin.Unit> SetLayoutDirection;
property public final kotlin.jvm.functions.Function2<androidx.compose.ui.node.ComposeUiNode,androidx.compose.ui.layout.MeasurePolicy,kotlin.Unit> SetMeasurePolicy;
@@ -2765,7 +2753,7 @@
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.hapticfeedback.HapticFeedback> getLocalHapticFeedback();
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.input.InputModeManager> getLocalInputModeManager();
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.LayoutDirection> getLocalLayoutDirection();
- method @androidx.compose.ui.text.ExperimentalTextApi public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.PlatformTextInputPluginRegistry> getLocalPlatformTextInputPluginRegistry();
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.PlatformTextInputPluginRegistry> getLocalPlatformTextInputPluginRegistry();
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.TextInputService> getLocalTextInputService();
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.TextToolbar> getLocalTextToolbar();
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.UriHandler> getLocalUriHandler();
@@ -2781,7 +2769,7 @@
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.hapticfeedback.HapticFeedback> LocalHapticFeedback;
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.input.InputModeManager> LocalInputModeManager;
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.LayoutDirection> LocalLayoutDirection;
- property @androidx.compose.ui.text.ExperimentalTextApi public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.PlatformTextInputPluginRegistry> LocalPlatformTextInputPluginRegistry;
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.PlatformTextInputPluginRegistry> LocalPlatformTextInputPluginRegistry;
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.input.TextInputService> LocalTextInputService;
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.TextToolbar> LocalTextToolbar;
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.UriHandler> LocalUriHandler;
@@ -3038,6 +3026,10 @@
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static int integerResource(@IntegerRes int id);
}
+ public final class ResourceResolutionException extends java.lang.RuntimeException {
+ ctor public ResourceResolutionException(String message, Throwable cause);
+ }
+
public final class StringResources_androidKt {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String pluralStringResource(@PluralsRes int id, int count);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String pluralStringResource(@PluralsRes int id, int count, java.lang.Object... formatArgs);
@@ -3150,6 +3142,7 @@
}
public final class SemanticsActions {
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getClearTextSubstitution();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getCollapse();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getCopyText();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction>> getCustomActions();
@@ -3159,19 +3152,22 @@
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.util.List<androidx.compose.ui.text.TextLayoutResult>,java.lang.Boolean>>> getGetTextLayoutResult();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> getInsertTextAtCursor();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getOnClick();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getOnImeAction();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getOnLongClick();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPageDown();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPageLeft();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPageRight();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPageUp();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPasteText();
- method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getPerformImeAction();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> getRequestFocus();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function2<java.lang.Float,java.lang.Float,java.lang.Boolean>>> getScrollBy();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Integer,java.lang.Boolean>>> getScrollToIndex();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Boolean>>> getSetProgress();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function3<java.lang.Integer,java.lang.Integer,java.lang.Boolean,java.lang.Boolean>>> getSetSelection();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> getSetText();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> getSetTextSubstitution();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Boolean,java.lang.Boolean>>> getShowTextSubstitution();
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> ClearTextSubstitution;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> Collapse;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> CopyText;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction>> CustomActions;
@@ -3181,19 +3177,21 @@
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.util.List<androidx.compose.ui.text.TextLayoutResult>,java.lang.Boolean>>> GetTextLayoutResult;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> InsertTextAtCursor;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> OnClick;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> OnImeAction;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> OnLongClick;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PageDown;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PageLeft;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PageRight;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PageUp;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PasteText;
- property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> PerformImeAction;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> RequestFocus;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function2<java.lang.Float,java.lang.Float,java.lang.Boolean>>> ScrollBy;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Integer,java.lang.Boolean>>> ScrollToIndex;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Boolean>>> SetProgress;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function3<java.lang.Integer,java.lang.Integer,java.lang.Boolean,java.lang.Boolean>>> SetSelection;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> SetText;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>>> SetTextSubstitution;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function1<java.lang.Boolean,java.lang.Boolean>>> ShowTextSubstitution;
field public static final androidx.compose.ui.semantics.SemanticsActions INSTANCE;
}
@@ -3289,8 +3287,10 @@
method @Deprecated public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getIsContainer();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsDialog();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsPopup();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getIsShowingTextSubstitution();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getIsTraversalGroup();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.LiveRegionMode> getLiveRegion();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> getOriginalText();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> getPaneTitle();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getPassword();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.ProgressBarRangeInfo> getProgressBarRangeInfo();
@@ -3319,8 +3319,10 @@
property @Deprecated public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> IsContainer;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsDialog;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsPopup;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> IsShowingTextSubstitution;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> IsTraversalGroup;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.LiveRegionMode> LiveRegion;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> OriginalText;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> PaneTitle;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Password;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.ProgressBarRangeInfo> ProgressBarRangeInfo;
@@ -3344,6 +3346,7 @@
}
public final class SemanticsPropertiesKt {
+ method public static void clearTextSubstitution(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void collapse(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void copyText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void cutText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
@@ -3361,6 +3364,7 @@
method public static androidx.compose.ui.semantics.ScrollAxisRange getHorizontalScrollAxisRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method @Deprecated public static int getImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static int getLiveRegion(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static androidx.compose.ui.text.AnnotatedString getOriginalText(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static String getPaneTitle(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static androidx.compose.ui.semantics.ProgressBarRangeInfo getProgressBarRangeInfo(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static int getRole(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
@@ -3378,8 +3382,10 @@
method public static void insertTextAtCursor(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>? action);
method @androidx.compose.ui.ExperimentalComposeUiApi public static void invisibleToUser(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method @Deprecated public static boolean isContainer(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static boolean isShowingTextSubstitution(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static boolean isTraversalGroup(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void onClick(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
+ method public static void onImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int imeActionType, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void onLongClick(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void pageDown(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void pageLeft(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
@@ -3387,7 +3393,6 @@
method public static void pageUp(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void password(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void pasteText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
- method public static void performImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int imeActionType, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void popup(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void requestFocus(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
method public static void scrollBy(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function2<? super java.lang.Float,? super java.lang.Float,java.lang.Boolean>? action);
@@ -3403,21 +3408,25 @@
method public static void setHorizontalScrollAxisRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.ScrollAxisRange);
method @Deprecated public static void setImeAction(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int);
method public static void setLiveRegion(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int);
+ method public static void setOriginalText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.AnnotatedString);
method public static void setPaneTitle(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String);
method public static void setProgress(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Boolean>? action);
method public static void setProgressBarRangeInfo(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.ProgressBarRangeInfo);
method public static void setRole(androidx.compose.ui.semantics.SemanticsPropertyReceiver, int);
method public static void setSelected(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean);
method public static void setSelection(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Boolean,java.lang.Boolean>? action);
+ method public static void setShowingTextSubstitution(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean);
method public static void setStateDescription(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String);
method public static void setTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String);
method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.AnnotatedString);
method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>? action);
method public static void setTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, long);
+ method public static void setTextSubstitution(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean>? action);
method public static void setToggleableState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.state.ToggleableState);
method public static void setTraversalGroup(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean);
method public static void setTraversalIndex(androidx.compose.ui.semantics.SemanticsPropertyReceiver, float);
method public static void setVerticalScrollAxisRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.ScrollAxisRange);
+ method public static void showTextSubstitution(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function1<? super java.lang.Boolean,java.lang.Boolean>? action);
}
public final class SemanticsProperties_androidKt {
diff --git a/compose/ui/ui/build.gradle b/compose/ui/ui/build.gradle
index caff544..3ad4391 100644
--- a/compose/ui/ui/build.gradle
+++ b/compose/ui/ui/build.gradle
@@ -37,7 +37,8 @@
dependencies {
implementation(libs.kotlinStdlibCommon)
implementation(libs.kotlinCoroutinesCore)
-
+ api("androidx.annotation:annotation:1.6.0")
+ implementation("androidx.collection:collection:1.2.0")
// when updating the runtime version please also update the runtime-saveable version
implementation(project(":compose:runtime:runtime"))
api(project(":compose:runtime:runtime-saveable"))
@@ -79,7 +80,6 @@
// This has stub APIs for access to legacy Android APIs, so we don't want
// any dependency on this module.
compileOnly(project(":compose:ui:ui-android-stubs"))
- api("androidx.annotation:annotation:1.5.0")
implementation("androidx.autofill:autofill:1.0.0")
implementation(libs.kotlinCoroutinesAndroid)
diff --git a/compose/ui/ui/lint-baseline.xml b/compose/ui/ui/lint-baseline.xml
index 8aebb3a..4d3c0de 100644
--- a/compose/ui/ui/lint-baseline.xml
+++ b/compose/ui/ui/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
+<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">
<issue
id="BanHideAnnotation"
@@ -11,42 +11,6 @@
</issue>
<issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class TestModifierUpdater internal constructor(private val node: LayoutNode) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/compose/ui/layout/TestModifierUpdater.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="fun TestModifierUpdaterLayout(onAttached: (TestModifierUpdater) -> Unit) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/compose/ui/layout/TestModifierUpdater.kt"/>
- </issue>
-
- <issue
- id="BanInlineOptIn"
- message="Inline functions cannot opt into experimental APIs."
- errorLine1=" internal inline fun fetchCustomEnter("
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt"/>
- </issue>
-
- <issue
- id="BanInlineOptIn"
- message="Inline functions cannot opt into experimental APIs."
- errorLine1=" internal inline fun fetchCustomExit("
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt"/>
- </issue>
-
- <issue
id="BanThreadSleep"
message="Uses Thread.sleep()"
errorLine1=" Thread.sleep(sleepTime)"
@@ -67,2598 +31,6 @@
<issue
id="ExperimentalPropertyAnnotation"
message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
- errorLine1=" @ExperimentalComposeUiApi"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifier.kt"/>
- </issue>
-
- <issue
- id="ExperimentalPropertyAnnotation"
- message="This property does not have all required annotations to correctly mark it as experimental."
errorLine1=" @ExperimentalComposeUiApi"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
diff --git a/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/NestedScrollSamples.kt b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/NestedScrollSamples.kt
index 53d42e7..84c940f 100644
--- a/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/NestedScrollSamples.kt
+++ b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/NestedScrollSamples.kt
@@ -57,9 +57,7 @@
val toolbarHeight = 48.dp
val toolbarHeightPx = with(LocalDensity.current) { toolbarHeight.roundToPx().toFloat() }
// our offset to collapse toolbar
- val toolbarOffsetHeightPx =
-
- remember { mutableStateOf(0f) }
+ val toolbarOffsetHeightPx = remember { mutableStateOf(0f) }
// now, let's create connection to the nested scroll system and listen to the scroll
// happening inside child LazyColumn
val nestedScrollConnection = remember {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
index 617ce21..3abbc61 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
@@ -19,10 +19,15 @@
import android.os.Build
import android.text.SpannableString
+import android.util.LongSparseArray
import android.view.ViewGroup
import android.view.ViewStructure
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
+import android.view.translation.TranslationRequestValue
+import android.view.translation.TranslationResponseValue
+import android.view.translation.ViewTranslationRequest
+import android.view.translation.ViewTranslationResponse
import android.widget.FrameLayout
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -76,6 +81,7 @@
import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.semantics.SemanticsOwner
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
+import androidx.compose.ui.semantics.clearTextSubstitution
import androidx.compose.ui.semantics.collapse
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.copyText
@@ -90,9 +96,11 @@
import androidx.compose.ui.semantics.getTextLayoutResult
import androidx.compose.ui.semantics.heading
import androidx.compose.ui.semantics.horizontalScrollAxisRange
+import androidx.compose.ui.semantics.isShowingTextSubstitution
import androidx.compose.ui.semantics.liveRegion
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.semantics.onLongClick
+import androidx.compose.ui.semantics.originalText
import androidx.compose.ui.semantics.password
import androidx.compose.ui.semantics.pasteText
import androidx.compose.ui.semantics.progressBarRangeInfo
@@ -101,6 +109,8 @@
import androidx.compose.ui.semantics.setProgress
import androidx.compose.ui.semantics.setSelection
import androidx.compose.ui.semantics.setText
+import androidx.compose.ui.semantics.setTextSubstitution
+import androidx.compose.ui.semantics.showTextSubstitution
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.semantics.testTagsAsResourceId
@@ -136,6 +146,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.Executors
+import java.util.function.Consumer
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.asCoroutineDispatcher
import org.junit.Assert.assertEquals
@@ -1457,7 +1468,7 @@
fun testInitContentCaptureSemanticsStructureChangeEvents_onStart() {
setUpContentCapture()
- accessibilityDelegate.initContentCaptureSemanticsStructureChangeEvents(true)
+ accessibilityDelegate.initContentCapture(true)
// verify the root node appeared
verify(contentCaptureSessionCompat).newVirtualViewStructure(any(), any())
@@ -1473,7 +1484,7 @@
fun testInitContentCaptureSemanticsStructureChangeEvents_onStop() {
setUpContentCapture()
- accessibilityDelegate.initContentCaptureSemanticsStructureChangeEvents(false)
+ accessibilityDelegate.initContentCapture(false)
// verify the root node disappeared
verify(contentCaptureSessionCompat).notifyViewsDisappeared(any())
@@ -1631,6 +1642,216 @@
assertThat(accessibilityDelegate.bufferedContentCaptureDisappearedNodes).isEmpty()
}
+ @Test
+ @SdkSuppress(minSdkVersion = 29)
+ fun testUpdateTranslationOnAppeared_showOriginal() {
+ setUpContentCapture()
+ accessibilityDelegate.onHideTranslation()
+
+ val nodeId = 10
+ val oldNode = createSemanticsNodeWithChildren(nodeId, emptyList())
+ val oldNodeCopy = SemanticsNodeCopy(oldNode, mapOf())
+ accessibilityDelegate.previousSemanticsNodes[nodeId] = oldNodeCopy
+
+ var result = true
+ val newNodeId1 = 11
+ val newNodeId2 = 10
+ val newNode1 = createSemanticsNodeWithChildren(newNodeId1, emptyList()) {
+ text = AnnotatedString("foo")
+ originalText = AnnotatedString("bar")
+ isShowingTextSubstitution = true
+ showTextSubstitution {
+ result = it
+ true
+ }
+ }
+ val newNode2 = createSemanticsNodeWithChildren(newNodeId2, listOf(newNode1))
+ accessibilityDelegate.currentSemanticsNodes = mapOf(
+ newNodeId1 to SemanticsNodeWithAdjustedBounds(newNode1, android.graphics.Rect()),
+ newNodeId2 to SemanticsNodeWithAdjustedBounds(newNode2, android.graphics.Rect()),
+ )
+
+ accessibilityDelegate.sendContentCaptureSemanticsStructureChangeEvents(
+ newNode2, oldNodeCopy)
+
+ assertFalse(result)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 29)
+ fun testUpdateTranslationOnAppeared_showTranslated() {
+ setUpContentCapture()
+ accessibilityDelegate.onShowTranslation()
+
+ val nodeId = 10
+ val oldNode = createSemanticsNodeWithChildren(nodeId, emptyList())
+ val oldNodeCopy = SemanticsNodeCopy(oldNode, mapOf())
+ accessibilityDelegate.previousSemanticsNodes[nodeId] = oldNodeCopy
+
+ var result = false
+ val newNodeId1 = 11
+ val newNodeId2 = 10
+ val newNode1 = createSemanticsNodeWithChildren(newNodeId1, emptyList()) {
+ text = AnnotatedString("foo")
+ isShowingTextSubstitution = false
+ showTextSubstitution {
+ result = it
+ true
+ }
+ }
+ val newNode2 = createSemanticsNodeWithChildren(newNodeId2, listOf(newNode1))
+ accessibilityDelegate.currentSemanticsNodes = mapOf(
+ newNodeId1 to SemanticsNodeWithAdjustedBounds(newNode1, android.graphics.Rect()),
+ newNodeId2 to SemanticsNodeWithAdjustedBounds(newNode2, android.graphics.Rect()),
+ )
+
+ accessibilityDelegate.sendContentCaptureSemanticsStructureChangeEvents(
+ newNode2, oldNodeCopy)
+
+ assertTrue(result)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testOnCreateVirtualViewTranslationRequests() {
+ setUpContentCapture()
+
+ val newNodeId1 = 11
+ val newNodeId2 = 10
+ val newNode1 = createSemanticsNodeWithChildren(newNodeId1, emptyList()) {
+ text = AnnotatedString("foo")
+ }
+ val newNode2 = createSemanticsNodeWithChildren(newNodeId2, listOf(newNode1)) {
+ text = AnnotatedString("bar")
+ }
+ accessibilityDelegate.currentSemanticsNodes = mapOf(
+ newNodeId1 to SemanticsNodeWithAdjustedBounds(newNode1, android.graphics.Rect()),
+ newNodeId2 to SemanticsNodeWithAdjustedBounds(newNode2, android.graphics.Rect()),
+ )
+
+ val ids = LongArray(1)
+ ids[0] = newNodeId1.toLong()
+ val requestsCollector: Consumer<ViewTranslationRequest?> = mock()
+
+ accessibilityDelegate.onCreateVirtualViewTranslationRequests(
+ ids,
+ IntArray(0),
+ requestsCollector,
+ )
+
+ val captor = argumentCaptor<ViewTranslationRequest>()
+ verify(requestsCollector).accept(captor.capture())
+ val request = ViewTranslationRequest.Builder(
+ androidComposeView.autofillId,
+ newNodeId1.toLong()
+ )
+ .setValue(ViewTranslationRequest.ID_TEXT, TranslationRequestValue.forText(
+ AnnotatedString("foo")))
+ .build()
+ assertEquals(captor.firstValue, request)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testOnVirtualViewTranslationResponses() {
+ setUpContentCapture()
+ val newNodeId1 = 11
+ var result: AnnotatedString? = null
+ val newNode1 = createSemanticsNodeWithChildren(newNodeId1, emptyList()) {
+ text = AnnotatedString("foo")
+ setTextSubstitution {
+ result = it
+ true
+ }
+ }
+ accessibilityDelegate.currentSemanticsNodes = mapOf(
+ newNodeId1 to SemanticsNodeWithAdjustedBounds(newNode1, android.graphics.Rect()),
+ )
+
+ val autofillId = androidComposeView.autofillId
+ val response = ViewTranslationResponse.Builder(autofillId)
+ .setValue(ViewTranslationRequest.ID_TEXT,
+ TranslationResponseValue.Builder(0).setText("bar").build())
+ .build()
+ val responses = LongSparseArray<ViewTranslationResponse?>()
+ responses.append(newNodeId1.toLong(), response)
+
+ accessibilityDelegate.onVirtualViewTranslationResponses(responses)
+
+ assertEquals("bar", result?.text)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testOnShowTranslation() {
+ setUpContentCapture()
+ val newNodeId1 = 11
+ var result = false
+ val newNode1 = createSemanticsNodeWithChildren(newNodeId1, emptyList()) {
+ text = AnnotatedString("foo")
+ isShowingTextSubstitution = false
+ showTextSubstitution {
+ result = it
+ true
+ }
+ }
+ accessibilityDelegate.currentSemanticsNodes = mapOf(
+ newNodeId1 to SemanticsNodeWithAdjustedBounds(newNode1, android.graphics.Rect()),
+ )
+
+ accessibilityDelegate.onShowTranslation()
+
+ assertTrue(result)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testOnHideTranslation() {
+ setUpContentCapture()
+ val newNodeId1 = 11
+ var result = true
+ val newNode1 = createSemanticsNodeWithChildren(newNodeId1, emptyList()) {
+ text = AnnotatedString("bar")
+ isShowingTextSubstitution = true
+ originalText = AnnotatedString("foo")
+ showTextSubstitution {
+ result = it
+ true
+ }
+ }
+ accessibilityDelegate.currentSemanticsNodes = mapOf(
+ newNodeId1 to SemanticsNodeWithAdjustedBounds(newNode1, android.graphics.Rect()),
+ )
+
+ accessibilityDelegate.onHideTranslation()
+
+ assertFalse(result)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testOnClearTranslation() {
+ setUpContentCapture()
+ val newNodeId1 = 11
+ var result = false
+ val newNode1 = createSemanticsNodeWithChildren(newNodeId1, emptyList()) {
+ text = AnnotatedString("bar")
+ originalText = AnnotatedString("foo")
+ isShowingTextSubstitution = true
+ clearTextSubstitution {
+ result = true
+ true
+ }
+ }
+ accessibilityDelegate.currentSemanticsNodes = mapOf(
+ newNodeId1 to SemanticsNodeWithAdjustedBounds(newNode1, android.graphics.Rect()),
+ )
+
+ accessibilityDelegate.onClearTranslation()
+
+ assertTrue(result)
+ }
+
private fun sendTextSemanticsChangeEvent(oldNodePassword: Boolean, newNodePassword: Boolean) {
val nodeId = 1
val oldTextNode = createSemanticsNodeWithProperties(nodeId, true) {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawReorderingTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawReorderingTest.kt
index 57531e5..ebea073 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawReorderingTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawReorderingTest.kt
@@ -43,6 +43,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.test.filters.SdkSuppress
+import com.google.common.truth.Truth.assertThat
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import org.junit.Assert.assertNotNull
@@ -1040,20 +1041,28 @@
@Test
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
- fun placingInDifferentOrderTriggersRedraw() {
+ fun changingPlaceOrderInLayout() {
var reverseOrder by mutableStateOf(false)
+ var childRelayoutCount = 0
+ val childRelayoutModifier = Modifier.layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ childRelayoutCount++
+ placeable.place(0, 0)
+ }
+ }
rule.runOnUiThread {
activity.setContent {
Layout(
content = {
- FixedSize(30) {
+ FixedSize(30, childRelayoutModifier) {
FixedSize(
10,
Modifier.padding(10)
.background(Color.White)
)
}
- FixedSize(30) {
+ FixedSize(30, childRelayoutModifier) {
FixedSize(
30,
Modifier.background(Color.Red)
@@ -1084,6 +1093,7 @@
rule.runOnUiThread {
drawLatch = CountDownLatch(1)
reverseOrder = true
+ childRelayoutCount = 0
}
rule.validateSquareColors(
@@ -1092,6 +1102,74 @@
size = 10,
drawLatch = drawLatch
)
+ rule.runOnUiThread {
+ // changing drawing order doesn't require child's layer block rerun
+ assertThat(childRelayoutCount).isEqualTo(0)
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun changingZIndexInLayout() {
+ var zIndex by mutableStateOf(1f)
+ var childRelayoutCount = 0
+ val childRelayoutModifier = Modifier.layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ childRelayoutCount++
+ placeable.place(0, 0)
+ }
+ }
+ rule.runOnUiThread {
+ activity.setContent {
+ Layout(
+ content = {
+ FixedSize(30, childRelayoutModifier) {
+ FixedSize(
+ 10,
+ Modifier.padding(10)
+ .background(Color.White)
+ )
+ }
+ FixedSize(30, childRelayoutModifier) {
+ FixedSize(
+ 30,
+ Modifier.background(Color.Red)
+ )
+ }
+ },
+ modifier = Modifier.drawLatchModifier()
+ ) { measurables, _ ->
+ val newConstraints = Constraints.fixed(30, 30)
+ val placeables = measurables.map { m ->
+ m.measure(newConstraints)
+ }
+ layout(newConstraints.maxWidth, newConstraints.maxWidth) {
+ placeables[0].place(0, 0)
+ placeables[1].place(0, 0, zIndex)
+ }
+ }
+ }
+ }
+
+ assertTrue(drawLatch.await(1, TimeUnit.SECONDS))
+
+ rule.runOnUiThread {
+ drawLatch = CountDownLatch(1)
+ zIndex = -1f
+ childRelayoutCount = 0
+ }
+
+ rule.validateSquareColors(
+ outerColor = Color.Red,
+ innerColor = Color.White,
+ size = 10,
+ drawLatch = drawLatch
+ )
+ rule.runOnUiThread {
+ // changing zIndex doesn't require child's layer block rerun
+ assertThat(childRelayoutCount).isEqualTo(0)
+ }
}
fun Modifier.drawLatchModifier() = drawBehind { drawLatch.countDown() }
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/GraphicsLayerTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/GraphicsLayerTest.kt
index ba80c91..cff9158 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/GraphicsLayerTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/GraphicsLayerTest.kt
@@ -121,9 +121,12 @@
rule.setContent {
FixedSize(
30,
- Modifier.padding(10).graphicsLayer().onGloballyPositioned {
- coords = it
- }
+ Modifier
+ .padding(10)
+ .graphicsLayer()
+ .onGloballyPositioned {
+ coords = it
+ }
) { /* no-op */ }
}
@@ -148,9 +151,11 @@
Padding(10) {
FixedSize(
10,
- Modifier.graphicsLayer(scaleX = 2f, scaleY = 3f).onGloballyPositioned {
- coords = it
- }
+ Modifier
+ .graphicsLayer(scaleX = 2f, scaleY = 3f)
+ .onGloballyPositioned {
+ coords = it
+ }
) {
}
}
@@ -171,9 +176,11 @@
Padding(10) {
FixedSize(
10,
- Modifier.scale(scaleX = 2f, scaleY = 3f).onGloballyPositioned {
- coords = it
- }
+ Modifier
+ .scale(scaleX = 2f, scaleY = 3f)
+ .onGloballyPositioned {
+ coords = it
+ }
) {
}
}
@@ -194,9 +201,11 @@
Padding(10) {
FixedSize(
10,
- Modifier.scale(scale = 2f).onGloballyPositioned {
- coords = it
- }
+ Modifier
+ .scale(scale = 2f)
+ .onGloballyPositioned {
+ coords = it
+ }
) {
}
}
@@ -217,9 +226,11 @@
Padding(10) {
FixedSize(
10,
- Modifier.graphicsLayer(scaleY = 3f, rotationZ = 90f).onGloballyPositioned {
- coords = it
- }
+ Modifier
+ .graphicsLayer(scaleY = 3f, rotationZ = 90f)
+ .onGloballyPositioned {
+ coords = it
+ }
) {
}
}
@@ -240,9 +251,11 @@
Padding(10) {
FixedSize(
10,
- Modifier.rotate(90f).onGloballyPositioned {
- coords = it
- }
+ Modifier
+ .rotate(90f)
+ .onGloballyPositioned {
+ coords = it
+ }
) {
}
}
@@ -263,12 +276,14 @@
Padding(10) {
FixedSize(
10,
- Modifier.graphicsLayer(
- rotationZ = 90f,
- transformOrigin = TransformOrigin(1.0f, 1.0f)
- ).onGloballyPositioned {
- coords = it
- }
+ Modifier
+ .graphicsLayer(
+ rotationZ = 90f,
+ transformOrigin = TransformOrigin(1.0f, 1.0f)
+ )
+ .onGloballyPositioned {
+ coords = it
+ }
)
}
}
@@ -288,12 +303,14 @@
Padding(10) {
FixedSize(
10,
- Modifier.graphicsLayer(
- translationX = 5.0f,
- translationY = 8.0f
- ).onGloballyPositioned {
- coords = it
- }
+ Modifier
+ .graphicsLayer(
+ translationX = 5.0f,
+ translationY = 8.0f
+ )
+ .onGloballyPositioned {
+ coords = it
+ }
)
}
}
@@ -314,9 +331,11 @@
FixedSize(10, Modifier.graphicsLayer(clip = true)) {
FixedSize(
10,
- Modifier.graphicsLayer(scaleX = 2f).onGloballyPositioned {
- coords = it
- }
+ Modifier
+ .graphicsLayer(scaleX = 2f)
+ .onGloballyPositioned {
+ coords = it
+ }
) {
}
}
@@ -339,18 +358,20 @@
rule.setContent {
with(LocalDensity.current) {
Box(
- Modifier.requiredSize(25.toDp())
+ Modifier
+ .requiredSize(25.toDp())
.graphicsLayer(
rotationZ = 30f,
clip = true
)
) {
Box(
- Modifier.graphicsLayer(
- rotationZ = 90f,
- transformOrigin = TransformOrigin(0f, 1f),
- clip = true
- )
+ Modifier
+ .graphicsLayer(
+ rotationZ = 90f,
+ transformOrigin = TransformOrigin(0f, 1f),
+ clip = true
+ )
.requiredSize(20.toDp(), 10.toDp())
.align(AbsoluteAlignment.TopLeft)
.onGloballyPositioned {
@@ -395,7 +416,9 @@
if (Build.VERSION.SDK_INT == 28) return // b/260095151
val testTag = "parent"
rule.setContent {
- Box(modifier = Modifier.testTag(testTag).wrapContentSize()) {
+ Box(modifier = Modifier
+ .testTag(testTag)
+ .wrapContentSize()) {
Box(
modifier = Modifier
.requiredSize(100.dp)
@@ -431,7 +454,10 @@
}
val tag = "testTag"
rule.setContent {
- Box(modifier = Modifier.testTag(tag).requiredSize(100.dp).background(Color.Blue)) {
+ Box(modifier = Modifier
+ .testTag(tag)
+ .requiredSize(100.dp)
+ .background(Color.Blue)) {
Box(
modifier = Modifier
.matchParentSize()
@@ -454,9 +480,11 @@
FixedSize(10, Modifier.graphicsLayer(clip = true)) {
FixedSize(
10,
- Modifier.padding(20).onGloballyPositioned {
- coords = it
- }
+ Modifier
+ .padding(20)
+ .onGloballyPositioned {
+ coords = it
+ }
) {
}
}
@@ -493,7 +521,8 @@
drawBlock: DrawScope.() -> Unit
) {
Box(
- Modifier.testTag(tag)
+ Modifier
+ .testTag(tag)
.size(size)
.background(Color.Black)
.graphicsLayer {
@@ -606,7 +635,11 @@
val size = (sizePx / density)
val squareSize = (squarePx / density)
offset = (20f / density).roundToInt()
- Box(Modifier.size(size.dp).background(Color.LightGray).testTag(testTag)) {
+ Box(
+ Modifier
+ .size(size.dp)
+ .background(Color.LightGray)
+ .testTag(testTag)) {
Box(
Modifier
.layout { measurable, constraints ->
@@ -664,7 +697,11 @@
val size = (sizePx / density)
val squareSize = (squarePx / density)
offset = (20f / density).roundToInt()
- Box(Modifier.size(size.dp).background(Color.LightGray).testTag(testTag)) {
+ Box(
+ Modifier
+ .size(size.dp)
+ .background(Color.LightGray)
+ .testTag(testTag)) {
Box(
Modifier
.layout { measurable, constraints ->
@@ -689,7 +726,8 @@
drawRect(
color = Color.Red,
topLeft = Offset(-width, -height),
- size = Size(width * 2, height * 2))
+ size = Size(width * 2, height * 2)
+ )
}
)
}
@@ -738,7 +776,11 @@
val size = (sizePx / density)
val squareSize = (squarePx / density)
offset = (20f / density).roundToInt()
- Box(Modifier.size(size.dp).background(Color.LightGray).testTag(testTag)) {
+ Box(
+ Modifier
+ .size(size.dp)
+ .background(Color.LightGray)
+ .testTag(testTag)) {
Box(
Modifier
.layout { measurable, constraints ->
@@ -764,7 +806,8 @@
drawRect(
color = Color.Red,
topLeft = Offset(-width, -height),
- size = Size(width * 2, height * 2))
+ size = Size(width * 2, height * 2)
+ )
}
)
}
@@ -815,7 +858,11 @@
val size = (sizePx / density)
val squareSize = (squarePx / density)
offset = (20f / density).roundToInt()
- Box(Modifier.size(size.dp).background(Color.LightGray).testTag(testTag)) {
+ Box(
+ Modifier
+ .size(size.dp)
+ .background(Color.LightGray)
+ .testTag(testTag)) {
Box(
Modifier
.layout { measurable, constraints ->
@@ -845,7 +892,8 @@
drawRect(
color = Color.Red,
topLeft = Offset(-width, -height),
- size = Size(width * 2, height * 2))
+ size = Size(width * 2, height * 2)
+ )
}
)
}
@@ -896,7 +944,11 @@
val size = (sizePx / density)
val squareSize = (squarePx / density)
offset = (20f / density).roundToInt()
- Box(Modifier.size(size.dp).background(Color.LightGray).testTag(testTag)) {
+ Box(
+ Modifier
+ .size(size.dp)
+ .background(Color.LightGray)
+ .testTag(testTag)) {
Box(
Modifier
.layout { measurable, constraints ->
@@ -971,7 +1023,11 @@
val size = (sizePx / density)
val squareSize = (squarePx / density)
offset = (20f / density).roundToInt()
- Box(Modifier.size(size.dp).background(Color.LightGray).testTag(testTag)) {
+ Box(
+ Modifier
+ .size(size.dp)
+ .background(Color.LightGray)
+ .testTag(testTag)) {
Box(
Modifier
.layout { measurable, constraints ->
@@ -1044,7 +1100,10 @@
rule.setContent {
FixedSize(
5,
- Modifier.graphicsLayer().testTag("tag").background(color)
+ Modifier
+ .graphicsLayer()
+ .testTag("tag")
+ .background(color)
)
}
@@ -1092,14 +1151,18 @@
Layout(
content = {
Box(
- Modifier.fillMaxSize().clickable {
- firstClicked = true
- }
+ Modifier
+ .fillMaxSize()
+ .clickable {
+ firstClicked = true
+ }
)
Box(
- Modifier.fillMaxSize().clickable {
- secondClicked = true
- }
+ Modifier
+ .fillMaxSize()
+ .clickable {
+ secondClicked = true
+ }
)
},
modifier = Modifier.testTag("layout")
@@ -1167,7 +1230,8 @@
rule.setContent {
Canvas(
modifier =
- Modifier.testTag(tag)
+ Modifier
+ .testTag(tag)
.size((dimen / LocalDensity.current.density).dp)
.background(Color.Black)
.graphicsLayer(
@@ -1209,7 +1273,8 @@
rule.setContent {
Canvas(
modifier =
- Modifier.testTag(tag)
+ Modifier
+ .testTag(tag)
.size((dimen / LocalDensity.current.density).dp)
.background(Color.LightGray)
.graphicsLayer(
@@ -1244,7 +1309,8 @@
rule.setContent {
Canvas(
modifier =
- Modifier.testTag(tag)
+ Modifier
+ .testTag(tag)
.size((dimen / LocalDensity.current.density).dp)
.background(Color.Black)
.graphicsLayer(
@@ -1360,7 +1426,10 @@
val size = 100
rule.setContent {
val sizeDp = with(LocalDensity.current) { size.toDp() }
- LazyColumn(Modifier.testTag("lazy").background(Color.Blue)) {
+ LazyColumn(
+ Modifier
+ .testTag("lazy")
+ .background(Color.Blue)) {
items(4) {
Box(
Modifier
@@ -1512,7 +1581,10 @@
}
}
rule.setContent {
- Box(Modifier.graphicsLayer(translationX = translationX).then(layoutModifier)) {
+ Box(
+ Modifier
+ .graphicsLayer(translationX = translationX)
+ .then(layoutModifier)) {
Layout(Modifier.onGloballyPositioned { coordinates = it }) { _, _ ->
layout(10, 10) {}
}
@@ -1550,7 +1622,10 @@
}
}
rule.setContent {
- Box(Modifier.graphicsLayer(lambda).then(layoutModifier)) {
+ Box(
+ Modifier
+ .graphicsLayer(lambda)
+ .then(layoutModifier)) {
Layout(Modifier.onGloballyPositioned { coordinates = it }) { _, _ ->
layout(10, 10) {}
}
@@ -1572,4 +1647,92 @@
assertEquals(0, relayoutCount)
}
}
+
+ @Test
+ fun addingLayerForChildDoesntTriggerChildRelayout() {
+ var relayoutCount = 0
+ var modifierRelayoutCount = 0
+ var needLayer by mutableStateOf(false)
+ var layerBlockCalled = false
+ rule.setContent {
+ Layout(content = {
+ Layout(
+ modifier = Modifier.layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ modifierRelayoutCount++
+ placeable.place(0, 0)
+ }
+ }
+ ) { _, _ ->
+ layout(10, 10) {
+ relayoutCount++
+ }
+ }
+ }) { measurables, constraints ->
+ val placeable = measurables[0].measure(constraints)
+ layout(placeable.width, placeable.height) {
+ if (needLayer) {
+ placeable.placeWithLayer(0, 0) {
+ layerBlockCalled = true
+ }
+ } else {
+ placeable.place(0, 0)
+ }
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ relayoutCount = 0
+ modifierRelayoutCount = 0
+ needLayer = true
+ }
+
+ rule.runOnIdle {
+ assertEquals(0, relayoutCount)
+ assertTrue(layerBlockCalled)
+ assertEquals(0, modifierRelayoutCount)
+ }
+ }
+
+ @Test
+ fun movingChildsLayerDoesntTriggerChildRelayout() {
+ var relayoutCount = 0
+ var modifierRelayoutCount = 0
+ var position by mutableStateOf(0)
+ rule.setContent {
+ Layout(content = {
+ Layout(
+ modifier = Modifier.layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ modifierRelayoutCount++
+ placeable.place(0, 0)
+ }
+ }
+ ) { _, _ ->
+ layout(10, 10) {
+ relayoutCount++
+ }
+ }
+ }) { measurables, constraints ->
+ val placeable = measurables[0].measure(constraints)
+ layout(placeable.width, placeable.height) {
+ placeable.placeWithLayer(position, 0)
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ relayoutCount = 0
+ modifierRelayoutCount = 0
+ position = 10
+ }
+
+ rule.runOnIdle {
+ assertEquals(0, relayoutCount)
+ assertEquals(0, modifierRelayoutCount)
+ }
+ }
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/CombinedFocusModifierNodeTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/CombinedFocusModifierNodeTest.kt
index 75515b6..c73a652 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/CombinedFocusModifierNodeTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/CombinedFocusModifierNodeTest.kt
@@ -20,6 +20,7 @@
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.ModifierNodeElement
@@ -40,7 +41,7 @@
@Test
fun requestFocus() {
// Arrange.
- val combinedFocusNode = CombinedFocusNode(delegatedFocusTarget)
+ val combinedFocusNode = CombinedFocusNode()
rule.setFocusableContent {
Box(Modifier.combinedFocusElement(combinedFocusNode))
}
@@ -59,7 +60,7 @@
@Test
fun captureFocus() {
// Arrange.
- val combinedFocusNode = CombinedFocusNode(delegatedFocusTarget)
+ val combinedFocusNode = CombinedFocusNode()
rule.setFocusableContent {
Box(Modifier.combinedFocusElement(combinedFocusNode))
}
@@ -82,7 +83,7 @@
@Test
fun freeFocus() {
// Arrange.
- val combinedFocusNode = CombinedFocusNode(delegatedFocusTarget)
+ val combinedFocusNode = CombinedFocusNode()
rule.setFocusableContent {
Box(Modifier.combinedFocusElement(combinedFocusNode))
}
@@ -106,7 +107,7 @@
@Test
fun requestFocusWhenCanFocusIsTrue() {
// Arrange.
- val combinedFocusNode = CombinedFocusNode(delegatedFocusTarget).apply { canFocus = true }
+ val combinedFocusNode = CombinedFocusNode().apply { canFocus = true }
rule.setFocusableContent {
Box(Modifier.combinedFocusElement(combinedFocusNode))
}
@@ -125,7 +126,7 @@
@Test
fun requestFocusWhenCanFocusIsFalse() {
// Arrange.
- val combinedFocusNode = CombinedFocusNode(delegatedFocusTarget).apply { canFocus = false }
+ val combinedFocusNode = CombinedFocusNode().apply { canFocus = false }
rule.setFocusableContent {
Box(Modifier.combinedFocusElement(combinedFocusNode))
}
@@ -148,7 +149,7 @@
@Test
fun losesFocusWhenCanFocusChangesToFalse() {
// Arrange.
- val combinedFocusNode = CombinedFocusNode(delegatedFocusTarget)
+ val combinedFocusNode = CombinedFocusNode()
rule.setFocusableContent {
Box(Modifier.combinedFocusElement(combinedFocusNode))
}
@@ -170,7 +171,7 @@
@Test
fun doesNotGainFocusWhenCanFocusChangesToTrue() {
// Arrange.
- val combinedFocusNode = CombinedFocusNode(delegatedFocusTarget)
+ val combinedFocusNode = CombinedFocusNode()
rule.setFocusableContent {
Box(Modifier.combinedFocusElement(combinedFocusNode))
}
@@ -190,44 +191,53 @@
}
}
- private fun Modifier.combinedFocusElement(combinedFocusNode: CombinedFocusNode): Modifier {
- return this
- .then(CombinedFocusElement(combinedFocusNode))
- .then(if (delegatedFocusTarget) Modifier else Modifier.focusTarget())
+ private fun Modifier.combinedFocusElement(
+ combinedFocusNode: CombinedFocusModifierNode
+ ): Modifier = if (delegatedFocusTarget) {
+ this then DelegatedFocusTargetElement(combinedFocusNode as DelegatedFocusTargetNode)
+ } else {
+ this then AppendedFocusTargetElement(combinedFocusNode as AppendedFocusTargetNode)
+ .focusTarget()
}
- private data class CombinedFocusElement(
- val combinedFocusNode: CombinedFocusNode
- ) : ModifierNodeElement<CombinedFocusNode>() {
- override fun create(): CombinedFocusNode = combinedFocusNode
- override fun update(node: CombinedFocusNode) {
- node.focusState = combinedFocusNode.focusState
- }
+ private data class AppendedFocusTargetElement(
+ val appendedFocusTargetNode: AppendedFocusTargetNode
+ ) : ModifierNodeElement<AppendedFocusTargetNode>() {
+ override fun create(): AppendedFocusTargetNode = appendedFocusTargetNode
+ override fun update(node: AppendedFocusTargetNode) {}
+ }
+
+ private data class DelegatedFocusTargetElement(
+ val delegatedFocusTargetNode: DelegatedFocusTargetNode
+ ) : ModifierNodeElement<DelegatedFocusTargetNode>() {
+ override fun create(): DelegatedFocusTargetNode = delegatedFocusTargetNode
+ override fun update(node: DelegatedFocusTargetNode) {}
}
companion object {
@JvmStatic
@Parameterized.Parameters(name = "delegatedFocusTarget = {0}")
- fun initParameters() =
- listOf(
- false,
- true
- )
+ fun initParameters() = listOf(false, true)
}
- private class CombinedFocusNode(delegatedFocusTarget: Boolean) :
- FocusRequesterModifierNode,
+ private fun CombinedFocusNode(): CombinedFocusModifierNode {
+ return if (delegatedFocusTarget) DelegatedFocusTargetNode() else AppendedFocusTargetNode()
+ }
+
+ private interface CombinedFocusModifierNode :
+ FocusRequesterModifierNode, FocusPropertiesModifierNode {
+ val focusState: FocusState
+ var canFocus: Boolean
+ }
+
+ private class AppendedFocusTargetNode :
+ CombinedFocusModifierNode,
FocusEventModifierNode,
- FocusPropertiesModifierNode,
DelegatingNode() {
- init {
- if (delegatedFocusTarget) delegate(FocusTargetNode())
- }
+ override lateinit var focusState: FocusState
- lateinit var focusState: FocusState
-
- var canFocus by mutableStateOf(true)
+ override var canFocus by mutableStateOf(true)
override fun onFocusEvent(focusState: FocusState) {
this.focusState = focusState
@@ -237,4 +247,21 @@
focusProperties.canFocus = canFocus
}
}
+
+ private class DelegatedFocusTargetNode :
+ CombinedFocusModifierNode,
+ DelegatingNode() {
+
+ val focusTargetModifierNode = delegate(FocusTargetModifierNode())
+
+ override val focusState: FocusState
+ @OptIn(ExperimentalComposeUiApi::class)
+ get() = focusTargetModifierNode.focusState
+
+ override var canFocus by mutableStateOf(true)
+
+ override fun applyFocusProperties(focusProperties: FocusProperties) {
+ focusProperties.canFocus = canFocus
+ }
+ }
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusManagerCompositionLocalTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusManagerCompositionLocalTest.kt
index a462e04..48f89f2 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusManagerCompositionLocalTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusManagerCompositionLocalTest.kt
@@ -18,7 +18,6 @@
import android.view.View
import androidx.compose.foundation.layout.Box
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusStateImpl.Active
import androidx.compose.ui.focus.FocusStateImpl.ActiveParent
@@ -425,12 +424,10 @@
}
}
- @OptIn(ExperimentalComposeUiApi::class)
private val FocusManager.rootFocusState: FocusState
get() = (this as FocusOwnerImpl).rootFocusNode.focusState
- @OptIn(ExperimentalComposeUiApi::class)
private fun FocusManager.setRootFocusState(focusState: FocusStateImpl) {
- (this as FocusOwnerImpl).rootFocusNode.focusStateImpl = focusState
+ (this as FocusOwnerImpl).rootFocusNode.focusState = focusState
}
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt
index ea7a61b..650d52c 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt
@@ -38,8 +38,10 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performMouseInput
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeDown
import androidx.compose.ui.test.swipeUp
@@ -53,6 +55,8 @@
import kotlin.math.sign
import kotlinx.coroutines.isActive
import kotlinx.coroutines.runBlocking
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
@@ -64,6 +68,8 @@
@get:Rule
val rule = createComposeRule()
+ private val mainLayoutTag = "mainLayout"
+
private val preScrollOffset = Offset(120f, 120f)
private val scrollOffset = Offset(125f, 125f)
private val scrollLeftOffset = Offset(32f, 32f)
@@ -1032,7 +1038,7 @@
}
}
- Column(modifier = Modifier.fillMaxSize().testTag("mainLayout")) {
+ Column(modifier = Modifier.fillMaxSize().testTag(mainLayoutTag)) {
Box(
modifier = Modifier
.fillMaxWidth()
@@ -1062,17 +1068,17 @@
}
}
- rule.onNodeWithTag("mainLayout").performTouchInput { swipeUp(bottom, centerY) }
+ rule.onNodeWithTag(mainLayoutTag).performTouchInput { swipeUp(bottom, centerY) }
rule.runOnIdle {
// swipe ups provide negative signed velocities
assertThat(sign(lastVelocity.y)).isEqualTo(-1)
}
- rule.onNodeWithTag("mainLayout").performTouchInput { swipeDown(centerY, bottom) }
+ rule.onNodeWithTag(mainLayoutTag).performTouchInput { swipeDown(centerY, bottom) }
rule.runOnIdle {
// swipe downs provide positive signed velocities
assertThat(sign(lastVelocity.y)).isEqualTo(1)
}
- rule.onNodeWithTag("mainLayout").performTouchInput { swipeDown(centerY, bottom) }
+ rule.onNodeWithTag(mainLayoutTag).performTouchInput { swipeDown(centerY, bottom) }
rule.runOnIdle {
// swipe downs provide positive signed velocities
assertThat(sign(lastVelocity.y)).isEqualTo(1)
@@ -1174,4 +1180,457 @@
assertThat(res).isEqualTo(preScrollReturn)
}
}
-}
\ No newline at end of file
+
+ @OptIn(ExperimentalTestApi::class)
+ @MediumTest
+ @Test
+ fun testPreScrollConsumption_verticalScrollMouse_postScrollAvailableIsZero() {
+ var preScrollCount = 0
+ var preScrollAvailableOffset = Offset.Zero
+
+ var postScrollCount = 0
+ var postScrollConsumedOffset = Offset.Zero
+ var postScrollAvailableOffset = Offset.Zero
+
+ val nestedScrollConnection = object : NestedScrollConnection {
+ override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
+ preScrollCount++
+ preScrollAvailableOffset = available
+
+ return available
+ }
+
+ override fun onPostScroll(
+ consumed: Offset,
+ available: Offset,
+ source: NestedScrollSource
+ ): Offset {
+ postScrollCount++
+ postScrollConsumedOffset = consumed
+ postScrollAvailableOffset = available
+
+ return super.onPostScroll(consumed, available, source)
+ }
+ }
+
+ rule.setContent {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .nestedScroll(connection = nestedScrollConnection)
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(80.dp)
+ )
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxWidth()
+ .testTag(mainLayoutTag)
+ .weight(1f)
+ ) {
+ items(100) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(60.dp)
+ .background(Color.Gray)
+ ) {
+ BasicText(text = it.toString())
+ }
+ Spacer(modifier = Modifier.height(8.dp))
+ }
+ }
+ }
+ }
+
+ // For the mouse scroll to work, you need to
+ // - 1. place the test tag directly on the LazyColumn
+ // - 2. Call moveTo() before scroll()
+ rule.onNodeWithTag(mainLayoutTag).performMouseInput {
+ moveTo(Offset.Zero)
+ scroll(100f)
+ }
+
+ rule.runOnIdle {
+ // Pre-Scroll checks
+ assertThat(preScrollCount).isGreaterThan(0)
+ assertFalse(preScrollAvailableOffset.customEquals(Offset.Zero))
+
+ // Post-Scroll checks
+ assertThat(postScrollCount).isGreaterThan(0)
+ assertTrue(postScrollConsumedOffset.customEquals(Offset.Zero))
+ assertTrue(postScrollAvailableOffset.customEquals(Offset.Zero))
+ }
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @MediumTest
+ @Test
+ fun testNoPreScrollConsumption_verticalScrollMouse_postScrollAvailableNotZero() {
+ var preScrollCount = 0
+ var preScrollAvailableOffset = Offset.Zero
+
+ var postScrollCount = 0
+ var postScrollConsumedOffset = Offset.Zero
+ var postScrollAvailableOffset = Offset.Zero
+
+ val nestedScrollConnection = object : NestedScrollConnection {
+ override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
+ preScrollCount++
+ preScrollAvailableOffset = available
+
+ return Offset.Zero
+ }
+
+ override fun onPostScroll(
+ consumed: Offset,
+ available: Offset,
+ source: NestedScrollSource
+ ): Offset {
+ postScrollCount++
+ postScrollConsumedOffset = consumed
+ postScrollAvailableOffset = available
+
+ return super.onPostScroll(consumed, available, source)
+ }
+ }
+
+ rule.setContent {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .nestedScroll(connection = nestedScrollConnection)
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(80.dp)
+ )
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxWidth()
+ .testTag(mainLayoutTag)
+ .weight(1f)
+ ) {
+ items(100) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(60.dp)
+ .background(Color.Gray)
+ ) {
+ BasicText(text = it.toString())
+ }
+ Spacer(modifier = Modifier.height(8.dp))
+ }
+ }
+ }
+ }
+
+ // For the mouse scroll to work, you need to
+ // - 1. place the test tag directly on the LazyColumn
+ // - 2. Call moveTo() before scroll()
+ rule.onNodeWithTag(mainLayoutTag).performMouseInput {
+ moveTo(Offset.Zero)
+ scroll(100f)
+ }
+
+ rule.runOnIdle {
+ // Pre-Scroll checks
+ assertThat(preScrollCount).isGreaterThan(0)
+ assertFalse(preScrollAvailableOffset.customEquals(Offset.Zero))
+
+ // Post-Scroll checks
+ assertThat(postScrollCount).isGreaterThan(0)
+ assertFalse(postScrollConsumedOffset.customEquals(Offset.Zero))
+ assertFalse(postScrollAvailableOffset.customEquals(Offset.Zero))
+ }
+ }
+
+ @MediumTest
+ @Test
+ fun testPreScrollConsumption_verticalSwipeUp_postScrollAvailableIsZero() {
+ var preScrollCount = 0
+ var preScrollAvailableOffset = Offset.Zero
+
+ var postScrollCount = 0
+ var postScrollConsumedOffset = Offset.Zero
+ var postScrollAvailableOffset = Offset.Zero
+
+ val nestedScrollConnection = object : NestedScrollConnection {
+ override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
+ preScrollCount++
+ preScrollAvailableOffset = available
+ // Pre-roll consumes full amount
+ return available
+ }
+
+ override fun onPostScroll(
+ consumed: Offset,
+ available: Offset,
+ source: NestedScrollSource
+ ): Offset {
+ postScrollCount++
+ postScrollConsumedOffset = consumed
+ postScrollAvailableOffset = available
+
+ return super.onPostScroll(consumed, available, source)
+ }
+ }
+
+ rule.setContent {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .nestedScroll(connection = nestedScrollConnection)
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(80.dp)
+ )
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxWidth()
+ .testTag(mainLayoutTag)
+ .weight(1f)
+ ) {
+ items(100) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(60.dp)
+ .background(Color.Gray)
+ ) {
+ BasicText(text = it.toString())
+ }
+ Spacer(modifier = Modifier.height(8.dp))
+ }
+ }
+ }
+ }
+
+ rule.onNodeWithTag(mainLayoutTag).performTouchInput { swipeUp(bottom, centerY) }
+
+ rule.runOnIdle {
+ // Pre-Scroll checks
+ assertThat(preScrollCount).isGreaterThan(0)
+ assertFalse(preScrollAvailableOffset.customEquals(Offset.Zero))
+
+ // Post-Scroll checks
+ assertThat(postScrollCount).isGreaterThan(0)
+ assertTrue(postScrollConsumedOffset.customEquals(Offset.Zero))
+ assertTrue(postScrollAvailableOffset.customEquals(Offset.Zero))
+ }
+ }
+
+ @MediumTest
+ @Test
+ fun testNoPreScrollConsumption_verticalSwipeUp_postScrollAvailableNotZero() {
+ var preScrollCount = 0
+ var preScrollAvailableOffset = Offset.Zero
+
+ var postScrollCount = 0
+ var postScrollConsumedOffset = Offset.Zero
+ var postScrollAvailableOffset = Offset.Zero
+
+ val nestedScrollConnection = object : NestedScrollConnection {
+ override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
+ preScrollCount++
+ preScrollAvailableOffset = available
+
+ return Offset.Zero
+ }
+
+ override fun onPostScroll(
+ consumed: Offset,
+ available: Offset,
+ source: NestedScrollSource
+ ): Offset {
+ postScrollCount++
+ postScrollConsumedOffset = consumed
+ postScrollAvailableOffset = available
+
+ return super.onPostScroll(consumed, available, source)
+ }
+ }
+
+ rule.setContent {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .nestedScroll(connection = nestedScrollConnection)
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(80.dp)
+ )
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxWidth()
+ .testTag(mainLayoutTag)
+ .weight(1f)
+ ) {
+ items(100) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(60.dp)
+ .background(Color.Gray)
+ ) {
+ BasicText(text = it.toString())
+ }
+ Spacer(modifier = Modifier.height(8.dp))
+ }
+ }
+ }
+ }
+
+ rule.onNodeWithTag(mainLayoutTag).performTouchInput { swipeUp(bottom, centerY) }
+
+ rule.runOnIdle {
+ // Pre-Scroll checks
+ assertThat(preScrollCount).isGreaterThan(0)
+ assertFalse(preScrollAvailableOffset.customEquals(Offset.Zero))
+
+ // Post-Scroll checks
+ assertThat(postScrollCount).isGreaterThan(0)
+ assertFalse(postScrollConsumedOffset.customEquals(Offset.Zero))
+ assertTrue(postScrollAvailableOffset.customEquals(Offset.Zero))
+ }
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @MediumTest
+ @Test
+ fun testFlingCallbacks_verticalScrollMouse_shouldNotTriggerCallbacks() {
+ var preFlingCount = 0
+ var postFlingCount = 0
+
+ val nestedScrollConnection = object : NestedScrollConnection {
+ override suspend fun onPreFling(available: Velocity): Velocity {
+ preFlingCount++
+ return super.onPreFling(available)
+ }
+
+ override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
+ postFlingCount++
+ return super.onPostFling(consumed, available)
+ }
+ }
+
+ rule.setContent {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .nestedScroll(connection = nestedScrollConnection)
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(80.dp)
+ )
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxWidth()
+ .testTag(mainLayoutTag)
+ .weight(1f)
+ ) {
+ items(100) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(60.dp)
+ .background(Color.Gray)
+ ) {
+ BasicText(text = it.toString())
+ }
+ Spacer(modifier = Modifier.height(8.dp))
+ }
+ }
+ }
+ }
+
+ // For the mouse scroll to work, you need to
+ // - 1. place the test tag directly on the LazyColumn
+ // - 2. Call moveTo() before scroll()
+ rule.onNodeWithTag(mainLayoutTag).performMouseInput {
+ moveTo(Offset.Zero)
+ scroll(100f)
+ }
+
+ rule.runOnIdle {
+ assertThat(preFlingCount).isEqualTo(0)
+ assertThat(postFlingCount).isEqualTo(0)
+ }
+ }
+
+ @MediumTest
+ @Test
+ fun testFlingCallbacks_verticalSwipeUp_shouldTriggerCallbacks() {
+ var preFlingCount = 0
+ var postFlingCount = 0
+
+ val nestedScrollConnection = object : NestedScrollConnection {
+ override suspend fun onPreFling(available: Velocity): Velocity {
+ preFlingCount++
+ return super.onPreFling(available)
+ }
+
+ override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
+ postFlingCount++
+ return super.onPostFling(consumed, available)
+ }
+ }
+
+ rule.setContent {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .nestedScroll(connection = nestedScrollConnection)
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(80.dp)
+ )
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxWidth()
+ .testTag(mainLayoutTag)
+ .weight(1f)
+ ) {
+ items(100) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(60.dp)
+ .background(Color.Gray)
+ ) {
+ BasicText(text = it.toString())
+ }
+ Spacer(modifier = Modifier.height(8.dp))
+ }
+ }
+ }
+ }
+
+ rule.onNodeWithTag(mainLayoutTag).performTouchInput { swipeUp(bottom, centerY) }
+
+ rule.runOnIdle {
+ assertThat(preFlingCount).isGreaterThan(0)
+ assertThat(postFlingCount).isGreaterThan(0)
+ }
+ }
+}
+
+private fun Offset.customEquals(other: Offset): Boolean {
+ return if (other == Offset.Zero || this == Offset.Zero) {
+ abs(this.x) == abs(other.x) && abs(this.y) == abs(other.y)
+ } else {
+ this == other
+ }
+}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
index 4bc3f57..4cb91c7 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
@@ -73,6 +73,7 @@
import com.google.common.truth.Truth.assertWithMessage
import java.util.concurrent.Executors
import kotlin.coroutines.CoroutineContext
+import kotlin.test.assertEquals
import kotlinx.coroutines.asCoroutineDispatcher
import org.junit.Before
import org.junit.Test
@@ -501,7 +502,7 @@
hitPathTracker.dispatchChanges(internalPointerEvent)
PointerInputChangeSubject
- .assertThat(internalPointerEvent.changes.values.first())
+ .assertThat(internalPointerEvent.changes.valueAt(0))
.isStructurallyEqualTo(down(5))
}
@@ -523,7 +524,7 @@
hitPathTracker.dispatchChanges(internalPointerEvent)
PointerInputChangeSubject
- .assertThat(internalPointerEvent.changes.values.first())
+ .assertThat(internalPointerEvent.changes.valueAt(0))
.isStructurallyEqualTo(down(13).apply { if (pressed != previousPressed) consume() })
}
@@ -629,7 +630,7 @@
assertThat(log1[5].pass).isEqualTo(PointerEventPass.Main)
PointerInputChangeSubject
- .assertThat(internalPointerEvent.changes.values.first())
+ .assertThat(internalPointerEvent.changes.valueAt(0))
.isStructurallyEqualTo(
consumedExpectedChange
)
@@ -771,14 +772,14 @@
)
assertThat(log2[3].pass).isEqualTo(PointerEventPass.Main)
- assertThat(internalPointerEvent.changes).hasSize(2)
+ assertEquals(2, internalPointerEvent.changes.size())
PointerInputChangeSubject
- .assertThat(internalPointerEvent.changes[actualEvent1.id])
+ .assertThat(internalPointerEvent.changes[actualEvent1.id.value])
.isStructurallyEqualTo(
consumedExpectedEvent1
)
PointerInputChangeSubject
- .assertThat(internalPointerEvent.changes[actualEvent2.id])
+ .assertThat(internalPointerEvent.changes[actualEvent2.id.value])
.isStructurallyEqualTo(
consumedExpectedEvent2
)
@@ -882,13 +883,13 @@
)
assertThat(log1[5].pass).isEqualTo(PointerEventPass.Main)
- assertThat(internalPointerEvent.changes).hasSize(2)
+ assertEquals(2, internalPointerEvent.changes.size())
PointerInputChangeSubject
- .assertThat(internalPointerEvent.changes[actualEvent1.id])
+ .assertThat(internalPointerEvent.changes[actualEvent1.id.value])
.isStructurallyEqualTo(consumedEvent1)
PointerInputChangeSubject
- .assertThat(internalPointerEvent.changes[actualEvent2.id])
+ .assertThat(internalPointerEvent.changes[actualEvent2.id.value])
.isStructurallyEqualTo(consumedEvent2)
}
@@ -971,14 +972,14 @@
)
assertThat(log1[3].pass).isEqualTo(PointerEventPass.Main)
- assertThat(internalPointerEvent.changes).hasSize(2)
+ assertEquals(2, internalPointerEvent.changes.size())
PointerInputChangeSubject
- .assertThat(internalPointerEvent.changes[actualEvent1.id])
+ .assertThat(internalPointerEvent.changes[actualEvent1.id.value])
.isStructurallyEqualTo(
consumedEvent1
)
PointerInputChangeSubject
- .assertThat(internalPointerEvent.changes[actualEvent2.id])
+ .assertThat(internalPointerEvent.changes[actualEvent2.id.value])
.isStructurallyEqualTo(
consumedEvent2
)
@@ -3537,8 +3538,8 @@
return false
}
var check = true
- actualNode.pointerIds.forEach {
- check = check && expectedNode.pointerIds.contains(it)
+ for (i in 0 until actualNode.pointerIds.size) {
+ check = check && expectedNode.pointerIds.contains(actualNode.pointerIds[i])
}
if (!check) {
return false
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInteropUtilsTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInteropUtilsTest.kt
index 98174bf..8e875e7 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInteropUtilsTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInteropUtilsTest.kt
@@ -18,6 +18,7 @@
import android.view.MotionEvent
import android.view.View
+import androidx.collection.LongSparseArray
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.gesture.PointerCoords
import androidx.compose.ui.gesture.PointerProperties
@@ -577,7 +578,14 @@
changes: List<PointerInputChange>,
motionEvent: MotionEvent
): PointerEvent {
- val changesMap = changes.map { it.id to it }.toMap()
- val internalPointerEvent = InternalPointerEvent(changesMap, motionEvent)
+ val internalPointerEvent = InternalPointerEvent(changes.toLongSparseArray(), motionEvent)
return PointerEvent(changes, internalPointerEvent)
-}
\ No newline at end of file
+}
+
+fun List<PointerInputChange>.toLongSparseArray(): LongSparseArray<PointerInputChange> {
+ val returnArray = LongSparseArray<PointerInputChange>(this.count())
+ for (change in this) {
+ returnArray.put(change.id.value, change)
+ }
+ return returnArray
+}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/TestUtils.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/TestUtils.kt
index fb92e8f..675867d 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/TestUtils.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/TestUtils.kt
@@ -22,6 +22,7 @@
import android.view.MotionEvent.ACTION_HOVER_MOVE
import android.view.MotionEvent.ACTION_UP
import android.view.View
+import androidx.collection.LongSparseArray
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@@ -252,23 +253,35 @@
motionEvent: MotionEvent = MotionEventDouble
) = PointerEvent(
changes.toList(),
- InternalPointerEvent(changes.map { it.id to it }.toMap(), motionEvent)
+ InternalPointerEvent(changes.toLongSparseArray(), motionEvent)
)
+fun Array<out PointerInputChange>.toLongSparseArray(): LongSparseArray<PointerInputChange> {
+ val returnArray = LongSparseArray<PointerInputChange>(this.count())
+ for (change in this) {
+ returnArray.put(change.id.value, change)
+ }
+ return returnArray
+}
+
internal fun InternalPointerEvent(
- changes: Map<PointerId, PointerInputChange>,
+ changes: LongSparseArray<PointerInputChange>,
motionEvent: MotionEvent
): InternalPointerEvent {
- val pointers = changes.values.map {
- @OptIn(ExperimentalComposeUiApi::class)
- PointerInputEventData(
- id = it.id,
- uptime = it.uptimeMillis,
- positionOnScreen = it.position,
- position = it.position,
- down = it.pressed,
- pressure = it.pressure,
- type = it.type
+ val pointers = mutableListOf<PointerInputEventData>()
+ for (i in 0 until changes.size()) {
+ val data = changes.valueAt(i)
+ pointers.add(
+ @OptIn(ExperimentalComposeUiApi::class)
+ PointerInputEventData(
+ id = data.id,
+ uptime = data.uptimeMillis,
+ positionOnScreen = data.position,
+ position = data.position,
+ down = data.pressed,
+ pressure = data.pressure,
+ type = data.type
+ )
)
}
val pointer = PointerInputEvent(pointers[0].uptime, pointers, motionEvent)
@@ -407,7 +420,7 @@
)
}
val pointerEvent = PointerInputEvent(0L, pointers, event)
- return InternalPointerEvent(changes.toList().associateBy { it.id }.toMutableMap(), pointerEvent)
+ return InternalPointerEvent(changes.toLongSparseArray(), pointerEvent)
}
internal fun hoverInternalPointerEvent(
@@ -441,8 +454,10 @@
)
val pointerEvent = PointerInputEvent(0L, listOf(pointer), createHoverMotionEvent(action, x, y))
+ val pointerArray = LongSparseArray<PointerInputChange>(1)
+ pointerArray.put(change.id.value, change)
return InternalPointerEvent(
- mutableMapOf(change.id to change),
+ pointerArray,
pointerEvent
)
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/Helpers.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/Helpers.kt
index b481e69..8e4d1a2 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/Helpers.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/Helpers.kt
@@ -47,7 +47,6 @@
import androidx.compose.ui.platform.TextToolbar
import androidx.compose.ui.platform.ViewConfiguration
import androidx.compose.ui.platform.WindowInfo
-import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.PlatformTextInputPluginRegistry
@@ -159,7 +158,6 @@
get() = TODO("Not yet implemented")
override val textInputService: TextInputService
get() = TODO("Not yet implemented")
- @OptIn(ExperimentalTextApi::class)
override val platformTextInputPluginRegistry: PlatformTextInputPluginRegistry
get() = TODO("Not yet implemented")
override val pointerIconService: PointerIconService
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LayoutCooperationTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LayoutCooperationTest.kt
index 154f1fd..e91f316 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LayoutCooperationTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LayoutCooperationTest.kt
@@ -29,9 +29,12 @@
import androidx.compose.ui.background
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.assertLeftPositionInRootIsEqualTo
+import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
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.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
@@ -52,8 +55,14 @@
val size = 48
var initialOuterSize by mutableStateOf((size / 2).toDp())
rule.setContent {
- Box(Modifier.size(initialOuterSize).testTag("outer")) {
- Box(Modifier.requiredSize(size.toDp()).background(Color.Yellow))
+ Box(
+ Modifier
+ .size(initialOuterSize)
+ .testTag("outer")) {
+ Box(
+ Modifier
+ .requiredSize(size.toDp())
+ .background(Color.Yellow))
}
}
@@ -65,4 +74,45 @@
Color.Yellow
}
}
+
+ @Test
+ fun relayoutSkippingModifiersDoesntBreakCooperation() {
+ with(rule.density) {
+ val containerSize = 100
+ val width = 50
+ val widthDp = width.toDp()
+ val height = 40
+ val heightDp = height.toDp()
+ var offset by mutableStateOf(0)
+ rule.setContent {
+ Layout(content = {
+ Box(Modifier.requiredSize(widthDp, heightDp)) {
+ Box(Modifier.testTag("child"))
+ }
+ }) { measurables, _ ->
+ val placeable =
+ measurables.first().measure(Constraints.fixed(containerSize, containerSize))
+ layout(containerSize, containerSize) {
+ placeable.place(offset, offset)
+ }
+ }
+ }
+
+ var expectedTop = ((containerSize - height) / 2).toDp()
+ var expectedLeft = ((containerSize - width) / 2).toDp()
+ rule.onNodeWithTag("child")
+ .assertTopPositionInRootIsEqualTo(expectedTop)
+ .assertLeftPositionInRootIsEqualTo(expectedLeft)
+
+ rule.runOnIdle {
+ offset = 10
+ }
+
+ expectedTop += offset.toDp()
+ expectedLeft += offset.toDp()
+ rule.onNodeWithTag("child")
+ .assertTopPositionInRootIsEqualTo(expectedTop)
+ .assertLeftPositionInRootIsEqualTo(expectedLeft)
+ }
+ }
}
\ No newline at end of file
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 942c141..a1e73ac 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
@@ -1716,6 +1716,7 @@
repeat(3) { id ->
subcompose(id) {
Box(Modifier.trackMainPassPlacement {
+ iteration.toString() // state read to make callback called
actualPlacementOrder.add(id)
})
}.fastMap { it.measure(constraints) }.let { placeables.addAll(it) }
@@ -1726,6 +1727,7 @@
val id = index + 3
subcompose(id) {
Box(Modifier.trackMainPassPlacement {
+ iteration.toString() // state read to make callback called
actualPlacementOrder.add(id)
})
}.fastMap { it.measure(constraints) }.let { allPlaceables.addAll(it) }
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/OnGloballyPositionedTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/OnGloballyPositionedTest.kt
index d0c65cd..e49bbc4a 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/OnGloballyPositionedTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/OnGloballyPositionedTest.kt
@@ -16,12 +16,15 @@
package androidx.compose.ui.layout
+import android.os.SystemClock
+import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.ScrollView
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.size
@@ -53,6 +56,7 @@
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -1051,6 +1055,62 @@
assertFalse(coordindates.isAttached)
}
}
+
+ // In some special circumstances, the onGloballyPositioned callbacks can be called recursively
+ // and they shouldn't crash when that happens. This tests a pointer event causing an
+ // onGloballyPositioned callback while processing the onGloballyPositioned.
+ @Test
+ fun recurseGloballyPositionedCallback() {
+ val view = rule.activity.findViewById<View>(android.R.id.content)
+ var offset by mutableStateOf(IntOffset.Zero)
+ var position = Offset.Unspecified
+ var hasSent = false
+ rule.setContent {
+ Box(Modifier.fillMaxSize()) {
+ Box(Modifier.fillMaxSize().offset { offset }.onGloballyPositioned {
+ if (offset != IntOffset.Zero) {
+ position = it.positionInRoot()
+ }
+ })
+ Box(Modifier.fillMaxSize().offset { offset }.onGloballyPositioned {
+ if (offset != IntOffset.Zero && !hasSent) {
+ hasSent = true
+ val now = SystemClock.uptimeMillis()
+ val event = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+ view.dispatchTouchEvent(event)
+ }
+ })
+ }
+ }
+ rule.runOnIdle {
+ offset = IntOffset(1, 1)
+ }
+ rule.runOnIdle {
+ assertThat(position).isEqualTo(Offset(1f, 1f))
+ }
+ }
+
+ @Test
+ fun lotsOfNotifications() {
+ // have more than 16 OnGloballyPositioned liseteners to test listener cache
+ var offset by mutableStateOf(IntOffset.Zero)
+ var position = Offset.Unspecified
+ rule.setContent {
+ Box(Modifier.fillMaxSize()) {
+ repeat(30) {
+ Box(Modifier.fillMaxSize().offset { offset }.onGloballyPositioned {
+ position = it.positionInRoot()
+ })
+ }
+ }
+ }
+ rule.runOnIdle {
+ offset = IntOffset(1, 1)
+ }
+ rule.runOnIdle {
+ assertThat(position).isEqualTo(Offset(1f, 1f))
+ }
+ }
}
@Composable
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/PlacementLayoutCoordinatesTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/PlacementLayoutCoordinatesTest.kt
index f655381..ca5805c 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/PlacementLayoutCoordinatesTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/PlacementLayoutCoordinatesTest.kt
@@ -257,7 +257,7 @@
Layout(content, Modifier.alignByBaseline()) { measurables, constraints ->
val p = measurables[0].measure(constraints)
layout(p.width, p.height) {
- locations += coordinates
+ locations += coordinates.use()
p.place(0, 0)
}
}
@@ -287,7 +287,7 @@
Layout(content, Modifier.alignByBaseline()) { measurables, constraints ->
val p = measurables[0].measure(constraints)
layout(p.width, p.height) {
- locations += coordinates
+ locations += coordinates.use()
p.place(0, 0)
}
}
@@ -329,7 +329,7 @@
}) { measurables, constraints ->
val p = measurables[0].measure(constraints)
layout(p.width, p.height) {
- locations += coordinates
+ locations += coordinates.use()
p.place(0, 0)
}
}
@@ -343,7 +343,7 @@
}
@Test
- fun parentCoordateChangeCausesRelayout() {
+ fun parentCoordinateChangeCausesRelayout() {
val locations = mutableStateListOf<LayoutCoordinates?>()
var offset by mutableStateOf(DpOffset(0.dp, 0.dp))
rule.setContent {
@@ -354,7 +354,7 @@
.layout { measurable, constraints ->
val p = measurable.measure(constraints)
layout(p.width, p.height) {
- locations += coordinates
+ locations += coordinates.use()
p.place(0, 0)
}
}
@@ -386,7 +386,7 @@
.layout { measurable, constraints ->
val p = measurable.measure(constraints)
layout(p.width, p.height) {
- locations += coordinates
+ locations += coordinates.use()
p.place(0, 0)
}
}
@@ -422,7 +422,7 @@
.layout { measurable, constraints ->
val p = measurable.measure(constraints)
layout(p.width, p.height) {
- locations += coordinates
+ locations += coordinates.use()
p.place(0, 0)
}
}
@@ -459,7 +459,8 @@
.layout { measurable, constraints ->
val p = measurable.measure(constraints)
layout(p.width, p.height) {
- layoutCalls += if (readCoordinates) coordinates else null
+ layoutCalls +=
+ if (readCoordinates) coordinates.use() else null
p.place(0, 0)
}
}
@@ -507,7 +508,7 @@
.layout { measurable, constraints ->
val p = measurable.measure(constraints)
layout(p.width, p.height) {
- locations += coordinates
+ locations += coordinates.use()
p.place(0, 0)
}
}
@@ -568,7 +569,7 @@
.layout { measurable, constraints ->
val p = measurable.measure(constraints)
layout(p.width, p.height) {
- locations += coordinates
+ locations += coordinates.use()
p.place(0, 0)
}
}
@@ -604,7 +605,7 @@
.layout { measurable, constraints ->
val p = measurable.measure(constraints)
layout(p.width, p.height) {
- locations += coordinates
+ locations += coordinates.use()
p.place(0, 0)
}
}
@@ -634,7 +635,7 @@
.layout { measurable, constraints ->
val p = measurable.measure(constraints)
layout(p.width, p.height) {
- locations += coordinates
+ locations += coordinates.use()
p.place(0, 0)
}
}
@@ -668,4 +669,235 @@
rule.waitForIdle()
assertEquals(1, locations.size)
}
+
+ @Test
+ fun readingFromMainLayoutPolicyAfterMultipleMoves() {
+ var offset by mutableStateOf(0)
+ var layoutBlockCalls = 0
+ rule.setContent {
+ Layout(content = {
+ Layout { _, _ ->
+ layout(10, 10) {
+ coordinates?.positionInParent()
+ layoutBlockCalls++
+ }
+ }
+ }) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ layout(placeable.width, placeable.height) {
+ placeable.place(offset, 0)
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ layoutBlockCalls = 0
+ offset = 1
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, layoutBlockCalls)
+ layoutBlockCalls = 0
+ offset = 2
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, layoutBlockCalls)
+ }
+ }
+
+ @Test
+ fun onlyRealPositionReadsTriggerRelayout() {
+ var offset by mutableStateOf(0)
+ var coordinatesAction: (LayoutCoordinates) -> Unit by mutableStateOf({})
+ var layoutBlockCalls = 0
+ rule.setContent {
+ Layout(content = {
+ Layout { _, _ ->
+ layout(10, 10) {
+ coordinates?.let(coordinatesAction)
+ layoutBlockCalls++
+ }
+ }
+ }) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ layout(placeable.width, placeable.height) {
+ placeable.place(offset, 0)
+ }
+ }
+ }
+
+ fun assert(
+ relayoutExpected: Boolean,
+ description: String,
+ action: (LayoutCoordinates) -> Unit
+ ) {
+ coordinatesAction = action
+ rule.runOnIdle {
+ layoutBlockCalls = 0
+ offset = if (offset == 0) 10 else 0
+ }
+ rule.runOnIdle {
+ assertEquals(
+ "Relayout because of `$description` read was " +
+ "${if (!relayoutExpected) " not" else ""} expected, but " +
+ "$layoutBlockCalls calls happened",
+ if (relayoutExpected) 1 else 0,
+ layoutBlockCalls
+ )
+ }
+ }
+
+ assert(relayoutExpected = true, "positionInParent()") { it.positionInParent() }
+ assert(relayoutExpected = true, "positionInRoot()") { it.positionInRoot() }
+ assert(relayoutExpected = true, "positionInWindow()") { it.positionInWindow() }
+ assert(relayoutExpected = true, "boundsInParent()") { it.boundsInParent() }
+ assert(relayoutExpected = true, "boundsInRoot()") { it.boundsInRoot() }
+ assert(relayoutExpected = true, "boundsInWindow()") { it.boundsInWindow() }
+
+ assert(relayoutExpected = false, "empty") { }
+ assert(relayoutExpected = false, "size") { it.size }
+ assert(relayoutExpected = false, "isAttached") { it.isAttached }
+ assert(relayoutExpected = false, "providedAlignmentLines") { it.providedAlignmentLines }
+ }
+
+ @Test
+ fun onlyRealPositionReadsTriggerRelayout_inModifier() {
+ var offset by mutableStateOf(0)
+ var coordinatesAction: (LayoutCoordinates) -> Unit by mutableStateOf({})
+ var layoutBlockCalls = 0
+ rule.setContent {
+ Layout(content = {
+ Box(
+ Modifier
+ .layout { measurable, constraints ->
+ val p = measurable.measure(constraints)
+ layout(p.width, p.height) {
+ coordinates?.let(coordinatesAction)
+ layoutBlockCalls++
+ p.place(0, 0)
+ }
+ }
+ )
+ }) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ layout(placeable.width, placeable.height) {
+ placeable.place(offset, 0)
+ }
+ }
+ }
+
+ fun assert(
+ relayoutExpected: Boolean,
+ description: String,
+ action: (LayoutCoordinates) -> Unit
+ ) {
+ coordinatesAction = action
+ rule.runOnIdle {
+ layoutBlockCalls = 0
+ offset = if (offset == 0) 10 else 0
+ }
+ rule.runOnIdle {
+ assertEquals(
+ "Relayout because of `$description` read was " +
+ "${if (!relayoutExpected) " not" else ""} expected, but " +
+ "$layoutBlockCalls calls happened",
+ if (relayoutExpected) 1 else 0,
+ layoutBlockCalls
+ )
+ }
+ }
+
+ assert(relayoutExpected = true, "positionInParent()") { it.positionInParent() }
+ assert(relayoutExpected = true, "positionInRoot()") { it.positionInRoot() }
+ assert(relayoutExpected = true, "positionInWindow()") { it.positionInWindow() }
+ assert(relayoutExpected = true, "boundsInParent()") { it.boundsInParent() }
+ assert(relayoutExpected = true, "boundsInRoot()") { it.boundsInRoot() }
+ assert(relayoutExpected = true, "boundsInWindow()") { it.boundsInWindow() }
+
+ assert(relayoutExpected = false, "empty") { }
+ assert(relayoutExpected = false, "size") { it.size }
+ assert(relayoutExpected = false, "isAttached") { it.isAttached }
+ assert(relayoutExpected = false, "providedAlignmentLines") { it.providedAlignmentLines }
+ }
+
+ @OptIn(ExperimentalComposeUiApi::class)
+ @Test
+ fun onlyRealPositionReadsTriggerRelayout_inLookahead() {
+ var offset by mutableStateOf(0)
+ var coordinatesAction: (LayoutCoordinates) -> Unit by mutableStateOf({})
+ var intermediateLayoutBlockCalls = 0
+ rule.setContent {
+ LookaheadScope {
+ Layout(content = {
+ Box(
+ Modifier
+ .intermediateLayout { measurable, constraints ->
+ val p = measurable.measure(constraints)
+ layout(p.width, p.height) {
+ coordinates?.let(coordinatesAction)
+ intermediateLayoutBlockCalls++
+ p.place(0, 0)
+ }
+ }
+ .layout { measurable, constraints ->
+ val p = measurable.measure(constraints)
+ layout(10, 10) {
+ // if we don't read the coordinates here as well
+ // the read of coordinates in intermediate layout could be
+ // skipped as both passes share the same
+ // coordinatesAccessedDuringPlacement property.
+ // filed b/284153462 to track this issue
+ coordinates?.let(coordinatesAction)
+ p.place(0, 0)
+ }
+ }
+ )
+ }) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ layout(placeable.width, placeable.height) {
+ placeable.place(offset, 0)
+ }
+ }
+ }
+ }
+
+ fun assert(
+ relayoutExpected: Boolean,
+ description: String,
+ action: (LayoutCoordinates) -> Unit
+ ) {
+ coordinatesAction = action
+ rule.runOnIdle {
+ intermediateLayoutBlockCalls = 0
+ offset = if (offset == 0) 10 else 0
+ }
+ rule.runOnIdle {
+ assertEquals(
+ "Relayout because of `$description` read was " +
+ "${if (!relayoutExpected) " not" else ""} expected, but " +
+ "$intermediateLayoutBlockCalls calls happened",
+ if (relayoutExpected) 1 else 0,
+ intermediateLayoutBlockCalls
+ )
+ }
+ }
+
+ assert(relayoutExpected = true, "positionInParent()") { it.positionInParent() }
+ assert(relayoutExpected = true, "positionInRoot()") { it.positionInRoot() }
+ assert(relayoutExpected = true, "positionInWindow()") { it.positionInWindow() }
+ assert(relayoutExpected = true, "boundsInParent()") { it.boundsInParent() }
+ assert(relayoutExpected = true, "boundsInRoot()") { it.boundsInRoot() }
+ assert(relayoutExpected = true, "boundsInWindow()") { it.boundsInWindow() }
+
+ assert(relayoutExpected = false, "empty") { }
+ assert(relayoutExpected = false, "size") { it.size }
+ assert(relayoutExpected = false, "isAttached") { it.isAttached }
+ assert(relayoutExpected = false, "providedAlignmentLines") { it.providedAlignmentLines }
+ }
+}
+
+private fun LayoutCoordinates?.use(): LayoutCoordinates? {
+ this?.parentCoordinates
+ return this
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/ResizingComposeViewTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/ResizingComposeViewTest.kt
index d8d73e7..6d07ce6 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/ResizingComposeViewTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/ResizingComposeViewTest.kt
@@ -40,6 +40,7 @@
import kotlin.math.roundToInt
import org.junit.Assert
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
@@ -263,6 +264,7 @@
awaitDrawAndAssertSizes()
}
+ @Ignore // b/284402894
@Test
fun whenForceRemeasureCalledAndSizeChanged() {
var childHeight by mutableStateOf(10)
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/CompositionLocalMapInjectionTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/CompositionLocalMapInjectionTest.kt
index b677ada..d64b638 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/CompositionLocalMapInjectionTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/CompositionLocalMapInjectionTest.kt
@@ -24,9 +24,11 @@
import androidx.compose.runtime.ReusableComposeNode
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.currentComposer
+import androidx.compose.runtime.currentCompositeKeyHash
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.UiComposable
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
@@ -37,6 +39,12 @@
import androidx.compose.ui.layout.materializerOfWithCompositionLocalInjection
import androidx.compose.ui.materializeWithCompositionLocalInjectionInternal
import androidx.compose.ui.node.ComposeUiNode
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetCompositeKeyHash
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetDensity
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetLayoutDirection
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetMeasurePolicy
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetModifier
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetViewConfiguration
import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
import androidx.compose.ui.node.DrawModifierNode
import androidx.compose.ui.node.LayoutModifierNode
@@ -292,6 +300,7 @@
modifier: Modifier = Modifier,
measurePolicy: MeasurePolicy
) {
+ val compositeKeyHash = currentCompositeKeyHash
val density = LocalDensity.current
val layoutDirection = LocalLayoutDirection.current
val viewConfiguration = LocalViewConfiguration.current
@@ -299,10 +308,12 @@
ReusableComposeNode<ComposeUiNode, Applier<Any>>(
factory = ComposeUiNode.Constructor,
update = {
- set(measurePolicy, ComposeUiNode.SetMeasurePolicy)
- set(density, ComposeUiNode.SetDensity)
- set(layoutDirection, ComposeUiNode.SetLayoutDirection)
- set(viewConfiguration, ComposeUiNode.SetViewConfiguration)
+ set(measurePolicy, SetMeasurePolicy)
+ set(density, SetDensity)
+ set(layoutDirection, SetLayoutDirection)
+ set(viewConfiguration, SetViewConfiguration)
+ @OptIn(ExperimentalComposeUiApi::class)
+ set(compositeKeyHash, SetCompositeKeyHash)
},
// The old version of Layout called a function called "materializerOf". The function below
// has the same JVM signature as that function used to have, so the code that this source
@@ -320,6 +331,7 @@
modifier: Modifier = Modifier,
measurePolicy: MeasurePolicy
) {
+ val compositeKeyHash = currentCompositeKeyHash
val density = LocalDensity.current
val layoutDirection = LocalLayoutDirection.current
val viewConfiguration = LocalViewConfiguration.current
@@ -331,11 +343,13 @@
ReusableComposeNode<ComposeUiNode, Applier<Any>>(
factory = ComposeUiNode.Constructor,
update = {
- set(measurePolicy, ComposeUiNode.SetMeasurePolicy)
- set(density, ComposeUiNode.SetDensity)
- set(layoutDirection, ComposeUiNode.SetLayoutDirection)
- set(viewConfiguration, ComposeUiNode.SetViewConfiguration)
- set(materialized, ComposeUiNode.SetModifier)
+ set(measurePolicy, SetMeasurePolicy)
+ set(density, SetDensity)
+ set(layoutDirection, SetLayoutDirection)
+ set(viewConfiguration, SetViewConfiguration)
+ set(materialized, SetModifier)
+ @OptIn(ExperimentalComposeUiApi::class)
+ set(compositeKeyHash, SetCompositeKeyHash)
},
)
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/ModifierNodeReuseAndDeactivationTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/ModifierNodeReuseAndDeactivationTest.kt
index 0b0714d..3e5cb7f 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/ModifierNodeReuseAndDeactivationTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/ModifierNodeReuseAndDeactivationTest.kt
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-@file:OptIn(ExperimentalComposeUiApi::class)
-
package androidx.compose.ui.modifier
import androidx.compose.runtime.Applier
@@ -792,6 +790,7 @@
rule.setContent {
ReusableContentHost(active) {
ReusableContent(0) {
+ @OptIn(ExperimentalComposeUiApi::class)
Layout(
modifier = Modifier
.modifierLocalProvider(key) { providedValue }
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/node/CompositeKeyHashTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/node/CompositeKeyHashTest.kt
new file mode 100644
index 0000000..a58e3c4
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/node/CompositeKeyHashTest.kt
@@ -0,0 +1,403 @@
+/*
+ * 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.node
+
+import android.widget.TextView
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.text.BasicText
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.key
+import androidx.compose.runtime.remember
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.MultiMeasureLayout
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.test.ext.junit.runners.AndroidJUnit4
+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
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalComposeUiApi::class)
+class CompositeKeyHashTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun nonZeroCompositeKeyHash() {
+ // Arrange.
+ val node = object : Modifier.Node() {}
+ rule.setContent {
+ Box(Modifier.elementOf(node))
+ }
+
+ // Act.
+ val compositeKeyHash = rule.runOnIdle { node.requireLayoutNode().compositeKeyHash }
+
+ // Assert.
+ assertThat(compositeKeyHash).isNotEqualTo(0)
+ }
+
+ @Test
+ fun parentAndChildLayoutNodesHaveDifferentCompositeKeyHashes() {
+ // Arrange.
+ val (parent, child) = List(3) { object : Modifier.Node() {} }
+ rule.setContent {
+ Box(Modifier.elementOf(parent)) {
+ Box(Modifier.elementOf(child))
+ }
+ }
+
+ // Act.
+ rule.waitForIdle()
+ val parentCompositeKeyHash = parent.requireLayoutNode().compositeKeyHash
+ val childCompositeKeyHash = child.requireLayoutNode().compositeKeyHash
+
+ // Assert.
+ assertThat(parentCompositeKeyHash).isNotEqualTo(childCompositeKeyHash)
+ }
+
+ @Test
+ fun differentChildrenHaveSameCompositeKeyHashes_Row() {
+ // Arrange.
+ val (node1, node2) = List(3) { object : Modifier.Node() {} }
+ rule.setContent {
+ Row {
+ Box(Modifier.elementOf(node1))
+ Box(Modifier.elementOf(node2))
+ }
+ }
+
+ // Act.
+ rule.waitForIdle()
+ val compositeKeyHash1 = node1.requireLayoutNode().compositeKeyHash
+ val compositeKeyHash2 = node2.requireLayoutNode().compositeKeyHash
+
+ // Assert.
+ assertThat(compositeKeyHash1).isEqualTo(compositeKeyHash2)
+ }
+
+ @Test
+ fun differentChildrenWithKeyHaveDifferentCompositeKeyHashes_Row() {
+ // Arrange.
+ val (node1, node2) = List(3) { object : Modifier.Node() {} }
+ rule.setContent {
+ Row {
+ key(1) {
+ Box(Modifier.elementOf(node1))
+ }
+ key(2) {
+ Box(Modifier.elementOf(node2))
+ }
+ }
+ }
+
+ // Act.
+ rule.waitForIdle()
+ val compositeKeyHash1 = node1.requireLayoutNode().compositeKeyHash
+ val compositeKeyHash2 = node2.requireLayoutNode().compositeKeyHash
+
+ // Assert.
+ assertThat(compositeKeyHash1).isNotEqualTo(compositeKeyHash2)
+ }
+ @Test
+ fun differentChildrenHaveSameCompositeKeyHashes_Box() {
+ // Arrange.
+ val (node1, node2) = List(2) { object : Modifier.Node() {} }
+ rule.setContent {
+ Box {
+ Box(Modifier.elementOf(node1))
+ Box(Modifier.elementOf(node2))
+ }
+ }
+
+ // Act.
+ rule.waitForIdle()
+ val compositeKeyHash1 = node1.requireLayoutNode().compositeKeyHash
+ val compositeKeyHash2 = node2.requireLayoutNode().compositeKeyHash
+
+ // Assert.
+ assertThat(compositeKeyHash1).isEqualTo(compositeKeyHash2)
+ }
+
+ @Test
+ fun differentChildrenWithKeysHaveDifferentCompositeKeyHashes_Box() {
+ // Arrange.
+ val (node1, node2) = List(2) { object : Modifier.Node() {} }
+ rule.setContent {
+ Box {
+ key(1) {
+ Box(Modifier.elementOf(node1))
+ }
+ key(2) {
+ Box(Modifier.elementOf(node2))
+ }
+ }
+ }
+
+ // Act.
+ rule.waitForIdle()
+ val compositeKeyHash1 = node1.requireLayoutNode().compositeKeyHash
+ val compositeKeyHash2 = node2.requireLayoutNode().compositeKeyHash
+
+ // Assert.
+ assertThat(compositeKeyHash1).isNotEqualTo(compositeKeyHash2)
+ }
+
+ @Test
+ fun differentChildrenInLazyColumn_item() {
+ // Arrange.
+ val (node1, node2) = List(2) { object : Modifier.Node() {} }
+ rule.setContent {
+ LazyColumn {
+ item {
+ Box(Modifier.elementOf(node1))
+ }
+ item {
+ Box(Modifier.elementOf(node2))
+ }
+ }
+ }
+
+ // Act.
+ rule.waitForIdle()
+ val compositeKeyHash1 = node1.requireLayoutNode().compositeKeyHash
+ val compositeKeyHash2 = node2.requireLayoutNode().compositeKeyHash
+
+ // Assert.
+ assertThat(compositeKeyHash1).isNotEqualTo(compositeKeyHash2)
+ }
+
+ @Test
+ fun differentChildrenInLazyColumn_Items() {
+ // Arrange.
+ val (node1, node2) = List(2) { object : Modifier.Node() {} }
+ rule.setContent {
+ LazyColumn {
+ items(2) {
+ Box(Modifier.elementOf(if (it == 0) node1 else node2))
+ }
+ }
+ }
+
+ // Act.
+ rule.waitForIdle()
+ val compositionKeyHash1 = node1.requireLayoutNode().compositeKeyHash
+ val compositionKeyHash2 = node2.requireLayoutNode().compositeKeyHash
+
+ // Assert.
+ assertThat(compositionKeyHash1).isNotEqualTo(compositionKeyHash2)
+ }
+
+ @Test
+ fun text() {
+ // Arrange.
+ val node = object : Modifier.Node() {}
+ rule.setContent {
+ BasicText(
+ text = "text",
+ modifier = Modifier.elementOf(node),
+ )
+ }
+
+ // Act.
+ val compositeKeyHash = rule.runOnIdle { node.requireLayoutNode().compositeKeyHash }
+
+ // Assert.
+ assertThat(compositeKeyHash).isNotEqualTo(0)
+ }
+
+ @Test
+ fun androidView() {
+ // Arrange.
+ val node = object : Modifier.Node() {}
+ rule.setContent {
+ AndroidView(
+ factory = { TextView(it) },
+ modifier = Modifier.elementOf(node)
+ )
+ }
+
+ // Act.
+ val compositeKeyHash = rule.runOnIdle { node.requireLayoutNode().compositeKeyHash }
+
+ // Assert.
+ assertThat(compositeKeyHash).isNotEqualTo(0)
+ }
+
+ @Test
+ fun androidView_noOnReset() {
+ // Arrange.
+ val node = object : Modifier.Node() {}
+ rule.setContent {
+ AndroidView(
+ factory = { TextView(it) },
+ modifier = Modifier.elementOf(node),
+ onReset = null
+ )
+ }
+
+ // Act.
+ val compositeKeyHash = rule.runOnIdle { node.requireLayoutNode().compositeKeyHash }
+
+ // Assert.
+ assertThat(compositeKeyHash).isNotEqualTo(0)
+ }
+
+ @Test
+ fun androidView_withOnReset() {
+ // Arrange.
+ val node = object : Modifier.Node() {}
+ rule.setContent {
+ AndroidView(
+ factory = { TextView(it) },
+ modifier = Modifier.elementOf(node),
+ onReset = { }
+ )
+ }
+
+ // Act.
+ val compositeKeyHash = rule.runOnIdle { node.requireLayoutNode().compositeKeyHash }
+
+ // Assert.
+ assertThat(compositeKeyHash).isNotEqualTo(0)
+ }
+
+ @Test
+ fun Layout1() {
+ // Arrange.
+ var compositeKeyHash = 0
+ rule.setContent {
+ Layout1 { compositeKeyHash = it }
+ }
+
+ // Assert.
+ assertThat(compositeKeyHash).isNotEqualTo(0)
+ }
+
+ @Test
+ fun Layout2() { // Add other overloads of Layout here.
+ // Arrange.
+ var compositeKeyHash = 0
+ rule.setContent {
+ Layout2 { compositeKeyHash = it }
+ }
+
+ // Assert.
+ assertThat(compositeKeyHash).isNotEqualTo(0)
+ }
+
+ @Test
+ fun Layout3() { // Add other overloads of Layout here.
+ // Arrange.
+ var compositeKeyHash = 0
+ rule.setContent {
+ Layout3 { compositeKeyHash = it }
+ }
+
+ // Assert.
+ assertThat(compositeKeyHash).isNotEqualTo(0)
+ }
+
+ @Test
+ fun Layout4() { // Add other overloads of Layout here.
+ // Arrange.
+ var compositeKeyHash = 0
+ rule.setContent {
+ Layout4 { compositeKeyHash = it }
+ }
+
+ // Assert.
+ assertThat(compositeKeyHash).isNotEqualTo(0)
+ }
+
+ @Composable
+ private fun Layout1(onSetCompositionKeyHash: (Int) -> Unit) {
+ val node = remember { object : Modifier.Node() {} }
+ Layout(
+ measurePolicy = { measurables, constraints ->
+ measurables.forEach { it.measure(constraints) }
+ layout(0, 0) {}
+ },
+ modifier = Modifier.elementOf(node)
+ )
+ SideEffect {
+ onSetCompositionKeyHash(node.requireLayoutNode().compositeKeyHash)
+ }
+ }
+
+ @Composable
+ private fun Layout2(onSetCompositionKeyHash: (Int) -> Unit) {
+ val node = remember { object : Modifier.Node() {} }
+ Layout(
+ contents = listOf({}, {}),
+ measurePolicy = { measurables, constraints ->
+ measurables.forEach {
+ it.forEach { measurable ->
+ measurable.measure(constraints)
+ }
+ }
+ layout(0, 0) {}
+ },
+ modifier = Modifier.elementOf(node)
+ )
+ SideEffect {
+ onSetCompositionKeyHash.invoke(node.requireLayoutNode().compositeKeyHash)
+ }
+ }
+
+ @Composable
+ private fun Layout3(onSetCompositionKeyHash: (Int) -> Unit) {
+ val node = remember { object : Modifier.Node() {} }
+ Layout(
+ content = { },
+ measurePolicy = { measurables, constraints ->
+ measurables.forEach { it.measure(constraints) }
+ layout(0, 0) {}
+ },
+ modifier = Modifier.elementOf(node)
+ )
+ SideEffect {
+ onSetCompositionKeyHash.invoke(node.requireLayoutNode().compositeKeyHash)
+ }
+ }
+
+ @Composable
+ private fun Layout4(onSetCompositionKeyHash: (Int) -> Unit) {
+ val node = remember { object : Modifier.Node() {} }
+ @Suppress("DEPRECATION")
+ MultiMeasureLayout(
+ content = { },
+ measurePolicy = { measurables, constraints ->
+ measurables.forEach { it.measure(constraints) }
+ layout(0, 0) {}
+ },
+ modifier = Modifier.elementOf(node)
+ )
+ SideEffect {
+ onSetCompositionKeyHash.invoke(node.requireLayoutNode().compositeKeyHash)
+ }
+ }
+}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/AndroidViewCompatTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/AndroidViewCompatTest.kt
index 432b2fe..a099b70 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/AndroidViewCompatTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/AndroidViewCompatTest.kt
@@ -755,7 +755,7 @@
}
}
- rule.runOnIdle { assertEquals(invalidatesDuringScroll + 1, view!!.draws) }
+ rule.waitUntil { view!!.draws == (invalidatesDuringScroll + 1) }
}
@Test
@@ -775,8 +775,9 @@
invalidate()
}
}
-
- rule.runOnIdle { assertEquals(invalidatesDuringScroll + 1, view!!.draws) }
+ rule.waitUntil(10000) {
+ view!!.draws == invalidatesDuringScroll + 1
+ }
}
@Ignore // b/254573760
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
index 2b9e3ba..d052e2e 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
@@ -1067,6 +1067,84 @@
assertNotEquals(oldId, newId)
}
+
+ @Test
+ fun testSetTextSubstitution_annotatedString() {
+ rule.setContent {
+ Surface {
+ Text(
+ AnnotatedString("hello"),
+ Modifier
+ .testTag(TestTag)
+ )
+ }
+ }
+
+ val config = rule.onNodeWithTag(TestTag, true).fetchSemanticsNode().config
+ rule.runOnUiThread {
+ config.getOrNull(SemanticsActions.SetTextSubstitution)?.action?.invoke(
+ AnnotatedString("bonjour"))
+ }
+
+ rule.waitForIdle()
+
+ var newConfig = rule.onNodeWithTag(TestTag, true).fetchSemanticsNode().config
+ // SetTextSubstitution doesn't trigger text update
+ assertThat(newConfig.getOrNull(SemanticsProperties.Text))
+ .containsExactly(AnnotatedString("hello"))
+
+ rule.runOnUiThread {
+ config.getOrNull(SemanticsActions.ShowTextSubstitution)?.action?.invoke(true)
+ }
+
+ rule.waitForIdle()
+
+ newConfig = rule.onNodeWithTag(TestTag, true).fetchSemanticsNode().config
+ // ShowTextSubstitution triggers text update
+ assertThat(newConfig.getOrNull(SemanticsProperties.Text))
+ .containsExactly(AnnotatedString("bonjour"))
+ assertEquals(
+ AnnotatedString("hello"), newConfig.getOrNull(SemanticsProperties.OriginalText))
+ }
+
+ @Test
+ fun testSetTextSubstitution_simpleString() {
+ rule.setContent {
+ Surface {
+ Text(
+ "hello",
+ Modifier
+ .testTag(TestTag)
+ )
+ }
+ }
+
+ val config = rule.onNodeWithTag(TestTag, true).fetchSemanticsNode().config
+ rule.runOnUiThread {
+ config.getOrNull(SemanticsActions.SetTextSubstitution)?.action?.invoke(
+ AnnotatedString("bonjour"))
+ }
+
+ rule.waitForIdle()
+
+ var newConfig = rule.onNodeWithTag(TestTag, true).fetchSemanticsNode().config
+ // SetTextSubstitution doesn't trigger text update
+ assertThat(newConfig.getOrNull(SemanticsProperties.Text))
+ .containsExactly(AnnotatedString("hello"))
+
+ rule.runOnUiThread {
+ config.getOrNull(SemanticsActions.ShowTextSubstitution)?.action?.invoke(true)
+ }
+
+ rule.waitForIdle()
+
+ newConfig = rule.onNodeWithTag(TestTag, true).fetchSemanticsNode().config
+ // ShowTextSubstitution triggers text update
+ assertThat(newConfig.getOrNull(SemanticsProperties.Text))
+ .containsExactly(AnnotatedString("bonjour"))
+ assertEquals(
+ AnnotatedString("hello"), newConfig.getOrNull(SemanticsProperties.OriginalText))
+ }
}
private fun SemanticsNodeInteraction.assertDoesNotHaveProperty(property: SemanticsPropertyKey<*>) {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/text/input/PlatformTextInputEditTextIntegrationTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/text/input/PlatformTextInputEditTextIntegrationTest.kt
index 706dc6d..f59e04c 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/text/input/PlatformTextInputEditTextIntegrationTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/text/input/PlatformTextInputEditTextIntegrationTest.kt
@@ -28,7 +28,7 @@
import androidx.compose.ui.platform.LocalPlatformTextInputPluginRegistry
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.insertTextAtCursor
-import androidx.compose.ui.semantics.performImeAction
+import androidx.compose.ui.semantics.onImeAction
import androidx.compose.ui.semantics.requestFocus
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.setSelection
@@ -42,7 +42,6 @@
import androidx.compose.ui.test.performTextInput
import androidx.compose.ui.test.performTextInputSelection
import androidx.compose.ui.test.performTextReplacement
-import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.viewinterop.AndroidView
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -60,7 +59,7 @@
* This test exercises the use case of an [EditText] embedded in a composition using the text input
* plugin system to wire into Compose's testing framework.
*/
-@OptIn(ExperimentalTestApi::class, ExperimentalTextApi::class)
+@OptIn(ExperimentalTestApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class PlatformTextInputEditTextIntegrationTest {
@@ -195,7 +194,7 @@
}
return@setSelection false
}
- performImeAction(ImeAction.Go) {
+ onImeAction(ImeAction.Go) {
editText.onEditorAction(ExpectedActionCode)
true
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/text/input/PlatformTextInputViewIntegrationTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/text/input/PlatformTextInputViewIntegrationTest.kt
index 79c8798..f6744de 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/text/input/PlatformTextInputViewIntegrationTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/text/input/PlatformTextInputViewIntegrationTest.kt
@@ -24,7 +24,6 @@
import androidx.compose.ui.platform.LocalPlatformTextInputPluginRegistry
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.text.ExperimentalTextApi
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
@@ -32,7 +31,6 @@
import org.junit.Test
import org.junit.runner.RunWith
-@OptIn(ExperimentalTextApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class PlatformTextInputViewIntegrationTest {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
index f331246..ed1eaae 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
@@ -155,6 +155,45 @@
}
@Test
+ fun androidViewInvalidatingDuringDrawTest() {
+ var drawCount = 0
+ val timesToInvalidate = 10
+ var customView: InvalidatedTextView? = null
+ rule.setContent {
+ AndroidView(
+ factory = {
+ val view: View = LayoutInflater.from(it)
+ .inflate(R.layout.test_multiple_invalidation_layout, null)
+ customView = view.findViewById<InvalidatedTextView>(R.id.custom_draw_view)
+ customView!!.timesToInvalidate = timesToInvalidate
+ view.viewTreeObserver?.addOnPreDrawListener {
+ ++drawCount
+ true
+ }
+ view
+ })
+ }
+ // the first drawn was not caused by invalidation, thus add it to expected draw count.
+ var expectedDraws = timesToInvalidate + 1
+ repeat(expectedDraws) {
+ rule.mainClock.advanceTimeByFrame()
+ }
+
+ // Ensure we wait until the time advancement actually happened as sometimes we can race if
+ // we use runOnIdle directly making the test fail, so providing a big enough timeout to
+ // give plenty of time for the frame advancement to happen.
+ rule.waitUntil(3000) {
+ drawCount == expectedDraws
+ }
+
+ rule.runOnIdle {
+ // Verify that we only drew once per invalidation
+ assertThat(drawCount).isEqualTo(expectedDraws)
+ assertThat(drawCount).isEqualTo(customView!!.timesDrawn)
+ }
+ }
+
+ @Test
fun androidViewWithViewTest() {
lateinit var frameLayout: FrameLayout
rule.activityRule.scenario.onActivity { activity ->
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/viewinterop/InvalidatedTextView.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/viewinterop/InvalidatedTextView.kt
new file mode 100644
index 0000000..4b2583a1
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/viewinterop/InvalidatedTextView.kt
@@ -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.compose.ui.viewinterop
+
+import android.content.Context
+import android.graphics.Canvas
+import android.util.AttributeSet
+import android.widget.TextView
+
+/**
+ * Custom view that represents a TextView that invalidates itself during every draw which
+ * is mainly used for testing invalidation paths.
+ *
+ * The view invalidates up to the amount of times specified in [timesToInvalidate] then it will
+ * no longer invalidate upon drawing.
+ */
+class InvalidatedTextView : TextView {
+ var timesDrawn: Int = 0
+ var timesToInvalidate: Int = 0
+
+ constructor(context: Context?) : super(context)
+ constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+ constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
+ context,
+ attrs,
+ defStyleAttr
+ )
+
+ override fun draw(canvas: Canvas) {
+ if (timesDrawn < timesToInvalidate) {
+ invalidate()
+ }
+ super.draw(canvas)
+ ++timesDrawn
+ }
+}
diff --git a/compose/ui/ui/src/androidAndroidTest/res/layout/test_multiple_invalidation_layout.xml b/compose/ui/ui/src/androidAndroidTest/res/layout/test_multiple_invalidation_layout.xml
new file mode 100644
index 0000000..c30d386
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/res/layout/test_multiple_invalidation_layout.xml
@@ -0,0 +1,27 @@
+<?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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <androidx.compose.ui.viewinterop.InvalidatedTextView
+ android:id="@+id/custom_draw_view"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="This is text 1"/>
+</LinearLayout>
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerEvent.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerEvent.android.kt
index 59921b2..c0ce531 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerEvent.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerEvent.android.kt
@@ -17,10 +17,11 @@
package androidx.compose.ui.input.pointer
import android.view.MotionEvent
+import androidx.collection.LongSparseArray
import androidx.compose.ui.util.fastFirstOrNull
internal actual class InternalPointerEvent actual constructor(
- actual val changes: Map<PointerId, PointerInputChange>,
+ actual val changes: LongSparseArray<PointerInputChange>,
val pointerInputEvent: PointerInputEvent
) {
val motionEvent: MotionEvent
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/PointerEvent.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/PointerEvent.android.kt
index e13bda9..27ee806 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/PointerEvent.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/PointerEvent.android.kt
@@ -19,6 +19,7 @@
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.MotionEvent.ACTION_SCROLL
+import androidx.collection.LongSparseArray
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.util.fastForEach
@@ -91,10 +92,10 @@
null -> PointerEvent(changes, null)
this.motionEvent -> PointerEvent(changes, internalPointerEvent)
else -> {
- val map = LinkedHashMap<PointerId, PointerInputChange>(changes.size)
+ val changesArray = LongSparseArray<PointerInputChange>(changes.size)
val pointerEventData = ArrayList<PointerInputEventData>(changes.size)
changes.fastForEach { change ->
- map[change.id] = change
+ changesArray.put(change.id.value, change)
pointerEventData += PointerInputEventData(
change.id,
change.uptimeMillis,
@@ -109,7 +110,7 @@
val pointerInputEvent =
PointerInputEvent(motionEvent.eventTime, pointerEventData, motionEvent)
- val event = InternalPointerEvent(map, pointerInputEvent)
+ val event = InternalPointerEvent(changesArray, pointerInputEvent)
PointerEvent(changes, event)
}
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
index 5fdc593..d4c3cd3 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
@@ -24,6 +24,7 @@
import android.os.Looper
import android.os.SystemClock
import android.util.Log
+import android.util.LongSparseArray
import android.util.SparseArray
import android.view.KeyEvent as AndroidKeyEvent
import android.view.MotionEvent
@@ -47,6 +48,9 @@
import android.view.autofill.AutofillValue
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
+import android.view.translation.ViewTranslationCallback
+import android.view.translation.ViewTranslationRequest
+import android.view.translation.ViewTranslationResponse
import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
import androidx.annotation.VisibleForTesting
@@ -157,6 +161,7 @@
import androidx.savedstate.SavedStateRegistryOwner
import androidx.savedstate.findViewTreeSavedStateRegistryOwner
import java.lang.reflect.Method
+import java.util.function.Consumer
import kotlin.coroutines.CoroutineContext
import kotlin.math.roundToInt
@@ -580,6 +585,11 @@
// Support for this feature in Compose is tracked here: b/207654434
AndroidComposeViewForceDarkModeQ.disallowForceDark(this)
}
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ AndroidComposeViewTranslationCallbackS.setViewTranslationCallback(
+ this, AndroidComposeViewTranslationCallback())
+ }
}
/**
@@ -870,20 +880,30 @@
}
override fun measureAndLayout(sendPointerUpdate: Boolean) {
- trace("AndroidOwner:measureAndLayout") {
- val resend = if (sendPointerUpdate) resendMotionEventOnLayout else null
- val rootNodeResized = measureAndLayoutDelegate.measureAndLayout(resend)
- if (rootNodeResized) {
- requestLayout()
+ // only run the logic when we have something pending
+ if (measureAndLayoutDelegate.hasPendingMeasureOrLayout ||
+ measureAndLayoutDelegate.hasPendingOnPositionedCallbacks
+ ) {
+ trace("AndroidOwner:measureAndLayout") {
+ val resend = if (sendPointerUpdate) resendMotionEventOnLayout else null
+ val rootNodeResized = measureAndLayoutDelegate.measureAndLayout(resend)
+ if (rootNodeResized) {
+ requestLayout()
+ }
+ measureAndLayoutDelegate.dispatchOnPositionedCallbacks()
}
- measureAndLayoutDelegate.dispatchOnPositionedCallbacks()
}
}
override fun measureAndLayout(layoutNode: LayoutNode, constraints: Constraints) {
trace("AndroidOwner:measureAndLayout") {
measureAndLayoutDelegate.measureAndLayout(layoutNode, constraints)
- measureAndLayoutDelegate.dispatchOnPositionedCallbacks()
+ // only dispatch the callbacks if we don't have other nodes to process as otherwise
+ // we will have one more measureAndLayout() pass anyway in the same frame.
+ // it allows us to not traverse the hierarchy twice.
+ if (!measureAndLayoutDelegate.hasPendingMeasureOrLayout) {
+ measureAndLayoutDelegate.dispatchOnPositionedCallbacks()
+ }
}
}
@@ -1289,6 +1309,23 @@
if (autofillSupported()) _autofill?.performAutofill(values)
}
+ @RequiresApi(Build.VERSION_CODES.S)
+ override fun onCreateVirtualViewTranslationRequests(
+ virtualIds: LongArray,
+ supportedFormats: IntArray,
+ requestsCollector: Consumer<ViewTranslationRequest?>
+ ) {
+ accessibilityDelegate.onCreateVirtualViewTranslationRequests(
+ virtualIds, supportedFormats, requestsCollector)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ override fun onVirtualViewTranslationResponses(
+ response: LongSparseArray<ViewTranslationResponse?>
+ ) {
+ accessibilityDelegate.onVirtualViewTranslationResponses(response)
+ }
+
override fun dispatchGenericMotionEvent(event: MotionEvent) = when (event.actionMasked) {
ACTION_SCROLL -> when {
event.isFromSource(SOURCE_ROTARY_ENCODER) -> handleRotaryEvent(event)
@@ -1418,6 +1455,7 @@
}
}
+ @OptIn(InternalCoreApi::class)
private fun sendMotionEvent(motionEvent: MotionEvent): ProcessResult {
if (keyboardModifiersRequireUpdate) {
keyboardModifiersRequireUpdate = false
@@ -1459,6 +1497,7 @@
}
}
+ @OptIn(InternalCoreApi::class)
private fun sendSimulatedEvent(
motionEvent: MotionEvent,
action: Int,
@@ -1838,6 +1877,27 @@
*/
val savedStateRegistryOwner: SavedStateRegistryOwner
)
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ private class AndroidComposeViewTranslationCallback : ViewTranslationCallback {
+ override fun onShowTranslation(view: View): Boolean {
+ val androidComposeView = view as AndroidComposeView
+ androidComposeView.accessibilityDelegate.onShowTranslation()
+ return true
+ }
+
+ override fun onHideTranslation(view: View): Boolean {
+ val androidComposeView = view as AndroidComposeView
+ androidComposeView.accessibilityDelegate.onHideTranslation()
+ return true
+ }
+
+ override fun onClearTranslation(view: View): Boolean {
+ val androidComposeView = view as AndroidComposeView
+ androidComposeView.accessibilityDelegate.onClearTranslation()
+ return true
+ }
+ }
}
/**
@@ -1909,6 +1969,15 @@
}
}
+@RequiresApi(Build.VERSION_CODES.S)
+private object AndroidComposeViewTranslationCallbackS {
+ @DoNotInline
+ @RequiresApi(Build.VERSION_CODES.S)
+ fun setViewTranslationCallback(view: View, translationCallback: ViewTranslationCallback) {
+ view.setViewTranslationCallback(translationCallback)
+ }
+}
+
/**
* Sets this [Matrix] to be the result of this * [other]
*/
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
index 834d018..61b48eb 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
@@ -27,6 +27,7 @@
import android.os.SystemClock
import android.text.SpannableString
import android.util.Log
+import android.util.LongSparseArray
import android.view.MotionEvent
import android.view.View
import android.view.accessibility.AccessibilityEvent
@@ -38,6 +39,9 @@
import android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX
import android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
import android.view.accessibility.AccessibilityNodeProvider
+import android.view.translation.TranslationRequestValue
+import android.view.translation.ViewTranslationRequest
+import android.view.translation.ViewTranslationResponse
import androidx.annotation.DoNotInline
import androidx.annotation.IntRange
import androidx.annotation.RequiresApi
@@ -87,6 +91,7 @@
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastForEachIndexed
import androidx.compose.ui.util.fastMap
+import androidx.core.util.keyIterator
import androidx.core.view.AccessibilityDelegateCompat
import androidx.core.view.ViewCompat
import androidx.core.view.ViewCompat.ACCESSIBILITY_LIVE_REGION_ASSERTIVE
@@ -96,11 +101,11 @@
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
import androidx.core.view.accessibility.AccessibilityNodeProviderCompat
-import androidx.core.view.children
import androidx.core.view.contentcapture.ContentCaptureSessionCompat
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
+import java.util.function.Consumer
import kotlin.math.abs
import kotlin.math.ceil
import kotlin.math.floor
@@ -111,73 +116,6 @@
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
-// TODO(mnuzen): This code is copy-pasted from experimental API in the Kotlin 1.7 standard library: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.ranges/range-until.html.
-// Delete it when this API graduates to stable in Kotlin (when the docs page linked no longer has @ExperimentalStdlibApi annotation).
-/**
- * Represents a range of values (for example, numbers or characters) where the upper bound is not included in the range.
- * See the [Kotlin language documentation](https://kotlinlang.org/docs/reference/ranges.html) for more information.
- */
-internal interface OpenEndRange<T : Comparable<T>> {
- /**
- * The minimum value in the range.
- */
- val start: T
-
- /**
- * The maximum value in the range (exclusive).
- *
- * @throws IllegalStateException can be thrown if the exclusive end bound cannot be represented
- * with a value of type [T].
- */
- val endExclusive: T
-
- /**
- * Checks whether the specified [value] belongs to the range.
- *
- * A value belongs to the open-ended range if it is greater than or equal to the [start] bound and strictly less than the [endExclusive] bound.
- */
- operator fun contains(value: T): Boolean = value >= start && value < endExclusive
-
- /**
- * Checks whether the range is empty.
- *
- * The open-ended range is empty if its start value is greater than or equal to the end value.
- */
- fun isEmpty(): Boolean = start >= endExclusive
-}
-
-private class OpenEndFloatRange(
- start: Float,
- endExclusive: Float
-) : OpenEndRange<Float> {
- private val _start = start
- private val _endExclusive = endExclusive
- override val start: Float get() = _start
- override val endExclusive: Float get() = _endExclusive
-
- private fun lessThanOrEquals(a: Float, b: Float): Boolean = a <= b
-
- override fun contains(value: Float): Boolean = value >= _start && value < _endExclusive
- override fun isEmpty(): Boolean = !(_start < _endExclusive)
-
- override fun equals(other: Any?): Boolean {
- return other is OpenEndFloatRange && (isEmpty() && other.isEmpty() ||
- _start == other._start && _endExclusive == other._endExclusive)
- }
-
- override fun hashCode(): Int {
- return if (isEmpty()) -1 else 31 * _start.hashCode() + _endExclusive.hashCode()
- }
-
- override fun toString(): String = "$_start..<$_endExclusive"
-}
-
-internal operator fun Float.rangeUntil(that: Float): OpenEndRange<Float> =
- OpenEndFloatRange(this, that)
-
-private fun OpenEndRange<Float>.overlaps(it: OpenEndRange<Float>) =
- !isEmpty() && !it.isEmpty() && max(start, it.start) < min(endExclusive, it.endExclusive)
-
private fun LayoutNode.findClosestParentNode(selector: (LayoutNode) -> Boolean): LayoutNode? {
var currentParent = this.parent
while (currentParent != null) {
@@ -332,6 +270,15 @@
}
/**
+ * Indicates whether the translated information is show or hide in the [AndroidComposeView].
+ *
+ * See [ViewTranslationCallback](https://cs.android.com/android/platform/superproject/+/refs/heads/master:frameworks/base/core/java/android/view/translation/ViewTranslationCallback.java)
+ * for more details of the View translation API.
+ */
+ enum class TranslateStatus { SHOW_ORIGINAL, SHOW_TRANSLATED }
+ private var translateStatus = TranslateStatus.SHOW_ORIGINAL
+
+ /**
* True if accessibility service with the touch exploration (e.g. Talkback) is enabled in the
* system.
* Note that UIAutomator doesn't request touch exploration therefore returns false
@@ -385,7 +332,9 @@
if (currentSemanticsNodesInvalidated) { // first instance of retrieving all nodes
currentSemanticsNodesInvalidated = false
field = view.semanticsOwner.getAllUncoveredSemanticsNodesToMap()
- setTraversalValues()
+ if (isEnabledForAccessibility) {
+ setTraversalValues()
+ }
}
return field
}
@@ -457,11 +406,11 @@
}
override fun onStart(owner: LifecycleOwner) {
- initContentCaptureSemanticsStructureChangeEvents(onStart = true)
+ initContentCapture(onStart = true)
}
override fun onStop(owner: LifecycleOwner) {
- initContentCaptureSemanticsStructureChangeEvents(onStart = false)
+ initContentCapture(onStart = false)
}
/**
@@ -566,24 +515,52 @@
return info.unwrap()
}
- private fun semanticComparator(
- layoutIsRtl: Boolean,
- ): Comparator<SemanticsNode> {
- // First compare the coordinates LTR
- var comparator = compareBy<SemanticsNode>(
- { it.boundsInWindow.left },
- { it.boundsInWindow.top },
- { it.boundsInWindow.bottom },
- { it.boundsInWindow.right })
- // Modify comparison if we're not using LTR comparison strategy to use RTL instead
- if (layoutIsRtl) {
- comparator = compareBy(
- { it.boundsInWindow.right },
- { it.boundsInWindow.top },
- { it.boundsInWindow.bottom },
- { it.boundsInWindow.left })
+ object TopBottomBoundsComparator : Comparator<Pair<Rect, MutableList<SemanticsNode>>> {
+ override fun compare(
+ a: Pair<Rect, MutableList<SemanticsNode>>,
+ b: Pair<Rect, MutableList<SemanticsNode>>
+ ): Int {
+ val r = a.first.top.compareTo(b.first.top)
+ if (r != 0) return r
+ return a.first.bottom.compareTo(b.first.bottom)
}
- return comparator
+ }
+
+ object LtrBoundsComparator : Comparator<SemanticsNode> {
+ override fun compare(a: SemanticsNode, b: SemanticsNode): Int {
+ // TODO: boundsInWindow is quite expensive and allocates several objects,
+ // we need to fix this since this is called during sorting
+ val ab = a.boundsInWindow
+ val bb = b.boundsInWindow
+ var r = ab.left.compareTo(bb.left)
+ if (r != 0) return r
+ r = ab.top.compareTo(bb.top)
+ if (r != 0) return r
+ r = ab.bottom.compareTo(bb.bottom)
+ if (r != 0) return r
+ return ab.right.compareTo(bb.right)
+ }
+ }
+
+ object RtlBoundsComparator : Comparator<SemanticsNode> {
+ override fun compare(a: SemanticsNode, b: SemanticsNode): Int {
+ // TODO: boundsInWindow is quite expensive and allocates several objects,
+ // we need to fix this since this is called during sorting
+ val ab = a.boundsInWindow
+ val bb = b.boundsInWindow
+ var r = ab.right.compareTo(bb.right)
+ if (r != 0) return r
+ r = ab.top.compareTo(bb.top)
+ if (r != 0) return r
+ r = ab.bottom.compareTo(bb.bottom)
+ if (r != 0) return r
+ return ab.left.compareTo(bb.left)
+ }
+ }
+
+ @Suppress("NOTHING_TO_INLINE")
+ private inline fun semanticComparator(layoutIsRtl: Boolean): Comparator<SemanticsNode> {
+ return (if (layoutIsRtl) RtlBoundsComparator else LtrBoundsComparator)
// then compare by layoutNode's zIndex and placement order
.thenBy(LayoutNode.ZComparator) { it.layoutNode }
// then compare by semanticsId to break the tie somehow
@@ -603,12 +580,12 @@
*/
private fun sortByGeometryGroupings(
layoutIsRtl: Boolean,
- parentListToSort: MutableList<SemanticsNode>,
+ parentListToSort: ArrayList<SemanticsNode>,
containerChildrenMapping: MutableMap<Int, MutableList<SemanticsNode>> = mutableMapOf()
): MutableList<SemanticsNode> {
// RowGroupings list consists of pairs, first = a rectangle of the bounds of the row
// and second = the list of nodes in that row
- val rowGroupings = mutableListOf<Pair<Rect, MutableList<SemanticsNode>>>()
+ val rowGroupings = ArrayList<Pair<Rect, MutableList<SemanticsNode>>>()
// check to see if this entry overlaps with any groupings in rowGroupings
fun placedEntryRowOverlaps(
@@ -617,21 +594,21 @@
// Conversion to long is needed in order to utilize `until`, which has no float ver
val entryTopCoord = node.boundsInWindow.top
val entryBottomCoord = node.boundsInWindow.bottom
- val entryRange = entryTopCoord.rangeUntil(entryBottomCoord)
+ val entryIsEmpty = entryTopCoord >= entryBottomCoord
for (currIndex in 0..rowGroupings.lastIndex) {
- var currRect = rowGroupings[currIndex].first
- var groupRange = currRect.top.rangeUntil(currRect.bottom)
+ val currRect = rowGroupings[currIndex].first
+ val groupIsEmpty = currRect.top >= currRect.bottom
+ val groupOverlapsEntry = !entryIsEmpty && !groupIsEmpty &&
+ max(entryTopCoord, currRect.top) < min(entryBottomCoord, currRect.bottom)
// If it overlaps with this row group, update cover and add node
- if (groupRange.overlaps(entryRange)) {
+ if (groupOverlapsEntry) {
val newRect = currRect.intersect(
- Rect(
- 0f,
- entryTopCoord,
- Float.POSITIVE_INFINITY,
- entryBottomCoord
- )
+ 0f,
+ entryTopCoord,
+ Float.POSITIVE_INFINITY,
+ entryBottomCoord
)
// Replace the cover rectangle, copying over the old list of nodes
rowGroupings[currIndex] = Pair(newRect, rowGroupings[currIndex].second)
@@ -656,9 +633,9 @@
}
// Sort the rows from top to bottom
- rowGroupings.sortWith(compareBy({ it.first.top }, { it.first.bottom }))
+ rowGroupings.sortWith(TopBottomBoundsComparator)
- val returnList = mutableListOf<SemanticsNode>()
+ val returnList = ArrayList<SemanticsNode>()
rowGroupings.fastForEach { row ->
// Sort each individual row's parent nodes
row.second.sortWith(semanticComparator(layoutIsRtl))
@@ -667,7 +644,7 @@
// Kotlin `sortWith` should just pull out the highest traversal indices, but keep everything
// else in place
- returnList.sortWith(compareBy { it.getTraversalIndex })
+ returnList.sortWith { a, b -> a.traversalIndex.compareTo(b.traversalIndex) }
var i = 0
// Afterwards, go in and add the containers' children.
@@ -688,6 +665,33 @@
return returnList
}
+ private fun geometryDepthFirstSearch(
+ currNode: SemanticsNode,
+ layoutIsRtl: Boolean,
+ geometryList: ArrayList<SemanticsNode>,
+ containerMapToChildren: MutableMap<Int, MutableList<SemanticsNode>>
+ ) {
+ // We only want to add children that are either traversalGroups or are
+ // screen reader focusable. The child must also be in the current pruned semantics tree.
+ val isTraversalGroup = currNode.isTraversalGroup
+ if ((isTraversalGroup || isScreenReaderFocusable(currNode)) &&
+ currNode.id in currentSemanticsNodes.keys) {
+ geometryList.add(currNode)
+ }
+ if (isTraversalGroup) {
+ // Recurse and record the container's children, sorted
+ containerMapToChildren[currNode.id] = subtreeSortedByGeometryGrouping(
+ layoutIsRtl, currNode.children.toMutableList()
+ )
+ } else {
+ // Otherwise, continue adding children to the list that'll be sorted regardless of
+ // hierarchy
+ currNode.children.fastForEach { child ->
+ geometryDepthFirstSearch(child, layoutIsRtl, geometryList, containerMapToChildren)
+ }
+ }
+ }
+
/**
* This function prepares a subtree for `sortByGeometryGroupings` by retrieving all
* non-container nodes and adding them to the list to be geometrically sorted. We recurse on
@@ -702,31 +706,10 @@
// are container nodes in this level. If there are container nodes, `containerMapToChildren`
// would look like {containerId: [sortedChild, sortedChild], containerId: [sortedChild]}
val containerMapToChildren = mutableMapOf<Int, MutableList<SemanticsNode>>()
- val geometryList = mutableListOf<SemanticsNode>()
-
- fun depthFirstSearch(currNode: SemanticsNode) {
- // We only want to add children that are either traversalGroups or are
- // screen reader focusable. The child must also be in the current pruned semantics tree.
- if ((currNode.isTraversalGroup == true || isScreenReaderFocusable(currNode)) &&
- currNode.id in currentSemanticsNodes.keys) {
- geometryList.add(currNode)
- }
- if (currNode.isTraversalGroup == true) {
- // Recurse and record the container's children, sorted
- containerMapToChildren[currNode.id] = subtreeSortedByGeometryGrouping(
- layoutIsRtl, currNode.children.toMutableList()
- )
- } else {
- // Otherwise, continue adding children to the list that'll be sorted regardless of
- // hierarchy
- currNode.children.fastForEach { child ->
- depthFirstSearch(child)
- }
- }
- }
+ val geometryList = ArrayList<SemanticsNode>()
listToSort.fastForEach { node ->
- depthFirstSearch(node)
+ geometryDepthFirstSearch(node, layoutIsRtl, geometryList, containerMapToChildren)
}
return sortByGeometryGroupings(layoutIsRtl, geometryList, containerMapToChildren)
@@ -960,7 +943,7 @@
)
}
- semanticsNode.unmergedConfig.getOrNull(SemanticsActions.PerformImeAction)?.let {
+ semanticsNode.unmergedConfig.getOrNull(SemanticsActions.OnImeAction)?.let {
info.addAction(
AccessibilityActionCompat(
android.R.id.accessibilityActionImeEnter,
@@ -1558,9 +1541,11 @@
event.packageName = view.context.packageName
event.setSource(view, virtualViewId)
- // populate additional information from the node
- currentSemanticsNodes[virtualViewId]?.let {
- event.isPassword = it.semanticsNode.isPassword
+ if (isEnabledForAccessibility) {
+ // populate additional information from the node
+ currentSemanticsNodes[virtualViewId]?.let {
+ event.isPassword = it.semanticsNode.isPassword
+ }
}
return event
@@ -1820,7 +1805,7 @@
}
android.R.id.accessibilityActionImeEnter -> {
- return node.unmergedConfig.getOrNull(SemanticsActions.PerformImeAction)
+ return node.unmergedConfig.getOrNull(SemanticsActions.OnImeAction)
?.action?.invoke() ?: false
}
@@ -2283,14 +2268,18 @@
private fun checkForSemanticsChanges() {
// Structural change
- sendAccessibilitySemanticsStructureChangeEvents(
- view.semanticsOwner.unmergedRootSemanticsNode,
- previousSemanticsRoot
- )
- sendContentCaptureSemanticsStructureChangeEvents(
- view.semanticsOwner.unmergedRootSemanticsNode,
- previousSemanticsRoot
- )
+ if (isEnabledForAccessibility) {
+ sendAccessibilitySemanticsStructureChangeEvents(
+ view.semanticsOwner.unmergedRootSemanticsNode,
+ previousSemanticsRoot
+ )
+ }
+ if (isEnabledForContentCapture) {
+ sendContentCaptureSemanticsStructureChangeEvents(
+ view.semanticsOwner.unmergedRootSemanticsNode,
+ previousSemanticsRoot
+ )
+ }
// Property change
sendSemanticsPropertyChangeEvents(currentSemanticsNodes)
updateSemanticsNodesCopyAndPanes()
@@ -2875,6 +2864,9 @@
if (!isEnabledForContentCapture) {
return
}
+
+ updateTranslationOnAppeared(node)
+
bufferContentCaptureViewAppeared(node.id, node.toViewStructure())
node.replacedChildren.fastForEach { child -> updateContentCaptureBuffersOnAppeared(child) }
}
@@ -2889,6 +2881,66 @@
}
}
+ private fun updateTranslationOnAppeared(node: SemanticsNode) {
+ val config = node.unmergedConfig
+ val isShowingTextSubstitution = config.getOrNull(
+ SemanticsProperties.IsShowingTextSubstitution)
+
+ if (translateStatus == TranslateStatus.SHOW_ORIGINAL &&
+ isShowingTextSubstitution == true) {
+ config.getOrNull(SemanticsActions.ShowTextSubstitution)?.action?.invoke(false)
+ } else if (translateStatus == TranslateStatus.SHOW_TRANSLATED &&
+ isShowingTextSubstitution == false) {
+ config.getOrNull(SemanticsActions.ShowTextSubstitution)?.action?.invoke(true)
+ }
+ }
+
+ internal fun onShowTranslation() {
+ translateStatus = TranslateStatus.SHOW_TRANSLATED
+ showTranslatedText()
+ }
+
+ internal fun onHideTranslation() {
+ translateStatus = TranslateStatus.SHOW_ORIGINAL
+ hideTranslatedText()
+ }
+
+ internal fun onClearTranslation() {
+ translateStatus = TranslateStatus.SHOW_ORIGINAL
+ clearTranslatedText()
+ }
+
+ private fun showTranslatedText() {
+ for (node in currentSemanticsNodes.values) {
+ val config = node.semanticsNode.unmergedConfig
+ if (config.getOrNull(SemanticsProperties.IsShowingTextSubstitution) == false) {
+ config.getOrNull(SemanticsActions.ShowTextSubstitution)?.action?.invoke(
+ true
+ )
+ }
+ }
+ }
+
+ private fun hideTranslatedText() {
+ for (node in currentSemanticsNodes.values) {
+ val config = node.semanticsNode.unmergedConfig
+ if (config.getOrNull(SemanticsProperties.IsShowingTextSubstitution) == true) {
+ config.getOrNull(SemanticsActions.ShowTextSubstitution)?.action?.invoke(
+ false
+ )
+ }
+ }
+ }
+
+ private fun clearTranslatedText() {
+ for (node in currentSemanticsNodes.values) {
+ val config = node.semanticsNode.unmergedConfig
+ if (config.getOrNull(SemanticsProperties.IsShowingTextSubstitution) != null) {
+ config.getOrNull(SemanticsActions.ClearTextSubstitution)?.action?.invoke()
+ }
+ }
+ }
+
private fun sendAccessibilitySemanticsStructureChangeEvents(
newNode: SemanticsNode,
oldNode: SemanticsNodeCopy
@@ -2922,11 +2974,7 @@
}
}
- internal fun initContentCaptureSemanticsStructureChangeEvents(onStart: Boolean) {
- if (!isEnabledForContentCapture) {
- return
- }
-
+ internal fun initContentCapture(onStart: Boolean) {
if (onStart) {
updateContentCaptureBuffersOnAppeared(view.semanticsOwner.unmergedRootSemanticsNode)
} else {
@@ -3306,6 +3354,76 @@
}
}
}
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ private object ViewTranslationHelperMethodsS {
+ @DoNotInline
+ @Suppress("UNUSED_PARAMETER")
+ @RequiresApi(Build.VERSION_CODES.S)
+ fun onCreateVirtualViewTranslationRequests(
+ accessibilityDelegateCompat: AndroidComposeViewAccessibilityDelegateCompat,
+ virtualIds: LongArray,
+ supportedFormats: IntArray,
+ requestsCollector: Consumer<ViewTranslationRequest?>
+ ) {
+
+ virtualIds.forEach {
+ val node = accessibilityDelegateCompat.currentSemanticsNodes[it.toInt()]
+ ?.semanticsNode ?: return@forEach
+ val requestBuilder = ViewTranslationRequest.Builder(
+ accessibilityDelegateCompat.view.autofillId,
+ node.id.toLong()
+ )
+
+ var text = node.unmergedConfig.getOrNull(SemanticsProperties.OriginalText)
+ ?: AnnotatedString(node.getTextForTranslation() ?: return@forEach)
+
+ requestBuilder.setValue(ViewTranslationRequest.ID_TEXT,
+ TranslationRequestValue.forText(text))
+ requestsCollector.accept(requestBuilder.build())
+ }
+ }
+
+ @DoNotInline
+ @RequiresApi(Build.VERSION_CODES.S)
+ fun onVirtualViewTranslationResponses(
+ accessibilityDelegateCompat: AndroidComposeViewAccessibilityDelegateCompat,
+ response: LongSparseArray<ViewTranslationResponse?>
+ ) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
+ return
+ }
+
+ for (key in response.keyIterator()) {
+ response.get(key)?.getValue(ViewTranslationRequest.ID_TEXT)?.text?.let {
+ accessibilityDelegateCompat.currentSemanticsNodes[key.toInt()]
+ ?.semanticsNode
+ ?.let { semanticsNode ->
+ semanticsNode.unmergedConfig
+ .getOrNull(SemanticsActions.SetTextSubstitution)?.action
+ ?.invoke(AnnotatedString(it.toString()))
+ }
+ }
+ }
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ internal fun onCreateVirtualViewTranslationRequests(
+ virtualIds: LongArray,
+ supportedFormats: IntArray,
+ requestsCollector: Consumer<ViewTranslationRequest?>
+ ) {
+ ViewTranslationHelperMethodsS.onCreateVirtualViewTranslationRequests(
+ this, virtualIds, supportedFormats, requestsCollector)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ internal fun onVirtualViewTranslationResponses(
+ response: LongSparseArray<ViewTranslationResponse?>
+ ) {
+ ViewTranslationHelperMethodsS.onVirtualViewTranslationResponses(this, response)
+ }
}
private fun SemanticsNode.enabled() = (config.getOrNull(SemanticsProperties.Disabled) == null)
@@ -3326,22 +3444,21 @@
}
private fun SemanticsNode.hasPaneTitle() = config.contains(SemanticsProperties.PaneTitle)
-private val SemanticsNode.isPassword: Boolean get() = config.contains(SemanticsProperties.Password)
-private val SemanticsNode.isTextField get() = this.unmergedConfig.contains(SemanticsActions.SetText)
-private val SemanticsNode.isRtl get() = layoutInfo.layoutDirection == LayoutDirection.Rtl
-private val SemanticsNode.isTraversalGroup get() =
- config.getOrNull(SemanticsProperties.IsTraversalGroup)
-private val SemanticsNode.getTraversalIndex: Float
- get() {
- if (this.config.contains(SemanticsProperties.TraversalIndex)) {
- return config[SemanticsProperties.TraversalIndex]
- }
- // If the traversal index has not been set, default to zero
- return 0f
- }
+private inline val SemanticsNode.isPassword: Boolean get() =
+ config.contains(SemanticsProperties.Password)
+private inline val SemanticsNode.isTextField get() =
+ unmergedConfig.contains(SemanticsActions.SetText)
+private inline val SemanticsNode.isRtl get() = layoutInfo.layoutDirection == LayoutDirection.Rtl
+private inline val SemanticsNode.isTraversalGroup get() =
+ config.getOrElse(SemanticsProperties.IsTraversalGroup) { false }
+private inline val SemanticsNode.traversalIndex get() =
+ config.getOrElse(SemanticsProperties.TraversalIndex) { 0f }
private val SemanticsNode.infoContentDescriptionOrNull get() = this.unmergedConfig.getOrNull(
SemanticsProperties.ContentDescription)?.firstOrNull()
+private fun SemanticsNode.getTextForTranslation(): String? = this.unmergedConfig.getOrNull(
+ SemanticsProperties.Text)?.fastJoinToString("\n")
+
@OptIn(ExperimentalComposeUiApi::class)
private fun SemanticsNode.excludeLineAndPageGranularities(): Boolean {
// text field that is not in focus
@@ -3377,6 +3494,8 @@
val adjustedBounds: android.graphics.Rect
)
+private val DefaultFakeNodeBounds = Rect(0f, 0f, 10f, 10f)
+
/**
* Finds pruned [SemanticsNode]s in the tree owned by this [SemanticsOwner]. A semantics node
* completely covered by siblings drawn on top of it will be pruned. Return the results in a
@@ -3389,20 +3508,12 @@
if (!root.layoutNode.isPlaced || !root.layoutNode.isAttached) {
return nodes
}
- val unaccountedSpace = Region().also {
- it.set(
- root.boundsInRoot.run {
- android.graphics.Rect(
- left.roundToInt(),
- top.roundToInt(),
- right.roundToInt(),
- bottom.roundToInt()
- )
- }
- )
+
+ val unaccountedSpace = with(root.boundsInRoot) {
+ Region(left.roundToInt(), top.roundToInt(), right.roundToInt(), bottom.roundToInt())
}
- fun findAllSemanticNodesRecursive(currentNode: SemanticsNode) {
+ fun findAllSemanticNodesRecursive(currentNode: SemanticsNode, region: Region) {
val notAttachedOrPlaced =
!currentNode.layoutNode.isPlaced || !currentNode.layoutNode.isAttached
if ((unaccountedSpace.isEmpty && currentNode.id != root.id) ||
@@ -3411,19 +3522,19 @@
return
}
val touchBoundsInRoot = currentNode.touchBoundsInRoot
- val boundsInRoot = android.graphics.Rect(
- touchBoundsInRoot.left.roundToInt(),
- touchBoundsInRoot.top.roundToInt(),
- touchBoundsInRoot.right.roundToInt(),
- touchBoundsInRoot.bottom.roundToInt(),
- )
- val region = Region().also { it.set(boundsInRoot) }
+ val left = touchBoundsInRoot.left.roundToInt()
+ val top = touchBoundsInRoot.top.roundToInt()
+ val right = touchBoundsInRoot.right.roundToInt()
+ val bottom = touchBoundsInRoot.bottom.roundToInt()
+
+ region.set(left, top, right, bottom)
+
val virtualViewId = if (currentNode.id == root.id) {
AccessibilityNodeProviderCompat.HOST_VIEW_ID
} else {
currentNode.id
}
- if (region.op(unaccountedSpace, region, Region.Op.INTERSECT)) {
+ if (region.op(unaccountedSpace, Region.Op.INTERSECT)) {
nodes[virtualViewId] = SemanticsNodeWithAdjustedBounds(currentNode, region.bounds)
// Children could be drawn outside of parent, but we are using clipped bounds for
// accessibility now, so let's put the children recursion inside of this if. If later
@@ -3431,9 +3542,9 @@
// if block.
val children = currentNode.replacedChildren
for (i in children.size - 1 downTo 0) {
- findAllSemanticNodesRecursive(children[i])
+ findAllSemanticNodesRecursive(children[i], region)
}
- unaccountedSpace.op(boundsInRoot, unaccountedSpace, Region.Op.REVERSE_DIFFERENCE)
+ unaccountedSpace.op(left, top, right, bottom, Region.Op.DIFFERENCE)
} else {
if (currentNode.isFake) {
val parentNode = currentNode.parent
@@ -3441,7 +3552,7 @@
val boundsForFakeNode = if (parentNode?.layoutInfo?.isPlaced == true) {
parentNode.boundsInRoot
} else {
- Rect(0f, 0f, 10f, 10f)
+ DefaultFakeNodeBounds
}
nodes[virtualViewId] = SemanticsNodeWithAdjustedBounds(
currentNode,
@@ -3462,7 +3573,7 @@
}
}
- findAllSemanticNodesRecursive(root)
+ findAllSemanticNodesRecursive(root, Region())
return nodes
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidViewsHandler.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidViewsHandler.android.kt
index c0e88da..de8859fe7 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidViewsHandler.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidViewsHandler.android.kt
@@ -94,4 +94,9 @@
}
override fun shouldDelayChildPressedState(): Boolean = false
+
+ // We don't want the AndroidComposeView drawing the holder and its children. All draw
+ // calls should come through AndroidViewHolder or ViewLayer.
+ override fun dispatchDraw(canvas: Canvas) {
+ }
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
index f718f7b..2476012 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
@@ -208,8 +208,12 @@
val newLeft = position.x
val newTop = position.y
if (oldLeft != newLeft || oldTop != newTop) {
- renderNode.offsetLeftAndRight(newLeft - oldLeft)
- renderNode.offsetTopAndBottom(newTop - oldTop)
+ if (oldLeft != newLeft) {
+ renderNode.offsetLeftAndRight(newLeft - oldLeft)
+ }
+ if (oldTop != newTop) {
+ renderNode.offsetTopAndBottom(newTop - oldTop)
+ }
triggerRepaint()
matrixCache.invalidate()
}
@@ -291,7 +295,6 @@
override fun updateDisplayList() {
if (isDirty || !renderNode.hasDisplayList) {
- isDirty = false
val clipPath = if (renderNode.clipToOutline && !outlineResolver.outlineClipSupported) {
outlineResolver.clipPath
} else {
@@ -300,6 +303,7 @@
drawBlock?.let {
renderNode.record(canvasHolder, clipPath, it)
}
+ isDirty = false
}
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
index 5680642..dbf1063 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
@@ -286,7 +286,6 @@
}
override fun dispatchDraw(canvas: android.graphics.Canvas) {
- isInvalidated = false
canvasHolder.drawInto(canvas) {
var didClip = false
val clipPath = manualClipPath
@@ -300,6 +299,7 @@
restore()
}
}
+ isInvalidated = false
}
override fun invalidate() {
@@ -335,8 +335,8 @@
override fun updateDisplayList() {
if (isInvalidated && !shouldUseDispatchDraw) {
- isInvalidated = false
updateDisplayList(this)
+ isInvalidated = false
}
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/PainterResources.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/PainterResources.android.kt
index 6158d92..b075bfc 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/PainterResources.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/PainterResources.android.kt
@@ -67,7 +67,7 @@
} else {
// Otherwise load the bitmap resource
val imageBitmap = remember(path, id, context.theme) {
- loadImageBitmapResource(res, id)
+ loadImageBitmapResource(path, res, id)
}
BitmapPainter(imageBitmap)
}
@@ -104,13 +104,21 @@
* an ImageBitmap resource. Because this throws exceptions we cannot have this implementation
* as part of the composable implementation it is invoked in.
*/
-private fun loadImageBitmapResource(res: Resources, id: Int): ImageBitmap {
+private fun loadImageBitmapResource(path: CharSequence, res: Resources, id: Int): ImageBitmap {
try {
return ImageBitmap.imageResource(res, id)
- } catch (throwable: Throwable) {
- throw IllegalArgumentException(errorMessage)
+ } catch (exception: Exception) {
+ throw ResourceResolutionException("Error attempting to load resource: $path", exception)
}
}
+/**
+ * [Throwable] that is thrown in situations where a resource failed to load.
+ */
+class ResourceResolutionException(
+ message: String,
+ cause: Throwable
+) : RuntimeException(message, cause)
+
private const val errorMessage =
- "Only VectorDrawables and rasterized asset types are supported ex. PNG, JPG"
\ No newline at end of file
+ "Only VectorDrawables and rasterized asset types are supported ex. PNG, JPG, WEBP"
\ No newline at end of file
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 3ae949a..411909b 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
@@ -52,17 +52,10 @@
internal class TextInputServiceAndroid(
val view: View,
private val inputMethodManager: InputMethodManager,
- private val platformTextInput: PlatformTextInput?,
+ private val platformTextInput: PlatformTextInput? = null,
private val inputCommandProcessorExecutor: Executor = Choreographer.getInstance().asExecutor(),
) : PlatformTextInputService {
- // Non-experimental constructor.
- constructor(
- view: View,
- inputMethodManager: InputMethodManager,
- inputCommandProcessorExecutor: Executor = Choreographer.getInstance().asExecutor(),
- ) : this(view, inputMethodManager, platformTextInput = null, inputCommandProcessorExecutor)
-
/**
* Commands that can be sent into [textInputCommandQueue] to be processed by
* [processInputCommands].
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
index e47c66b..86c5c68 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
@@ -32,11 +32,14 @@
import androidx.compose.runtime.rememberCompositionContext
import androidx.compose.runtime.saveable.LocalSaveableStateRegistry
import androidx.compose.runtime.saveable.SaveableStateRegistry
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.InternalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.UiComposable
import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher
import androidx.compose.ui.materialize
-import androidx.compose.ui.node.ComposeUiNode
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetCompositeKeyHash
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetResolvedCompositionLocals
import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.node.UiApplier
import androidx.compose.ui.platform.LocalContext
@@ -204,6 +207,7 @@
onRelease: (T) -> Unit = NoOpUpdate,
update: (T) -> Unit = NoOpUpdate
) {
+ val compositeKeyHash = currentCompositeKeyHash
val materializedModifier = currentComposer.materialize(modifier)
val density = LocalDensity.current
val layoutDirection = LocalLayoutDirection.current
@@ -222,6 +226,7 @@
update = {
updateViewHolderParams<T>(
modifier = materializedModifier,
+ compositeKeyHash = compositeKeyHash,
density = density,
lifecycleOwner = lifecycleOwner,
savedStateRegistryOwner = savedStateRegistryOwner,
@@ -239,6 +244,7 @@
update = {
updateViewHolderParams<T>(
modifier = materializedModifier,
+ compositeKeyHash = compositeKeyHash,
density = density,
lifecycleOwner = lifecycleOwner,
savedStateRegistryOwner = savedStateRegistryOwner,
@@ -256,31 +262,32 @@
private fun <T : View> createAndroidViewNodeFactory(
factory: (Context) -> T
): () -> LayoutNode {
+ val compositeKeyHash = currentCompositeKeyHash
val context = LocalContext.current
val parentReference = rememberCompositionContext()
val stateRegistry = LocalSaveableStateRegistry.current
- val stateKey = currentCompositeKeyHash.toString()
return {
- ViewFactoryHolder<T>(
+ ViewFactoryHolder(
context = context,
factory = factory,
parentContext = parentReference,
saveStateRegistry = stateRegistry,
- saveStateKey = stateKey
+ compositeKeyHash = compositeKeyHash
).layoutNode
}
}
private fun <T : View> Updater<LayoutNode>.updateViewHolderParams(
modifier: Modifier,
+ compositeKeyHash: Int,
density: Density,
lifecycleOwner: LifecycleOwner,
savedStateRegistryOwner: SavedStateRegistryOwner,
layoutDirection: LayoutDirection,
compositionLocalMap: CompositionLocalMap
) {
- set(compositionLocalMap, ComposeUiNode.SetResolvedCompositionLocals)
+ set(compositionLocalMap, SetResolvedCompositionLocals)
set(modifier) { requireViewFactoryHolder<T>().modifier = it }
set(density) { requireViewFactoryHolder<T>().density = it }
set(lifecycleOwner) { requireViewFactoryHolder<T>().lifecycleOwner = it }
@@ -293,10 +300,13 @@
LayoutDirection.Rtl -> android.util.LayoutDirection.RTL
}
}
+ @OptIn(ExperimentalComposeUiApi::class)
+ set(compositeKeyHash, SetCompositeKeyHash)
}
@Suppress("UNCHECKED_CAST")
private fun <T : View> LayoutNode.requireViewFactoryHolder(): ViewFactoryHolder<T> {
+ @OptIn(InternalComposeUiApi::class)
return checkNotNull(interopViewFactoryHolder) as ViewFactoryHolder<T>
}
@@ -308,30 +318,33 @@
internal class ViewFactoryHolder<T : View> private constructor(
context: Context,
parentContext: CompositionContext? = null,
- val typedView: T,
+ private val typedView: T,
// NestedScrollDispatcher that will be passed/used for nested scroll interop
val dispatcher: NestedScrollDispatcher = NestedScrollDispatcher(),
private val saveStateRegistry: SaveableStateRegistry?,
- private val saveStateKey: String
-) : AndroidViewHolder(context, parentContext, dispatcher, typedView), ViewRootForInspector {
+ private val compositeKeyHash: Int,
+) : AndroidViewHolder(context, parentContext, compositeKeyHash, dispatcher, typedView),
+ ViewRootForInspector {
constructor(
context: Context,
factory: (Context) -> T,
parentContext: CompositionContext? = null,
saveStateRegistry: SaveableStateRegistry?,
- saveStateKey: String
+ compositeKeyHash: Int
) : this(
context = context,
typedView = factory(context),
parentContext = parentContext,
saveStateRegistry = saveStateRegistry,
- saveStateKey = saveStateKey,
+ compositeKeyHash = compositeKeyHash,
)
override val viewRoot: View get() = this
- private var saveableRegistryEntry: SaveableStateRegistry.Entry? = null
+ private val saveStateKey: String
+
+ private var savableRegistryEntry: SaveableStateRegistry.Entry? = null
set(value) {
field?.unregister()
field = value
@@ -339,6 +352,7 @@
init {
clipChildren = false
+ saveStateKey = compositeKeyHash.toString()
@Suppress("UNCHECKED_CAST")
val savedState = saveStateRegistry
@@ -370,7 +384,7 @@
private fun registerSaveStateProvider() {
if (saveStateRegistry != null) {
- saveableRegistryEntry = saveStateRegistry.registerProvider(saveStateKey) {
+ savableRegistryEntry = saveStateRegistry.registerProvider(saveStateKey) {
SparseArray<Parcelable>().apply {
typedView.saveHierarchyState(this)
}
@@ -379,6 +393,6 @@
}
private fun unregisterSaveStateProvider() {
- saveableRegistryEntry = null
+ savableRegistryEntry = null
}
}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
index 4f322a1..b646acd 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
@@ -28,6 +28,7 @@
import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.snapshots.SnapshotStateObserver
import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.InternalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
@@ -73,6 +74,7 @@
internal open class AndroidViewHolder(
context: Context,
parentContext: CompositionContext?,
+ private val compositeKeyHash: Int,
private val dispatcher: NestedScrollDispatcher,
/**
* The view hosted by this holder.
@@ -177,6 +179,10 @@
}
}
+ private val runInvalidate: () -> Unit = {
+ layoutNode.invalidateLayer()
+ }
+
internal var onRequestDisallowInterceptTouchEvent: ((Boolean) -> Unit)? = null
private val location = IntArray(2)
@@ -187,6 +193,8 @@
private val nestedScrollingParentHelper: NestedScrollingParentHelper =
NestedScrollingParentHelper(this)
+ private var isDrawing = false
+
override fun onReuse() {
// We reset at the same time we remove the view. So if the view was removed, we can just
// re-add it and it's ready to go. If it's already attached, we didn't reset it and need
@@ -262,14 +270,26 @@
@Suppress("Deprecation")
override fun invalidateChildInParent(location: IntArray?, dirty: Rect?): ViewParent? {
super.invalidateChildInParent(location, dirty)
- layoutNode.invalidateLayer()
+ invalidateOrDefer()
return null
}
override fun onDescendantInvalidated(child: View, target: View) {
// We need to call super here in order to correctly update the dirty flags of the holder.
super.onDescendantInvalidated(child, target)
- layoutNode.invalidateLayer()
+ invalidateOrDefer()
+ }
+
+ fun invalidateOrDefer() {
+ if (isDrawing) {
+ // If an invalidation occurs while drawing invalidate until next frame to avoid
+ // redrawing multiple times during the same frame the same content.
+ view.postOnAnimation(runInvalidate)
+ } else {
+ // when not drawing, we can invalidate any time and not risk multiple draws, we don't
+ // defer to avoid waiting a full frame to draw content.
+ layoutNode.invalidateLayer()
+ }
}
override fun onWindowVisibilityChanged(visibility: Int) {
@@ -305,6 +325,7 @@
val layoutNode: LayoutNode = run {
// Prepare layout node that proxies measure and layout passes to the View.
val layoutNode = LayoutNode()
+ @OptIn(InternalComposeUiApi::class)
layoutNode.interopViewFactoryHolder = this@AndroidViewHolder
val coreModifier = Modifier
@@ -313,14 +334,17 @@
.pointerInteropFilter(this)
.drawBehind {
drawIntoCanvas { canvas ->
+ isDrawing = true
(layoutNode.owner as? AndroidComposeView)
?.drawAndroidView(this@AndroidViewHolder, canvas.nativeCanvas)
+ isDrawing = false
}
}.onGloballyPositioned {
// The global position of this LayoutNode can change with it being replaced. For
// these cases, we need to inform the View.
layoutAccordingTo(layoutNode)
}
+ layoutNode.compositeKeyHash = compositeKeyHash
layoutNode.modifier = modifier.then(coreModifier)
onModifierChanged = { layoutNode.modifier = it.then(coreModifier) }
@@ -565,4 +589,4 @@
private fun toNestedScrollSource(type: Int): NestedScrollSource = when (type) {
ViewCompat.TYPE_TOUCH -> NestedScrollSource.Drag
else -> NestedScrollSource.Fling
-}
\ No newline at end of file
+}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/DrawModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/DrawModifier.kt
index 0408729..3c02269 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/DrawModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/DrawModifier.kt
@@ -22,7 +22,6 @@
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.internal.JvmDefaultWithCompatibility
-import androidx.compose.ui.node.CacheDrawModifierNode
import androidx.compose.ui.node.DrawModifierNode
import androidx.compose.ui.node.ModifierNodeElement
import androidx.compose.ui.node.Nodes
@@ -161,6 +160,15 @@
return CacheDrawModifierNodeImpl(CacheDrawScope(), onBuildDrawCache)
}
+/**
+ * Expands on the [androidx.compose.ui.node.DrawModifierNode] by adding the ability to invalidate
+ * the draw cache for changes in things like shapes and bitmaps (see Modifier.border for a usage
+ * examples).
+ */
+sealed interface CacheDrawModifierNode : DrawModifierNode {
+ fun invalidateDrawCache()
+}
+
private class CacheDrawModifierNodeImpl(
private val cacheDrawScope: CacheDrawScope,
block: CacheDrawScope.() -> DrawResult
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusEventModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusEventModifierNode.kt
index e37c8d7..4d51d46 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusEventModifierNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusEventModifierNode.kt
@@ -45,7 +45,7 @@
internal fun FocusEventModifierNode.getFocusState(): FocusState {
visitSelfAndChildren(Nodes.FocusTarget) {
- when (val focusState = it.focusStateImpl) {
+ when (val focusState = it.focusState) {
// If we find a focused child, we use that child's state as the aggregated state.
Active, ActiveParent, Captured -> return focusState
// We use the Inactive state only if we don't have a focused child.
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwnerImpl.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwnerImpl.kt
index b743bd4..935a8f5 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwnerImpl.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwnerImpl.kt
@@ -87,8 +87,8 @@
override fun takeFocus() {
// If the focus state is not Inactive, it indicates that the focus state is already
// set (possibly by dispatchWindowFocusChanged). So we don't update the state.
- if (rootFocusNode.focusStateImpl == Inactive) {
- rootFocusNode.focusStateImpl = Active
+ if (rootFocusNode.focusState == Inactive) {
+ rootFocusNode.focusState = Active
// TODO(b/152535715): propagate focus to children based on child focusability.
// moveFocus(FocusDirection.Enter)
}
@@ -130,9 +130,9 @@
// If this hierarchy had focus before clearing it, it indicates that the host view has
// focus. So after clearing focus within the compose hierarchy, we should restore focus to
// the root focus modifier to maintain consistency with the host view.
- val rootInitialState = rootFocusNode.focusStateImpl
+ val rootInitialState = rootFocusNode.focusState
if (rootFocusNode.clearFocus(force, refreshFocusEvents)) {
- rootFocusNode.focusStateImpl = when (rootInitialState) {
+ rootFocusNode.focusState = when (rootInitialState) {
Active, ActiveParent, Captured -> Active
Inactive -> Inactive
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt
new file mode 100644
index 0000000..f80d68f
--- /dev/null
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.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.compose.ui.focus
+
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.node.DelegatableNode
+
+/**
+ * This modifier node can be used to create a modifier that makes a component focusable.
+ */
+sealed interface FocusTargetModifierNode : DelegatableNode {
+ /**
+ * The [FocusState] associated with this [FocusTargetModifierNode]. When you implement a
+ * [FocusTargetModifierNode], instead of implementing [FocusEventModifierNode], you can get the
+ * state by accessing this variable.
+ */
+ @ExperimentalComposeUiApi
+ val focusState: FocusState
+}
+
+/**
+ * This modifier node can be used to create a modifier that makes a component focusable.
+ * Use a different instance of [FocusTargetModifierNode] for each focusable component.
+ */
+fun FocusTargetModifierNode(): FocusTargetModifierNode = FocusTargetNode()
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetNode.kt
index 2d79ccf..7ed4db0 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetNode.kt
@@ -36,22 +36,19 @@
import androidx.compose.ui.node.visitSelfAndAncestors
import androidx.compose.ui.platform.InspectorInfo
-/**
- * This modifier node can be used to create a modifier that makes a component focusable.
- * Use a different instance of [FocusTargetNode] for each focusable component.
- */
-class FocusTargetNode : ObserverModifierNode, ModifierLocalModifierNode, Modifier.Node() {
- /**
- * The [FocusState] associated with this [FocusTargetNode].
- */
- val focusState: FocusState
- get() = focusStateImpl
+internal class FocusTargetNode :
+ FocusTargetModifierNode,
+ ObserverModifierNode,
+ ModifierLocalModifierNode,
+ Modifier.Node() {
private var isProcessingCustomExit = false
private var isProcessingCustomEnter = false
- internal var focusStateImpl = Inactive
- internal val beyondBoundsLayoutParent: BeyondBoundsLayout?
+ @OptIn(ExperimentalComposeUiApi::class)
+ override var focusState: FocusStateImpl = Inactive
+
+ val beyondBoundsLayoutParent: BeyondBoundsLayout?
get() = ModifierLocalBeyondBoundsLayout.current
override fun onObservedReadsChanged() {
@@ -72,7 +69,7 @@
ActiveParent -> {
scheduleInvalidationForFocusEvents()
// This node might be reused, so reset the state to Inactive.
- focusStateImpl = Inactive
+ focusState = Inactive
}
Inactive -> scheduleInvalidationForFocusEvents()
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt
index 266789b..a791a39 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt
@@ -54,23 +54,21 @@
* custom focus [enter][FocusProperties.enter] and [exit][FocusProperties.exit]
* [properties][FocusProperties] have been specified.
*/
-internal fun FocusTargetNode.performRequestFocus(): Boolean {
- when (focusStateImpl) {
- Active, Captured -> {
- // There is no change in focus state, but we send a focus event to notify the user
- // that the focus request is completed.
- refreshFocusEventNodes()
- return true
- }
- ActiveParent -> return (clearChildFocus() && grantFocus()).also { success ->
+internal fun FocusTargetNode.performRequestFocus(): Boolean = when (focusState) {
+ Active, Captured -> {
+ // There is no change in focus state, but we send a focus event to notify the user
+ // that the focus request is completed.
+ refreshFocusEventNodes()
+ true
+ }
+ ActiveParent -> (clearChildFocus() && grantFocus()).also { success ->
+ if (success) refreshFocusEventNodes()
+ }
+ Inactive -> nearestAncestor(FocusTarget)
+ ?.requestFocusForChild(this)
+ ?: (requestFocusForOwner() && grantFocus()).also { success ->
if (success) refreshFocusEventNodes()
}
- Inactive -> return nearestAncestor(FocusTarget)
- ?.requestFocusForChild(this)
- ?: (requestFocusForOwner() && grantFocus()).also { success ->
- if (success) refreshFocusEventNodes()
- }
- }
}
/**
@@ -81,9 +79,9 @@
*
* @return true if the focus was successfully captured. False otherwise.
*/
-internal fun FocusTargetNode.captureFocus() = when (focusStateImpl) {
+internal fun FocusTargetNode.captureFocus() = when (focusState) {
Active -> {
- focusStateImpl = Captured
+ focusState = Captured
refreshFocusEventNodes()
true
}
@@ -98,9 +96,9 @@
*
* @return true if the captured focus was released. False Otherwise.
*/
-internal fun FocusTargetNode.freeFocus() = when (focusStateImpl) {
+internal fun FocusTargetNode.freeFocus() = when (focusState) {
Captured -> {
- focusStateImpl = Active
+ focusState = Active
refreshFocusEventNodes()
true
}
@@ -118,9 +116,9 @@
internal fun FocusTargetNode.clearFocus(
forced: Boolean = false,
refreshFocusEvents: Boolean
-): Boolean = when (focusStateImpl) {
+): Boolean = when (focusState) {
Active -> {
- focusStateImpl = Inactive
+ focusState = Inactive
if (refreshFocusEvents) refreshFocusEventNodes()
true
}
@@ -129,7 +127,7 @@
* first, before clearing focus from this node.
*/
ActiveParent -> if (clearChildFocus(forced, refreshFocusEvents)) {
- focusStateImpl = Inactive
+ focusState = Inactive
if (refreshFocusEvents) refreshFocusEventNodes()
true
} else {
@@ -141,7 +139,7 @@
*/
Captured -> {
if (forced) {
- focusStateImpl = Inactive
+ focusState = Inactive
if (refreshFocusEvents) refreshFocusEventNodes()
}
forced
@@ -162,8 +160,8 @@
// If canFocus is set to false, we need to clear focus.
observeReads { fetchFocusProperties() }
// No Focused Children, or we don't want to propagate focus to children.
- when (focusStateImpl) {
- Inactive, ActiveParent -> focusStateImpl = Active
+ when (focusState) {
+ Inactive, ActiveParent -> focusState = Active
Active, Captured -> { /* Already focused. */ }
}
return true
@@ -191,11 +189,11 @@
error("Non child node cannot request focus.")
}
- return when (focusStateImpl) {
+ return when (focusState) {
// If this node is [Active], it can give focus to the requesting child.
Active -> childNode.grantFocus().also { success ->
if (success) {
- focusStateImpl = ActiveParent
+ focusState = ActiveParent
childNode.refreshFocusEventNodes()
refreshFocusEventNodes()
}
@@ -215,7 +213,7 @@
when {
// If this node is the root, request focus from the compose owner.
focusParent == null && requestFocusForOwner() -> {
- focusStateImpl = Active
+ focusState = Active
refreshFocusEventNodes()
requestFocusForChild(childNode)
}
@@ -249,13 +247,13 @@
internal fun FocusTargetNode.performCustomRequestFocus(
focusDirection: FocusDirection
): CustomDestinationResult {
- when (focusStateImpl) {
+ when (focusState) {
Active, Captured -> return None
ActiveParent ->
return checkNotNull(activeChild).performCustomClearFocus(focusDirection)
Inactive -> {
val focusParent = nearestAncestor(FocusTarget) ?: return None
- return when (focusParent.focusStateImpl) {
+ return when (focusParent.focusState) {
Captured -> Cancelled
ActiveParent -> focusParent.performCustomRequestFocus(focusDirection)
Active -> focusParent.performCustomEnter(focusDirection)
@@ -269,7 +267,7 @@
internal fun FocusTargetNode.performCustomClearFocus(
focusDirection: FocusDirection
-): CustomDestinationResult = when (focusStateImpl) {
+): CustomDestinationResult = when (focusState) {
Active, Inactive -> None
Captured -> Cancelled
ActiveParent ->
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTraversal.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTraversal.kt
index b920a76..3b51325 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTraversal.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTraversal.kt
@@ -138,7 +138,7 @@
if (!node.isAttached) return null
visitChildren(Nodes.FocusTarget) {
- when (it.focusStateImpl) {
+ when (it.focusState) {
Active, ActiveParent, Captured -> return it
Inactive -> return@visitChildren
}
@@ -146,9 +146,8 @@
return null
}
-@OptIn(ExperimentalComposeUiApi::class)
internal fun FocusTargetNode.findActiveFocusNode(): FocusTargetNode? {
- when (focusStateImpl) {
+ when (focusState) {
Active, Captured -> return this
ActiveParent -> {
visitChildren(Nodes.FocusTarget) { node ->
@@ -161,7 +160,6 @@
}
@Suppress("ModifierFactoryExtensionFunction", "ModifierFactoryReturnType")
-@OptIn(ExperimentalComposeUiApi::class)
private fun FocusTargetNode.findNonDeactivatedParent(): FocusTargetNode? {
visitAncestors(Nodes.FocusTarget) {
if (it.fetchFocusProperties().canFocus) return it
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt
index b6b0b12..4855f77 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt
@@ -18,7 +18,6 @@
import androidx.compose.runtime.collection.MutableVector
import androidx.compose.runtime.collection.mutableVectorOf
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.focus.FocusDirection.Companion.Next
import androidx.compose.ui.focus.FocusDirection.Companion.Previous
import androidx.compose.ui.focus.FocusStateImpl.Active
@@ -32,7 +31,9 @@
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
+@Suppress("ConstPropertyName")
private const val InvalidFocusDirection = "This function should only be used for 1-D focus search"
+@Suppress("ConstPropertyName")
private const val NoActiveChild = "ActiveParent must have a focusedChild"
internal fun FocusTargetNode.oneDimensionalFocusSearch(
@@ -46,7 +47,7 @@
private fun FocusTargetNode.forwardFocusSearch(
onFound: (FocusTargetNode) -> Boolean
-): Boolean = when (focusStateImpl) {
+): Boolean = when (focusState) {
ActiveParent -> {
val focusedChild = activeChild ?: error(NoActiveChild)
focusedChild.forwardFocusSearch(onFound) ||
@@ -62,12 +63,12 @@
private fun FocusTargetNode.backwardFocusSearch(
onFound: (FocusTargetNode) -> Boolean
-): Boolean = when (focusStateImpl) {
+): Boolean = when (focusState) {
ActiveParent -> {
val focusedChild = activeChild ?: error(NoActiveChild)
// Unlike forwardFocusSearch, backwardFocusSearch visits the children before the parent.
- when (focusedChild.focusStateImpl) {
+ when (focusedChild.focusState) {
ActiveParent -> focusedChild.backwardFocusSearch(onFound) ||
generateAndSearchChildren(focusedChild, Previous, onFound) ||
(focusedChild.fetchFocusProperties().canFocus && onFound.invoke(focusedChild))
@@ -120,7 +121,7 @@
direction: FocusDirection,
onFound: (FocusTargetNode) -> Boolean
): Boolean {
- check(focusStateImpl == ActiveParent) {
+ check(focusState == ActiveParent) {
"This function should only be used within a parent that has focus."
}
val children = MutableVector<FocusTargetNode>().apply {
@@ -171,7 +172,6 @@
return false
}
-@OptIn(ExperimentalComposeUiApi::class)
private fun FocusTargetNode.isRoot() = nearestAncestor(Nodes.FocusTarget) == null
@Suppress("BanInlineOptIn")
@@ -217,7 +217,6 @@
* order index. This would be more expensive than sorting the items. In addition to this, sorting
* the items makes the next focus search more efficient.
*/
-@OptIn(ExperimentalComposeUiApi::class)
private object FocusableChildrenComparator : Comparator<FocusTargetNode> {
override fun compare(
focusTarget1: FocusTargetNode?,
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt
index 4970e34..957db41 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt
@@ -34,7 +34,9 @@
import kotlin.math.absoluteValue
import kotlin.math.max
+@Suppress("ConstPropertyName")
private const val InvalidFocusDirection = "This function should only be used for 2-D focus search"
+@Suppress("ConstPropertyName")
private const val NoActiveChild = "ActiveParent must have a focusedChild"
/**
@@ -52,7 +54,7 @@
direction: FocusDirection,
onFound: (FocusTargetNode) -> Boolean
): Boolean? {
- when (focusStateImpl) {
+ when (focusState) {
Inactive -> return if (fetchFocusProperties().canFocus) onFound.invoke(this) else false
ActiveParent -> {
val focusedChild = activeChild ?: error(NoActiveChild)
@@ -61,7 +63,7 @@
// search to a child only if it "has focus". If this node "is focused", we just skip the
// children and search among the siblings of the focused item by calling
// "searchChildren" on this node.
- when (focusedChild.focusStateImpl) {
+ when (focusedChild.focusState) {
ActiveParent -> {
// If the focusedChild is an intermediate parent, we search among its children.
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/SoftKeyboardInterceptionModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/SoftKeyboardInterceptionModifierNode.kt
index 31eb488..ceec4f7 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/SoftKeyboardInterceptionModifierNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/SoftKeyboardInterceptionModifierNode.kt
@@ -22,7 +22,9 @@
/**
* Implement this interface to create a [Modifier.Node] that can intercept hardware Key events
- * before they are sent to the software keyboard.
+ * before they are sent to the software keyboard. This can be used to intercept key input from a
+ * DPad, or physical keyboard connected to the device and is not applicable to input that is sent
+ * to the soft keyboard via spell check or autocomplete.
*
* The event is routed to the focused item. Before reaching the focused item,
* [onPreInterceptKeyBeforeSoftKeyboard] is called for parents of the focused item.
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/SoftwareKeyboardInterceptionModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/SoftwareKeyboardInterceptionModifier.kt
index be03189..6c2ea62 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/SoftwareKeyboardInterceptionModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/SoftwareKeyboardInterceptionModifier.kt
@@ -23,7 +23,9 @@
/**
* Adding this [modifier][Modifier] to the [modifier][Modifier] parameter of a component will
- * allow it to intercept hardware key events before they are sent to the software keyboard.
+ * allow it to intercept hardware key events before they are sent to the software keyboard. This
+ * can be used to intercept key input from a DPad, or physical keyboard connected to the device and
+ * is not applicable to input that is sent to the soft keyboard via spell check or autocomplete.
*
* @param onInterceptKeyBeforeSoftKeyboard This callback is invoked when the user interacts with
* the hardware keyboard. While implementing this callback, return true to stop propagation of this
@@ -43,8 +45,10 @@
/**
* Adding this [modifier][Modifier] to the [modifier][Modifier] parameter of a component will
* allow it to intercept hardware key events before they are sent to the software keyboard. This
- * modifier is similar to [onInterceptKeyBeforeSoftKeyboard], but allows a parent composable to
- * intercept the hardware key event before any child.
+ * can be used to intercept key input from a DPad, or physical keyboard connected to the device and
+ * is not applicable to input that is sent to the soft keyboard via spell check or autocomplete.
+ * This modifier is similar to [onInterceptKeyBeforeSoftKeyboard], but allows a parent composable
+ * to intercept the hardware key event before any child.
*
* @param onPreInterceptKeyBeforeSoftKeyboard This callback is invoked when the user interacts
* with the hardware keyboard. It gives ancestors of a focused component the chance to intercept a
@@ -66,13 +70,13 @@
private data class SoftKeyboardInterceptionElement(
val onKeyEvent: ((KeyEvent) -> Boolean)?,
val onPreKeyEvent: ((KeyEvent) -> Boolean)?
-) : ModifierNodeElement<InterceptedKeyInputModifierNodeImpl>() {
- override fun create() = InterceptedKeyInputModifierNodeImpl(
+) : ModifierNodeElement<InterceptedKeyInputNode>() {
+ override fun create() = InterceptedKeyInputNode(
onEvent = onKeyEvent,
onPreEvent = onPreKeyEvent
)
- override fun update(node: InterceptedKeyInputModifierNodeImpl) {
+ override fun update(node: InterceptedKeyInputNode) {
node.onEvent = onKeyEvent
node.onPreEvent = onPreKeyEvent
}
@@ -90,7 +94,7 @@
}
@OptIn(ExperimentalComposeUiApi::class)
-private class InterceptedKeyInputModifierNodeImpl(
+private class InterceptedKeyInputNode(
var onEvent: ((KeyEvent) -> Boolean)?,
var onPreEvent: ((KeyEvent) -> Boolean)?
) : SoftKeyboardInterceptionModifierNode, Modifier.Node() {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifier.kt
index 6c559ba..7209acf4 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifier.kt
@@ -236,7 +236,7 @@
Fling -> "Fling"
@OptIn(ExperimentalComposeUiApi::class)
Relocate -> "Relocate"
-
+ Wheel -> "Wheel"
else -> "Invalid"
}
}
@@ -260,6 +260,11 @@
@ExperimentalComposeUiApi
@Deprecated("Do not use. Will be removed in the future.")
val Relocate: NestedScrollSource = NestedScrollSource(3)
+
+ /**
+ * Scrolling via mouse wheel.
+ */
+ val Wheel: NestedScrollSource = NestedScrollSource(4)
}
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt
index abd9b6a..1e6d25b 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt
@@ -16,10 +16,12 @@
package androidx.compose.ui.input.pointer
+import androidx.collection.LongSparseArray
import androidx.compose.runtime.collection.MutableVector
import androidx.compose.runtime.collection.mutableVectorOf
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.pointer.util.PointerIdArray
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.node.InternalCoreApi
import androidx.compose.ui.node.Nodes
@@ -63,7 +65,7 @@
}
if (node != null) {
node.markIsIn()
- if (pointerId !in node.pointerIds) node.pointerIds.add(pointerId)
+ node.pointerIds.add(pointerId)
parent = node
continue@eachPin
} else {
@@ -143,7 +145,7 @@
val children: MutableVector<Node> = mutableVectorOf()
open fun buildCache(
- changes: Map<PointerId, PointerInputChange>,
+ changes: LongSparseArray<PointerInputChange>,
parentCoordinates: LayoutCoordinates,
internalPointerEvent: InternalPointerEvent,
isInBounds: Boolean
@@ -173,7 +175,7 @@
* @param internalPointerEvent the [InternalPointerEvent] needed to construct [PointerEvent]s
*/
open fun dispatchMainEventPass(
- changes: Map<PointerId, PointerInputChange>,
+ changes: LongSparseArray<PointerInputChange>,
parentCoordinates: LayoutCoordinates,
internalPointerEvent: InternalPointerEvent,
isInBounds: Boolean
@@ -254,13 +256,10 @@
@OptIn(InternalCoreApi::class, ExperimentalComposeUiApi::class)
internal class Node(val modifierNode: Modifier.Node) : NodeParent() {
- // Note: this is essentially a set, and writes should be guarded accordingly. We use a
- // MutableVector here instead since a set ends up being quite heavy, and calls to
- // set.contains() show up noticeably (~1%) in traces. Since the maximum size of this vector
- // is small (due to the limited amount of concurrent PointerIds there _could_ be), iterating
- // through the small vector in most cases should have a lower performance impact than using a
- // set.
- val pointerIds: MutableVector<PointerId> = mutableVectorOf()
+ // Note: pointerIds are stored in a structure specific to their value type (PointerId).
+ // This structure uses a LongArray internally, which avoids auto-boxing caused by
+ // a more generic collection such as HashMap or MutableVector.
+ val pointerIds = PointerIdArray()
/**
* Cached properties that will be set before the main event pass, and reset after the final
@@ -270,15 +269,16 @@
* @see buildCache
* @see clearCache
*/
- private val relevantChanges: MutableMap<PointerId, PointerInputChange> = mutableMapOf()
+ private val relevantChanges: LongSparseArray<PointerInputChange> = LongSparseArray(2)
private var coordinates: LayoutCoordinates? = null
private var pointerEvent: PointerEvent? = null
private var wasIn = false
private var isIn = true
private var hasExited = true
+ val vec = mutableVectorOf<Long>()
override fun dispatchMainEventPass(
- changes: Map<PointerId, PointerInputChange>,
+ changes: LongSparseArray<PointerInputChange>,
parentCoordinates: LayoutCoordinates,
internalPointerEvent: InternalPointerEvent,
isInBounds: Boolean
@@ -354,7 +354,7 @@
* @see clearCache
*/
override fun buildCache(
- changes: Map<PointerId, PointerInputChange>,
+ changes: LongSparseArray<PointerInputChange>,
parentCoordinates: LayoutCoordinates,
internalPointerEvent: InternalPointerEvent,
isInBounds: Boolean
@@ -375,19 +375,11 @@
}
@OptIn(ExperimentalComposeUiApi::class)
- for ((key, change) in changes) {
- val keyValue = key.value
+ for (j in 0 until changes.size()) {
+ val keyValue = changes.keyAt(j)
+ val change = changes.valueAt(j)
- // Using for (key in pointerIds) causes key to be boxed and create allocations
- var keyInPointerIds = false
- for (i in 0..pointerIds.lastIndex) {
- if (pointerIds[i].value == keyValue) {
- keyInPointerIds = true
- break
- }
- }
-
- if (keyInPointerIds) {
+ if (pointerIds.contains(keyValue)) {
// And translate their position relative to the parent coordinates, to give us a
// change local to the PointerInputFilter's coordinates
val historical = ArrayList<HistoricalChange>(change.historical.size)
@@ -400,7 +392,7 @@
)
}
- relevantChanges[key] = change.copy(
+ relevantChanges.put(keyValue, change.copy(
previousPosition = coordinates!!.localPositionOf(
parentCoordinates,
change.previousPosition
@@ -410,7 +402,7 @@
change.position
),
historical = historical
- )
+ ))
}
}
@@ -423,12 +415,16 @@
// Clean up any pointerIds that weren't dispatched
for (i in pointerIds.lastIndex downTo 0) {
val pointerId = pointerIds[i]
- if (!changes.containsKey(pointerId)) {
+ if (!changes.containsKey(pointerId.value)) {
pointerIds.removeAt(i)
}
}
- val event = PointerEvent(relevantChanges.values.toList(), internalPointerEvent)
+ val changesList = ArrayList<PointerInputChange>(relevantChanges.size())
+ for (i in 0 until relevantChanges.size()) {
+ changesList.add(relevantChanges.valueAt(i))
+ }
+ val event = PointerEvent(changesList, internalPointerEvent)
val enterExitChange = event.changes.fastFirstOrNull {
internalPointerEvent.issuesEnterExitEvent(it.id)
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerInput.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerInput.kt
index 4ead18f..ed60c9a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerInput.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerInput.kt
@@ -16,6 +16,7 @@
package androidx.compose.ui.input.pointer
+import androidx.collection.LongSparseArray
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.node.InternalCoreApi
@@ -61,10 +62,10 @@
*/
@OptIn(InternalCoreApi::class)
internal expect class InternalPointerEvent(
- changes: Map<PointerId, PointerInputChange>,
+ changes: LongSparseArray<PointerInputChange>,
pointerInputEvent: PointerInputEvent
) {
- val changes: Map<PointerId, PointerInputChange>
+ val changes: LongSparseArray<PointerInputChange>
/**
* Embedded Android Views may consume an event and [ProcessResult] should not
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessor.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessor.kt
index dd43434..4ead517 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessor.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessor.kt
@@ -16,6 +16,7 @@
package androidx.compose.ui.input.pointer
+import androidx.collection.LongSparseArray
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.node.HitTestResult
@@ -54,6 +55,7 @@
* @see PointerInputEvent
*/
fun process(
+ @OptIn(InternalCoreApi::class)
pointerEvent: PointerInputEvent,
positionCalculator: PositionCalculator,
isInBounds: Boolean = true
@@ -69,14 +71,22 @@
isProcessing = true
// Gets a new PointerInputChangeEvent with the PointerInputEvent.
+ @OptIn(InternalCoreApi::class)
val internalPointerEvent =
pointerInputChangeEventProducer.produce(pointerEvent, positionCalculator)
- val isHover =
- !internalPointerEvent.changes.values.any { it.pressed || it.previousPressed }
+ var isHover = true
+ for (i in 0 until internalPointerEvent.changes.size()) {
+ val pointerInputChange = internalPointerEvent.changes.valueAt(i)
+ if (pointerInputChange.pressed || pointerInputChange.previousPressed) {
+ isHover = false
+ break
+ }
+ }
// Add new hit paths to the tracker due to down events.
- internalPointerEvent.changes.values.forEach { pointerInputChange ->
+ for (i in 0 until internalPointerEvent.changes.size()) {
+ val pointerInputChange = internalPointerEvent.changes.valueAt(i)
if (isHover || pointerInputChange.changedToDownIgnoreConsumed()) {
val isTouchEvent = pointerInputChange.type == PointerType.Touch
root.hitTest(pointerInputChange.position, hitResult, isTouchEvent)
@@ -98,8 +108,15 @@
val anyMovementConsumed = if (internalPointerEvent.suppressMovementConsumption) {
false
} else {
- internalPointerEvent.changes.values
- .any { it.positionChangedIgnoreConsumed() && it.isConsumed }
+ var result = false
+ for (i in 0 until internalPointerEvent.changes.size()) {
+ val event = internalPointerEvent.changes.valueAt(i)
+ if (event.positionChangedIgnoreConsumed() && event.isConsumed) {
+ result = true
+ break
+ }
+ }
+ result
}
return ProcessResult(dispatchedToSomething, anyMovementConsumed)
@@ -130,7 +147,7 @@
*/
@OptIn(InternalCoreApi::class, ExperimentalComposeUiApi::class)
private class PointerInputChangeEventProducer {
- private val previousPointerInputData: MutableMap<PointerId, PointerInputData> = mutableMapOf()
+ private val previousPointerInputData: LongSparseArray<PointerInputData> = LongSparseArray()
/**
* Produces [InternalPointerEvent]s by tracking changes between [PointerInputEvent]s
@@ -140,14 +157,14 @@
positionCalculator: PositionCalculator
): InternalPointerEvent {
// Set initial capacity to avoid resizing - we know the size the map will be.
- val changes: MutableMap<PointerId, PointerInputChange> =
- LinkedHashMap(pointerInputEvent.pointers.size)
+ val changes: LongSparseArray<PointerInputChange> =
+ LongSparseArray(pointerInputEvent.pointers.size)
pointerInputEvent.pointers.fastForEach {
val previousTime: Long
val previousPosition: Offset
val previousDown: Boolean
- val previousData = previousPointerInputData[it.id]
+ val previousData = previousPointerInputData[it.id.value]
if (previousData == null) {
previousTime = it.uptime
previousPosition = it.position
@@ -159,7 +176,7 @@
positionCalculator.screenToLocal(previousData.positionOnScreen)
}
- changes[it.id] =
+ changes.put(it.id.value,
PointerInputChange(
it.id,
it.uptime,
@@ -174,15 +191,16 @@
it.historical,
it.scrollDelta
)
+ )
if (it.down) {
- previousPointerInputData[it.id] = PointerInputData(
+ previousPointerInputData.put(it.id.value, PointerInputData(
it.uptime,
it.positionOnScreen,
it.down,
it.type
- )
+ ))
} else {
- previousPointerInputData.remove(it.id)
+ previousPointerInputData.remove(it.id.value)
}
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/util/PointerIdArray.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/util/PointerIdArray.kt
new file mode 100644
index 0000000..96c7925
--- /dev/null
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/util/PointerIdArray.kt
@@ -0,0 +1,179 @@
+/*
+ * 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.input.pointer.util
+
+import androidx.compose.ui.input.pointer.PointerId
+
+/**
+ * This collection is specifically for dealing with [PointerId] values. We know that they
+ * contain [Long] values, so we store them in an underlying LongArray. We want to be able to
+ * resize the array if there are many ids to be stored, so we recreate the internal LongArray
+ * as necessary (since LongArray is not itself resizable).
+ */
+internal class PointerIdArray {
+
+ /**
+ * The size of this [PointerIdArray], which is equal to the number of ids stored in the array.
+ */
+ // Note that this is different than the size of the backing LongArray, which may allocate more
+ // entries to avoid resizing for every additional id that is added.
+ var size = 0
+ private set
+
+ /**
+ * The ids are stored as Long values in a LongArray. LongArray is not resizable, and we may
+ * need to expand this array if there are many pointer ids in use at any given time, so we
+ * keep the LongArray private and resize the PointerIdArray by allocating a larger LongArray
+ * (and copying existing values to it) as necessary.
+ *
+ * By default, we allocate the underlying array with 2 elements, since it is uncommon (though
+ * possible) to have more than two ids at a time.
+ */
+ private var internalArray = LongArray(2)
+
+ /**
+ * Returns the PointerId at the given index.
+ * This getter allows use of [] syntax to retrieve values.
+ */
+ operator fun get(index: Int): PointerId {
+ return PointerId(internalArray[index])
+ }
+
+ /**
+ * Removes the given [PointerId] from this array, if it exists.
+ *
+ * @return true if [pointerId] was in the array, false otherwise
+ */
+ fun remove(pointerId: PointerId): Boolean {
+ return remove(pointerId.value)
+ }
+
+ /**
+ * Removes a [PointerId] with the given value from this array, if it exists.
+ *
+ * @return true if a [PointerId] with the value [pointerIdValue] was in the array,
+ * false otherwise
+ */
+ fun remove(pointerIdValue: Long): Boolean {
+ for (i in 0 until size) {
+ if (pointerIdValue == this[i].value) {
+ removeAt(i)
+ return true
+ }
+ }
+ return false
+ }
+
+ /**
+ * Removes the [PointerId] at the given index value, if the index is less than the size
+ * of the array.
+ *
+ * @return true if a [PointerId] at that index was removed, false otherwise
+ */
+ fun removeAt(index: Int): Boolean {
+ if (index < size) {
+ for (i in index until size - 1) {
+ internalArray[i] = internalArray[i + 1]
+ }
+ size--
+ return true
+ }
+ return false
+ }
+
+ /**
+ * Returns the current size of the array
+ */
+ fun isEmpty() = size == 0
+
+ /**
+ * Adds the given pointerId value to this array unless it is already there.
+ *
+ * @return true if id was added, false otherwise
+ */
+ fun add(value: Long): Boolean {
+ if (!contains(value)) {
+ set(size, value)
+ return true
+ }
+ return false
+ }
+
+ /**
+ * Adds the given pointerId value to this array unless it is already there.
+ *
+ * @return true if id was added, false otherwise
+ */
+ fun add(pointerId: PointerId): Boolean {
+ return add(pointerId.value)
+ }
+
+ /**
+ * Sets the value at the given index to a [PointerId] with the value [value].
+ * The index must be less than or equal to the current size of the array. If it is
+ * equal to the size of the array, the storage in the array will be expanded to
+ * ensure that the item can be added to the end of it.
+ */
+ operator fun set(index: Int, value: Long) {
+ if (index >= internalArray.size) {
+ // Increase the size of the backing array
+ internalArray = internalArray.copyOf(maxOf(index + 1, internalArray.size * 2))
+ }
+ internalArray[index] = value
+ if (index >= size) size = index + 1
+ }
+
+ /**
+ * Sets the value at the given index to [pointerId].
+ * The index must be less than or equal to the current size of the array. If it is
+ * equal to the size of the array, the storage in the array will be expanded to
+ * ensure that the item can be added to the end of it.
+ */
+ operator fun set(index: Int, pointerId: PointerId) {
+ set(index, pointerId.value)
+ }
+
+ /**
+ * Clears the array. The new [size] of the array will be 0.
+ */
+ fun clear() {
+ // No need to clear, just reset the size. Elements beyond the current size are ignored.
+ size = 0
+ }
+
+ /**
+ * Returns true if [pointerId] is in the array, false otherwise
+ */
+ fun contains(pointerId: PointerId): Boolean {
+ return contains(pointerId.value)
+ }
+
+ /**
+ * Returns true if a [PointerId] with the given value is in the array, false otherwise
+ */
+ fun contains(pointerIdValue: Long): Boolean {
+ for (i in 0 until size) {
+ if (internalArray[i] == pointerIdValue) return true
+ }
+ return false
+ }
+
+ /**
+ * Returns index of last item in array
+ */
+ inline val lastIndex: Int get() = size - 1
+}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/IntrinsicMeasureScope.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/IntrinsicMeasureScope.kt
index 657e31d..68891fa 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/IntrinsicMeasureScope.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/IntrinsicMeasureScope.kt
@@ -16,7 +16,6 @@
package androidx.compose.ui.layout
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
@@ -37,9 +36,6 @@
*
* @sample androidx.compose.ui.samples.animateContentSizeAfterLookaheadPass
*/
- @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
- @get:ExperimentalComposeUiApi
- @ExperimentalComposeUiApi
val isLookingAhead: Boolean
get() = false
}
\ No newline at end of file
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Layout.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Layout.kt
index 813a516..ff4713b 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Layout.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Layout.kt
@@ -23,13 +23,19 @@
import androidx.compose.runtime.ReusableComposeNode
import androidx.compose.runtime.SkippableUpdater
import androidx.compose.runtime.currentComposer
+import androidx.compose.runtime.currentCompositeKeyHash
import androidx.compose.runtime.remember
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.UiComposable
import androidx.compose.ui.graphics.GraphicsLayerScope
import androidx.compose.ui.materialize
import androidx.compose.ui.materializeWithCompositionLocalInjectionInternal
import androidx.compose.ui.node.ComposeUiNode
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetCompositeKeyHash
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetMeasurePolicy
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetModifier
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetResolvedCompositionLocals
import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntOffset
@@ -69,12 +75,15 @@
modifier: Modifier = Modifier,
measurePolicy: MeasurePolicy
) {
+ val compositeKeyHash = currentCompositeKeyHash
val localMap = currentComposer.currentCompositionLocalMap
ReusableComposeNode<ComposeUiNode, Applier<Any>>(
factory = ComposeUiNode.Constructor,
update = {
- set(measurePolicy, ComposeUiNode.SetMeasurePolicy)
- set(localMap, ComposeUiNode.SetResolvedCompositionLocals)
+ set(measurePolicy, SetMeasurePolicy)
+ set(localMap, SetResolvedCompositionLocals)
+ @OptIn(ExperimentalComposeUiApi::class)
+ set(compositeKeyHash, SetCompositeKeyHash)
},
skippableUpdate = materializerOf(modifier),
content = content
@@ -111,14 +120,17 @@
modifier: Modifier = Modifier,
measurePolicy: MeasurePolicy
) {
+ val compositeKeyHash = currentCompositeKeyHash
val materialized = currentComposer.materialize(modifier)
val localMap = currentComposer.currentCompositionLocalMap
ReusableComposeNode<ComposeUiNode, Applier<Any>>(
factory = ComposeUiNode.Constructor,
update = {
- set(measurePolicy, ComposeUiNode.SetMeasurePolicy)
- set(localMap, ComposeUiNode.SetResolvedCompositionLocals)
- set(materialized, ComposeUiNode.SetModifier)
+ set(measurePolicy, SetMeasurePolicy)
+ set(localMap, SetResolvedCompositionLocals)
+ set(materialized, SetModifier)
+ @OptIn(ExperimentalComposeUiApi::class)
+ set(compositeKeyHash, SetCompositeKeyHash)
},
)
}
@@ -166,9 +178,13 @@
contents: List<@Composable @UiComposable () -> Unit>
): @Composable @UiComposable () -> Unit = {
contents.fastForEach { content ->
+ val compositeKeyHash = currentCompositeKeyHash
ReusableComposeNode<ComposeUiNode, Applier<Any>>(
factory = ComposeUiNode.VirtualConstructor,
- update = {},
+ update = {
+ @OptIn(ExperimentalComposeUiApi::class)
+ set(compositeKeyHash, SetCompositeKeyHash)
+ },
content = content
)
}
@@ -184,9 +200,12 @@
internal fun materializerOf(
modifier: Modifier
): @Composable SkippableUpdater<ComposeUiNode>.() -> Unit = {
+ val compositeKeyHash = currentCompositeKeyHash
val materialized = currentComposer.materialize(modifier)
update {
- set(materialized, ComposeUiNode.SetModifier)
+ set(materialized, SetModifier)
+ @OptIn(ExperimentalComposeUiApi::class)
+ set(compositeKeyHash, SetCompositeKeyHash)
}
}
@@ -204,9 +223,12 @@
internal fun materializerOfWithCompositionLocalInjection(
modifier: Modifier
): @Composable SkippableUpdater<ComposeUiNode>.() -> Unit = {
+ val compositeKeyHash = currentCompositeKeyHash
val materialized = currentComposer.materializeWithCompositionLocalInjectionInternal(modifier)
update {
- set(materialized, ComposeUiNode.SetModifier)
+ set(materialized, SetModifier)
+ @OptIn(ExperimentalComposeUiApi::class)
+ set(compositeKeyHash, SetCompositeKeyHash)
}
}
@@ -222,17 +244,20 @@
content: @Composable @UiComposable () -> Unit,
measurePolicy: MeasurePolicy
) {
+ val compositeKeyHash = currentCompositeKeyHash
val materialized = currentComposer.materialize(modifier)
val localMap = currentComposer.currentCompositionLocalMap
ReusableComposeNode<LayoutNode, Applier<Any>>(
factory = LayoutNode.Constructor,
update = {
- set(measurePolicy, ComposeUiNode.SetMeasurePolicy)
- set(localMap, ComposeUiNode.SetResolvedCompositionLocals)
+ set(measurePolicy, SetMeasurePolicy)
+ set(localMap, SetResolvedCompositionLocals)
@Suppress("DEPRECATION")
init { this.canMultiMeasure = true }
- set(materialized, ComposeUiNode.SetModifier)
+ set(materialized, SetModifier)
+ @OptIn(ExperimentalComposeUiApi::class)
+ set(compositeKeyHash, SetCompositeKeyHash)
},
content = content
)
@@ -277,8 +302,8 @@
*/
internal class DefaultIntrinsicMeasurable(
val measurable: IntrinsicMeasurable,
- val minMax: IntrinsicMinMax,
- val widthHeight: IntrinsicWidthHeight
+ private val minMax: IntrinsicMinMax,
+ private val widthHeight: IntrinsicWidthHeight
) : Measurable {
override val parentData: Any?
get() = measurable.parentData
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LayoutCoordinates.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LayoutCoordinates.kt
index af49d34..e674eed 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LayoutCoordinates.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LayoutCoordinates.kt
@@ -24,7 +24,7 @@
import androidx.compose.ui.unit.IntSize
/**
- * A holder of the measured bounds for the layout (MeasureBox).
+ * A holder of the measured bounds for the [Layout].
*/
@JvmDefaultWithCompatibility
interface LayoutCoordinates {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadLayoutCoordinates.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadLayoutCoordinates.kt
index 354fe56..a674790 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadLayoutCoordinates.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadLayoutCoordinates.kt
@@ -89,6 +89,7 @@
): Offset {
if (sourceCoordinates is LookaheadLayoutCoordinatesImpl) {
val source = sourceCoordinates.lookaheadDelegate
+ source.coordinator.onCoordinatesUsed()
val commonAncestor = coordinator.findCommonAncestor(source.coordinator)
return commonAncestor.lookaheadDelegate?.let { ancestor ->
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Placeable.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Placeable.kt
index 94893a6..b20aa16 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Placeable.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Placeable.kt
@@ -71,11 +71,11 @@
set(value) {
if (field != value) {
field = value
- recalculateWidthAndHeight()
+ onMeasuredSizeChanged()
}
}
- private fun recalculateWidthAndHeight() {
+ private fun onMeasuredSizeChanged() {
width = measuredSize.width.coerceIn(
measurementConstraints.minWidth,
measurementConstraints.maxWidth
@@ -84,6 +84,8 @@
measurementConstraints.minHeight,
measurementConstraints.maxHeight
)
+ apparentToRealOffset =
+ IntOffset((width - measuredSize.width) / 2, (height - measuredSize.height) / 2)
}
/**
@@ -110,7 +112,7 @@
set(value) {
if (field != value) {
field = value
- recalculateWidthAndHeight()
+ onMeasuredSizeChanged()
}
}
@@ -119,8 +121,8 @@
* The real layout will be centered on the space assigned by the parent, which computed the
* child's position only seeing its apparent size.
*/
- protected val apparentToRealOffset: IntOffset
- get() = IntOffset((width - measuredSize.width) / 2, (height - measuredSize.height) / 2)
+ protected var apparentToRealOffset: IntOffset = IntOffset.Zero
+ private set
/**
* Receiver scope that permits explicit placement of a [Placeable].
@@ -158,6 +160,10 @@
* When [coordinates] is `null`, there will always be a follow-up placement call in which
* [coordinates] is not-`null`.
*
+ * If you read a position from the coordinates during the placement block the block
+ * will be automatically re-executed when the parent layout changes a position. If you
+ * don't read it the placement block execution can be skipped as an optimization.
+ *
* @sample androidx.compose.ui.samples.PlacementScopeCoordinatesSample
*/
open val coordinates: LayoutCoordinates?
@@ -340,7 +346,11 @@
override val coordinates: LayoutCoordinates?
get() {
- layoutDelegate?.coordinatesAccessedDuringPlacement = true
+ // if coordinates are not null we will only set this flag when the inner
+ // coordinate values are read. see NodeCoordinator.onCoordinatesUsed()
+ if (_coordinates == null) {
+ layoutDelegate?.onCoordinatesUsed()
+ }
return _coordinates
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/RelocationModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/RelocationModifier.kt
deleted file mode 100644
index d16bf4e..0000000
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/RelocationModifier.kt
+++ /dev/null
@@ -1,85 +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.compose.ui.layout
-
-import androidx.compose.ui.ExperimentalComposeUiApi
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Rect
-import androidx.compose.ui.internal.JvmDefaultWithCompatibility
-
-/**
- * A [modifier][Modifier.Element] that can be used to respond to relocation requests to relocate
- * an item on screen.
- *
- * When a child calls [RelocationRequester.bringIntoView](), the framework calls
- * [computeDestination] where you can take the source bounds and compute the destination
- * rectangle for the child. Relocation Modifiers higher up the hierarchy will receive this
- * destination as their source rect. Finally after all relocation modifiers have a chance to
- * compute their destinations, the framework calls [performRelocation](source, destination)
- * which performs the actual relocation (scrolling).
- *
- * @see RelocationRequester
- */
-@Suppress("unused", "DeprecatedCallableAddReplaceWith")
-@ExperimentalComposeUiApi
-@Deprecated(
- message = "Please use BringIntoViewResponder instead.",
- level = DeprecationLevel.ERROR
-)
-@JvmDefaultWithCompatibility
-interface RelocationModifier : Modifier.Element {
- /**
- * Compute the destination given the source rectangle and current bounds.
- *
- * @param source The bounding box of the item that sent the request to be brought into view.
- * @param layoutCoordinates The layoutCoordinates associated with this modifier.
- * @return the destination rectangle.
- */
- fun computeDestination(source: Rect, layoutCoordinates: LayoutCoordinates): Rect
-
- /**
- * Using the source and destination bounds, perform a relocation operation that moves the
- * source rect to the destination location. (This is usually achieved by scrolling).
- */
- suspend fun performRelocation(source: Rect, destination: Rect)
-}
-
-/**
- * Add this modifier to respond to requests to bring an item into view.
- */
-@Suppress("UNUSED_PARAMETER", "unused", "DeprecatedCallableAddReplaceWith")
-@ExperimentalComposeUiApi
-@Deprecated(
- message = "Please use BringIntoViewResponder instead.",
- level = DeprecationLevel.ERROR
-)
-fun Modifier.onRelocationRequest(
- /**
- * Provide the destination given the source rectangle and current bounds.
- *
- * rect: The bounding box of the item that sent the request to be brought into view.
- * layoutCoordinates: The layoutCoordinates associated with this modifier.
- * @return the destination rectangle.
- */
- onProvideDestination: (rect: Rect, layoutCoordinates: LayoutCoordinates) -> Rect,
-
- /**
- * Using the source and destination bounds, perform a relocation operation that moves the
- * source rect to the destination location. (This is usually achieved by scrolling).
- */
- onPerformRelocation: suspend (sourceRect: Rect, destinationRect: Rect) -> Unit
-): Modifier = this
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/RelocationRequester.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/RelocationRequester.kt
deleted file mode 100644
index 9159f7f..0000000
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/RelocationRequester.kt
+++ /dev/null
@@ -1,56 +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.compose.ui.layout
-
-import androidx.compose.ui.ExperimentalComposeUiApi
-import androidx.compose.ui.geometry.Rect
-
-/**
- * This class can be used to send relocation requests. Pass it as a parameter to
- * [Modifier.relocationRequester()][relocationRequester].
- */
-@ExperimentalComposeUiApi
-@Suppress("UNUSED_PARAMETER", "RedundantSuspendModifier")
-@Deprecated(
- message = "Please use BringIntoViewRequester instead.",
- replaceWith = ReplaceWith(
- "BringIntoViewRequester",
- "androidx.compose.foundation.relocation.BringIntoViewRequester"
-
- ),
- level = DeprecationLevel.ERROR
-)
-class RelocationRequester {
- /**
- * Bring this item into bounds by making all the scrollable parents scroll appropriately.
- *
- * @param rect The rectangle (In local coordinates) that should be brought into view. If you
- * don't specify the coordinates, the coordinates of the
- * [Modifier.relocationRequester()][relocationRequester] associated with this
- * [RelocationRequester] will be used.
- */
- @Deprecated(
- message = "Please use BringIntoViewRequester instead.",
- replaceWith = ReplaceWith(
- "bringIntoView",
- "androidx.compose.foundation.relocation.BringIntoViewRequester"
-
- ),
- level = DeprecationLevel.ERROR
- )
- suspend fun bringIntoView(rect: Rect? = null) {}
-}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/RelocationRequesterModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/RelocationRequesterModifier.kt
deleted file mode 100644
index 1bef983..0000000
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/RelocationRequesterModifier.kt
+++ /dev/null
@@ -1,39 +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.compose.ui.layout
-
-import androidx.compose.ui.ExperimentalComposeUiApi
-import androidx.compose.ui.Modifier
-
-/**
- * This is a modifier that can be used to send relocation requests.
- *
- * @param relocationRequester an instance of [RelocationRequester]. This hoisted object can be
- * used to send relocation requests to parents of the current composable.
- */
-@ExperimentalComposeUiApi
-@Suppress("UNUSED_PARAMETER")
-@Deprecated(
- message = "Please use bringIntoViewRequester instead.",
- replaceWith = ReplaceWith(
- "bringIntoViewRequester",
- "androidx.compose.foundation.relocation.bringIntoViewRequester"
-
- ),
- level = DeprecationLevel.ERROR
-)
-fun Modifier.relocationRequester(relocationRequester: Any): Modifier = this
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
index 619812e..f5146b8 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
@@ -25,6 +25,7 @@
import androidx.compose.runtime.ReusableContentHost
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.currentComposer
+import androidx.compose.runtime.currentCompositeKeyHash
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -37,7 +38,9 @@
import androidx.compose.ui.UiComposable
import androidx.compose.ui.layout.SubcomposeLayoutState.PrecomposedSlotHandle
import androidx.compose.ui.materialize
-import androidx.compose.ui.node.ComposeUiNode
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetCompositeKeyHash
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetModifier
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetResolvedCompositionLocals
import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.node.LayoutNode.LayoutState
import androidx.compose.ui.node.LayoutNode.UsageByParent
@@ -104,6 +107,7 @@
modifier: Modifier = Modifier,
measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult
) {
+ val compositeKeyHash = currentCompositeKeyHash
val compositionContext = rememberCompositionContext()
val materialized = currentComposer.materialize(modifier)
val localMap = currentComposer.currentCompositionLocalMap
@@ -113,8 +117,10 @@
set(state, state.setRoot)
set(compositionContext, state.setCompositionContext)
set(measurePolicy, state.setMeasurePolicy)
- set(localMap, ComposeUiNode.SetResolvedCompositionLocals)
- set(materialized, ComposeUiNode.SetModifier)
+ set(localMap, SetResolvedCompositionLocals)
+ set(materialized, SetModifier)
+ @OptIn(ExperimentalComposeUiApi::class)
+ set(compositeKeyHash, SetCompositeKeyHash)
}
)
if (!currentComposer.skipping) {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/TestModifierUpdater.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/TestModifierUpdater.kt
index d065d02..bc53f49 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/TestModifierUpdater.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/TestModifierUpdater.kt
@@ -16,14 +16,18 @@
package androidx.compose.ui.layout
+import androidx.annotation.RestrictTo
import androidx.compose.runtime.Applier
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ComposeNode
+import androidx.compose.runtime.currentCompositeKeyHash
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
-import androidx.compose.ui.node.ComposeUiNode
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetCompositeKeyHash
+import androidx.compose.ui.node.ComposeUiNode.Companion.SetMeasurePolicy
import androidx.compose.ui.node.LayoutNode
-/** @hide */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
@Deprecated(
"It is a test API, do not use it in the real applications",
level = DeprecationLevel.ERROR
@@ -35,7 +39,7 @@
}
}
-/** @hide */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
@Deprecated(
"It is a test API, do not use it in the real applications",
level = DeprecationLevel.ERROR
@@ -44,13 +48,16 @@
@Composable
@Suppress("DEPRECATION_ERROR")
fun TestModifierUpdaterLayout(onAttached: (TestModifierUpdater) -> Unit) {
+ val compositeKeyHash = currentCompositeKeyHash
val measurePolicy = MeasurePolicy { _, constraints ->
layout(constraints.maxWidth, constraints.maxHeight) {}
}
ComposeNode<LayoutNode, Applier<Any>>(
factory = LayoutNode.Constructor,
update = {
- set(measurePolicy, ComposeUiNode.SetMeasurePolicy)
+ set(measurePolicy, SetMeasurePolicy)
+ @OptIn(ExperimentalComposeUiApi::class)
+ set(compositeKeyHash, SetCompositeKeyHash)
init { onAttached(TestModifierUpdater(this)) }
}
)
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ComposeUiNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ComposeUiNode.kt
index c808fdb..f55bfb5 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ComposeUiNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ComposeUiNode.kt
@@ -17,6 +17,7 @@
package androidx.compose.ui.node
import androidx.compose.runtime.CompositionLocalMap
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.MeasurePolicy
import androidx.compose.ui.platform.ViewConfiguration
@@ -34,6 +35,8 @@
var modifier: Modifier
var viewConfiguration: ViewConfiguration
var compositionLocalMap: CompositionLocalMap
+ @ExperimentalComposeUiApi
+ var compositeKeyHash: Int
/**
* Object of pre-allocated lambdas used to make use with ComposeNode allocation-less.
@@ -51,5 +54,10 @@
{ this.layoutDirection = it }
val SetViewConfiguration: ComposeUiNode.(ViewConfiguration) -> Unit =
{ this.viewConfiguration = it }
+ @get:ExperimentalComposeUiApi
+ @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
+ @ExperimentalComposeUiApi
+ val SetCompositeKeyHash: ComposeUiNode.(Int) -> Unit =
+ { this.compositeKeyHash = it }
}
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DrawModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DrawModifierNode.kt
index 05fb28e..99cd8b2 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DrawModifierNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DrawModifierNode.kt
@@ -33,15 +33,6 @@
}
/**
- * Expands on the [androidx.compose.ui.node.DrawModifierNode] by adding the ability to invalidate
- * the draw cache for changes in things like shapes and bitmaps (see Modifier.border for a usage
- * examples).
- */
-interface CacheDrawModifierNode : DrawModifierNode {
- fun invalidateDrawCache()
-}
-
-/**
* Invalidates this modifier's draw layer, ensuring that a draw pass will
* be run on the next frame.
*/
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 574419a..13b3d42 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
@@ -64,6 +64,7 @@
/**
* Enable to log changes to the LayoutNode tree. This logging is quite chatty.
*/
+@Suppress("ConstPropertyName")
private const val DebugChanges = false
private val DefaultDensity = Density(1f)
@@ -82,6 +83,7 @@
// subcompose multiple times into the same LayoutNode and define offsets.
private val isVirtual: Boolean = false,
// The unique semantics ID that is used by all semantics modifiers attached to this LayoutNode.
+ // TODO(b/281907968): Implement this with a getter that returns the compositeKeyHash.
override var semanticsId: Int = generateSemanticsId()
) : ComposeNodeLifecycleCallback,
Remeasurement,
@@ -91,6 +93,12 @@
InteroperableComposeUiNode,
Owner.OnLayoutCompletedListener {
+ @set:ExperimentalComposeUiApi
+ @get:ExperimentalComposeUiApi
+ @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
+ @ExperimentalComposeUiApi
+ override var compositeKeyHash: Int = 0
+
internal var isVirtualLookaheadRoot: Boolean = false
/**
@@ -669,7 +677,6 @@
density = value[LocalDensity]
layoutDirection = value[LocalLayoutDirection]
viewConfiguration = value[LocalViewConfiguration]
- @OptIn(ExperimentalComposeUiApi::class)
nodes.headToTail(Nodes.CompositionLocalConsumer) { modifierNode ->
val delegatedNode = modifierNode.node
if (delegatedNode.isAttached) {
@@ -818,7 +825,6 @@
/**
* The [Modifier] currently applied to this node.
*/
- @OptIn(ExperimentalComposeUiApi::class)
override var modifier: Modifier = Modifier
set(value) {
require(!isVirtual || modifier === Modifier) {
@@ -1028,7 +1034,6 @@
}
}
- @OptIn(ExperimentalComposeUiApi::class)
private fun invalidateFocusOnAttach() {
if (nodes.has(FocusTarget or FocusProperties or FocusEvent)) {
nodes.headToTail {
@@ -1069,7 +1074,6 @@
}
}
- @OptIn(ExperimentalComposeUiApi::class)
internal fun dispatchOnPositionedCallbacks() {
if (layoutState != Idle || layoutPending || measurePending) {
return // it hasn't yet been properly positioned, so don't make a call
@@ -1169,7 +1173,6 @@
*/
internal fun markLookaheadLayoutPending() = layoutDelegate.markLookaheadLayoutPending()
- @OptIn(ExperimentalComposeUiApi::class)
fun invalidateSubtree(isRootOfInvalidation: Boolean = true) {
if (isRootOfInvalidation) {
parent?.invalidateLayer()
@@ -1204,7 +1207,6 @@
}
}
- @OptIn(ExperimentalComposeUiApi::class)
override fun onLayoutComplete() {
innerCoordinator.visitNodes(Nodes.LayoutAware) {
it.onPlaced(innerCoordinator)
@@ -1235,7 +1237,6 @@
}
}
- @OptIn(ExperimentalComposeUiApi::class)
private fun shouldInvalidateParentLayer(): Boolean {
if (nodes.has(Nodes.Draw) && !nodes.has(Nodes.Layout)) return true
nodes.headToTail {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeAlignmentLines.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeAlignmentLines.kt
index fc84004..b682397 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeAlignmentLines.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeAlignmentLines.kt
@@ -203,7 +203,7 @@
alignmentLinesOwner.requestMeasure()
}
if (usedByModifierLayout) {
- parent.requestLayout()
+ alignmentLinesOwner.requestLayout()
}
parent.alignmentLines.onAlignmentsChanged()
}
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 e66dc1c..9e079fe 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
@@ -26,7 +26,6 @@
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.util.fastForEach
/**
* This class works as a layout delegate for [LayoutNode]. It delegates all the measure/layout
@@ -173,9 +172,30 @@
val oldValue = field
if (oldValue != value) {
field = value
- if (value) {
+ if (value && !coordinatesAccessedDuringModifierPlacement) {
+ // if first out of both flags changes to true increment
childrenAccessingCoordinatesDuringPlacement++
- } else {
+ } else if (!value && !coordinatesAccessedDuringModifierPlacement) {
+ // if both flags changes to false decrement
+ childrenAccessingCoordinatesDuringPlacement--
+ }
+ }
+ }
+
+ /**
+ * Similar to [coordinatesAccessedDuringPlacement], but tracks the coordinates read happening
+ * during the modifier layout blocks run.
+ */
+ var coordinatesAccessedDuringModifierPlacement = false
+ set(value) {
+ val oldValue = field
+ if (oldValue != value) {
+ field = value
+ if (value && !coordinatesAccessedDuringPlacement) {
+ // if first out of both flags changes to true increment
+ childrenAccessingCoordinatesDuringPlacement++
+ } else if (!value && !coordinatesAccessedDuringPlacement) {
+ // if both flags changes to false decrement
childrenAccessingCoordinatesDuringPlacement--
}
}
@@ -216,6 +236,25 @@
internal var lookaheadPassDelegate: LookaheadPassDelegate? = null
private set
+ fun onCoordinatesUsed() {
+ val state = layoutNode.layoutState
+ if (state == LayoutState.LayingOut || state == LayoutState.LookaheadLayingOut) {
+ if (measurePassDelegate.layingOutChildren) {
+ coordinatesAccessedDuringPlacement = true
+ } else {
+ coordinatesAccessedDuringModifierPlacement = true
+ }
+ }
+ if (state == LayoutState.LookaheadLayingOut) {
+ // TODO lookahead should have its own flags b/284153462
+ if (lookaheadPassDelegate?.layingOutChildren == true) {
+ coordinatesAccessedDuringPlacement = true
+ } else {
+ coordinatesAccessedDuringModifierPlacement = true
+ }
+ }
+ }
+
/**
* [MeasurePassDelegate] manages the measure/layout and alignmentLine related queries for the
* actual measure/layout pass.
@@ -293,7 +332,11 @@
return _childDelegates.asMutableList()
}
+ var layingOutChildren = false
+ private set
+
override fun layoutChildren() {
+ layingOutChildren = true
alignmentLines.recalculateQueryOwner()
if (layoutPending) {
@@ -308,6 +351,7 @@
layoutPending = false
val oldLayoutState = layoutState
layoutState = LayoutState.LayingOut
+ coordinatesAccessedDuringPlacement = false
with(layoutNode) {
val owner = requireOwner()
owner.snapshotObserver.observeLayoutSnapshotReads(
@@ -341,6 +385,8 @@
alignmentLines.previousUsedDuringParentLayout = true
}
if (alignmentLines.dirty && alignmentLines.required) alignmentLines.recalculate()
+
+ layingOutChildren = false
}
private fun checkChildrenPlaceOrderForUpdates() {
@@ -463,7 +509,7 @@
}
private inline fun forEachChildDelegate(block: (MeasurePassDelegate) -> Unit) {
- layoutNode.children.fastForEach {
+ layoutNode.forEachChild {
block(it.measurePassDelegate)
}
}
@@ -581,6 +627,10 @@
layerBlock: (GraphicsLayerScope.() -> Unit)?
) {
if (position != lastPosition) {
+ if (coordinatesAccessedDuringModifierPlacement ||
+ coordinatesAccessedDuringPlacement) {
+ layoutPending = true
+ }
notifyChildrenUsingCoordinatesWhilePlacing()
}
// This can actually be called as soon as LookaheadMeasure is done, but devs may expect
@@ -603,9 +653,7 @@
}
// Post-lookahead (if any) placement
- layoutState = LayoutState.LayingOut
placeOuterCoordinator(position, zIndex, layerBlock)
- layoutState = LayoutState.Idle
}
private fun placeOuterCoordinator(
@@ -613,26 +661,34 @@
zIndex: Float,
layerBlock: (GraphicsLayerScope.() -> Unit)?
) {
+ layoutState = LayoutState.LayingOut
+
lastPosition = position
lastZIndex = zIndex
lastLayerBlock = layerBlock
-
placedOnce = true
- alignmentLines.usedByModifierLayout = false
- coordinatesAccessedDuringPlacement = false
+
val owner = layoutNode.requireOwner()
- owner.snapshotObserver.observeLayoutModifierSnapshotReads(
- layoutNode,
- affectsLookahead = false
- ) {
- with(PlacementScope) {
- if (layerBlock == null) {
- outerCoordinator.place(position, zIndex)
- } else {
- outerCoordinator.placeWithLayer(position, zIndex, layerBlock)
+ if (!layoutPending && isPlaced) {
+ outerCoordinator.placeSelfApparentToRealOffset(position, zIndex, layerBlock)
+ onNodePlaced()
+ } else {
+ alignmentLines.usedByModifierLayout = false
+ coordinatesAccessedDuringModifierPlacement = false
+ owner.snapshotObserver.observeLayoutModifierSnapshotReads(
+ layoutNode, affectsLookahead = false
+ ) {
+ with(PlacementScope) {
+ if (layerBlock == null) {
+ outerCoordinator.place(position, zIndex)
+ } else {
+ outerCoordinator.placeWithLayer(position, zIndex, layerBlock)
+ }
}
}
}
+
+ layoutState = LayoutState.Idle
}
/**
@@ -730,7 +786,7 @@
get() = layoutNode.parent?.layoutDelegate?.alignmentLinesOwner
override fun forEachChildAlignmentLinesOwner(block: (AlignmentLinesOwner) -> Unit) {
- layoutNode.children.fastForEach {
+ layoutNode.forEachChild {
block(it.layoutDelegate.alignmentLinesOwner)
}
}
@@ -756,11 +812,11 @@
*/
fun notifyChildrenUsingCoordinatesWhilePlacing() {
if (childrenAccessingCoordinatesDuringPlacement > 0) {
- layoutNode.children.fastForEach { child ->
+ layoutNode.forEachChild { child ->
val childLayoutDelegate = child.layoutDelegate
- if (childLayoutDelegate.coordinatesAccessedDuringPlacement &&
- !childLayoutDelegate.layoutPending
- ) {
+ val accessed = childLayoutDelegate.coordinatesAccessedDuringPlacement ||
+ childLayoutDelegate.coordinatesAccessedDuringModifierPlacement
+ if (accessed && !childLayoutDelegate.layoutPending) {
child.requestRelayout()
}
childLayoutDelegate.measurePassDelegate
@@ -939,12 +995,16 @@
return _childDelegates.asMutableList()
}
+ var layingOutChildren = false
+ private set
+
private inline fun forEachChildDelegate(block: (LookaheadPassDelegate) -> Unit) =
layoutNode.forEachChild {
block(it.layoutDelegate.lookaheadPassDelegate!!)
}
override fun layoutChildren() {
+ layingOutChildren = true
alignmentLines.recalculateQueryOwner()
if (lookaheadLayoutPending) {
@@ -961,6 +1021,7 @@
val oldLayoutState = layoutState
layoutState = LayoutState.LookaheadLayingOut
val owner = layoutNode.requireOwner()
+ coordinatesAccessedDuringPlacement = false
owner.snapshotObserver.observeLayoutSnapshotReads(layoutNode) {
clearPlaceOrder()
forEachChildAlignmentLinesOwner { child ->
@@ -985,6 +1046,8 @@
alignmentLines.previousUsedDuringParentLayout = true
}
if (alignmentLines.dirty && alignmentLines.required) alignmentLines.recalculate()
+
+ layingOutChildren = false
}
private fun checkChildrenPlaceOrderForUpdates() {
@@ -1030,7 +1093,7 @@
get() = layoutNode.parent?.layoutDelegate?.lookaheadAlignmentLinesOwner
override fun forEachChildAlignmentLinesOwner(block: (AlignmentLinesOwner) -> Unit) {
- layoutNode.children.fastForEach {
+ layoutNode.forEachChild {
block(it.layoutDelegate.lookaheadAlignmentLinesOwner!!)
}
}
@@ -1056,11 +1119,11 @@
*/
fun notifyChildrenUsingCoordinatesWhilePlacing() {
if (childrenAccessingCoordinatesDuringPlacement > 0) {
- layoutNode.children.fastForEach { child ->
+ layoutNode.forEachChild { child ->
val childLayoutDelegate = child.layoutDelegate
- if (childLayoutDelegate.coordinatesAccessedDuringPlacement &&
- !childLayoutDelegate.layoutPending
- ) {
+ val accessed = childLayoutDelegate.coordinatesAccessedDuringPlacement ||
+ childLayoutDelegate.coordinatesAccessedDuringModifierPlacement
+ if (accessed && !childLayoutDelegate.layoutPending) {
child.requestLookaheadRelayout()
}
childLayoutDelegate.lookaheadPassDelegate
@@ -1160,14 +1223,23 @@
layoutState = LayoutState.LookaheadLayingOut
placedOnce = true
if (position != lastPosition) {
+ if (coordinatesAccessedDuringModifierPlacement ||
+ coordinatesAccessedDuringPlacement) {
+ lookaheadLayoutPending = true
+ }
notifyChildrenUsingCoordinatesWhilePlacing()
}
- alignmentLines.usedByModifierLayout = false
val owner = layoutNode.requireOwner()
- coordinatesAccessedDuringPlacement = false
- owner.snapshotObserver.observeLayoutModifierSnapshotReads(layoutNode) {
- with(PlacementScope) {
- outerCoordinator.lookaheadDelegate!!.place(position)
+
+ if (!lookaheadLayoutPending && isPlaced) {
+ onNodePlaced()
+ } else {
+ coordinatesAccessedDuringModifierPlacement = false
+ alignmentLines.usedByModifierLayout = false
+ owner.snapshotObserver.observeLayoutModifierSnapshotReads(layoutNode) {
+ with(PlacementScope) {
+ outerCoordinator.lookaheadDelegate!!.place(position)
+ }
}
}
lastPosition = position
@@ -1294,8 +1366,8 @@
}
if (parent != null) {
if (!relayoutWithoutParentInProgress &&
- parent.layoutState == LayoutState.LayingOut ||
- parent.layoutState == LayoutState.LookaheadLayingOut
+ (parent.layoutState == LayoutState.LayingOut ||
+ parent.layoutState == LayoutState.LookaheadLayingOut)
) {
// the parent is currently placing its children
check(placeOrder == NotPlacedPlaceOrder) {
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 d297aef..e743af7 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
@@ -48,6 +48,11 @@
val hasPendingMeasureOrLayout get() = relayoutNodes.isNotEmpty()
/**
+ * Whether any on positioned callbacks need to be dispatched
+ */
+ val hasPendingOnPositionedCallbacks get() = onPositionedDispatcher.isNotEmpty()
+
+ /**
* Flag to indicate that we're currently measuring.
*/
private var duringMeasureLayout = false
@@ -365,7 +370,7 @@
private fun recurseRemeasure(layoutNode: LayoutNode) {
remeasureOnly(layoutNode)
- layoutNode._children.forEach { child ->
+ layoutNode.forEachChild { child ->
if (child.measureAffectsParent) {
recurseRemeasure(child)
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
index 9043a07..23c09c2 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
@@ -745,6 +745,7 @@
): MutableVector<Modifier.Element> {
val capacity = result.size.coerceAtLeast(16)
val stack = MutableVector<Modifier>(capacity).also { it.add(this) }
+ var predicate: ((Modifier.Element) -> Boolean)? = null
while (stack.isNotEmpty()) {
when (val next = stack.removeAt(stack.size - 1)) {
is CombinedModifier -> {
@@ -753,10 +754,11 @@
}
is Modifier.Element -> result.add(next)
// some other androidx.compose.ui.node.Modifier implementation that we don't know about...
- else -> next.all {
- result.add(it)
+ // late-allocate the predicate only once for the entire stack
+ else -> next.all(predicate ?: { element: Modifier.Element ->
+ result.add(element)
true
- }
+ }.also { predicate = it })
}
}
return result
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
index 2a0b6e9..0e9b845 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
@@ -247,15 +247,21 @@
return null
}
+ internal fun onCoordinatesUsed() {
+ layoutNode.layoutDelegate.onCoordinatesUsed()
+ }
+
final override val parentLayoutCoordinates: LayoutCoordinates?
get() {
check(isAttached) { ExpectAttachedLayoutCoordinates }
+ onCoordinatesUsed()
return layoutNode.outerCoordinator.wrappedBy
}
final override val parentCoordinates: LayoutCoordinates?
get() {
check(isAttached) { ExpectAttachedLayoutCoordinates }
+ onCoordinatesUsed()
return wrappedBy
}
@@ -301,6 +307,14 @@
zIndex: Float,
layerBlock: (GraphicsLayerScope.() -> Unit)?
) {
+ placeSelf(position, zIndex, layerBlock)
+ }
+
+ private fun placeSelf(
+ position: IntOffset,
+ zIndex: Float,
+ layerBlock: (GraphicsLayerScope.() -> Unit)?
+ ) {
updateLayerBlock(layerBlock)
if (this.position != position) {
this.position = position
@@ -318,6 +332,14 @@
this.zIndex = zIndex
}
+ fun placeSelfApparentToRealOffset(
+ position: IntOffset,
+ zIndex: Float,
+ layerBlock: (GraphicsLayerScope.() -> Unit)?
+ ) {
+ placeSelf(position + apparentToRealOffset, zIndex, layerBlock)
+ }
+
/**
* Draws the content of the LayoutNode
*/
@@ -374,9 +396,9 @@
layerBlock: (GraphicsLayerScope.() -> Unit)?,
forceUpdateLayerParameters: Boolean = false
) {
- val updateParameters = this.layerBlock !== layerBlock || layerDensity != layoutNode
- .density || layerLayoutDirection != layoutNode.layoutDirection ||
- forceUpdateLayerParameters
+ val layoutNode = layoutNode
+ val updateParameters = forceUpdateLayerParameters || this.layerBlock !== layerBlock ||
+ layerDensity != layoutNode.density || layerLayoutDirection != layoutNode.layoutDirection
this.layerBlock = layerBlock
this.layerDensity = layoutNode.density
this.layerLayoutDirection = layoutNode.layoutDirection
@@ -737,6 +759,7 @@
}
val nodeCoordinator = sourceCoordinates.toCoordinator()
+ nodeCoordinator.onCoordinatesUsed()
val commonAncestor = findCommonAncestor(nodeCoordinator)
var position = relativeToSource
@@ -751,6 +774,7 @@
override fun transformFrom(sourceCoordinates: LayoutCoordinates, matrix: Matrix) {
val coordinator = sourceCoordinates.toCoordinator()
+ coordinator.onCoordinatesUsed()
val commonAncestor = findCommonAncestor(coordinator)
matrix.reset()
@@ -795,6 +819,7 @@
"LayoutCoordinates $sourceCoordinates is not attached!"
}
val srcCoordinator = sourceCoordinates.toCoordinator()
+ srcCoordinator.onCoordinatesUsed()
val commonAncestor = findCommonAncestor(srcCoordinator)
val bounds = rectCache
@@ -842,6 +867,7 @@
override fun localToRoot(relativeToLocal: Offset): Offset {
check(isAttached) { ExpectAttachedLayoutCoordinates }
+ onCoordinatesUsed()
var coordinator: NodeCoordinator? = this
var position = relativeToLocal
while (coordinator != null) {
@@ -1007,24 +1033,6 @@
}
/**
- * Send a request to bring a portion of this item into view. The portion that has to be
- * brought into view is specified as a rectangle where the coordinates are in the local
- * coordinates of that nodeCoordinator. This request is sent up the hierarchy to all parents
- * that have a [RelocationModifier][androidx.compose.ui.layout.RelocationModifier].
- */
- open suspend fun propagateRelocationRequest(rect: Rect) {
- val parent = wrappedBy ?: return
-
- // Translate this nodeCoordinator to the coordinate system of the parent.
- val boundingBoxInParentCoordinates = parent.localBoundingBoxOf(this, false)
-
- // Translate the rect to parent coordinates
- val rectInParentBounds = rect.translate(boundingBoxInParentCoordinates.topLeft)
-
- parent.propagateRelocationRequest(rectInParentBounds)
- }
-
- /**
* Called when [LayoutNode.modifier] has changed and all the NodeCoordinators have been
* configured.
*/
@@ -1178,7 +1186,8 @@
val layoutNode = coordinator.layoutNode
val layoutDelegate = layoutNode.layoutDelegate
if (layoutDelegate.childrenAccessingCoordinatesDuringPlacement > 0) {
- if (layoutDelegate.coordinatesAccessedDuringPlacement) {
+ if (layoutDelegate.coordinatesAccessedDuringModifierPlacement ||
+ layoutDelegate.coordinatesAccessedDuringPlacement) {
layoutNode.requestRelayout()
}
layoutDelegate.measurePassDelegate
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ObserverModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ObserverModifierNode.kt
index c3f37a2..34f9ef3 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ObserverModifierNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ObserverModifierNode.kt
@@ -20,14 +20,16 @@
/**
* [Modifier.Node]s that implement ObserverNode can provide their own implementation of
- * [onObservedReadsChanged] that will be called whenever the value of read object has changed.
- * To trigger [onObservedReadsChanged], read values within an [observeReads] block.
+ * [onObservedReadsChanged] that will be called in response to changes to snapshot objects
+ * read within an [observeReads] block.
*/
interface ObserverModifierNode : DelegatableNode {
/**
* This callback is called when any values that are read within the [observeReads] block
- * changes.
+ * change. It is called after the snapshot is committed. [onObservedReadsChanged] is called on
+ * the UI thread, and only called once in response to snapshot observation. To continue
+ * observing further updates, you need to call [observeReads] again.
*/
fun onObservedReadsChanged()
}
@@ -46,7 +48,8 @@
}
/**
- * Use this function to observe reads within the specified [block].
+ * Use this function to observe snapshot reads for any target within the specified [block].
+ * [onDrawCacheReadsChanged] is called when any of the observed values within the snapshot change.
*/
fun <T> T.observeReads(block: () -> Unit) where T : Modifier.Node, T : ObserverModifierNode {
val target = ownerScope ?: ObserverNodeOwnerScope(this).also { ownerScope = it }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OnPositionedDispatcher.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OnPositionedDispatcher.kt
index 07b7f50..4b34850 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OnPositionedDispatcher.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OnPositionedDispatcher.kt
@@ -24,6 +24,9 @@
*/
internal class OnPositionedDispatcher {
private val layoutNodes = mutableVectorOf<LayoutNode>()
+ private var cachedNodes: Array<LayoutNode?>? = null
+
+ fun isNotEmpty() = layoutNodes.isNotEmpty()
fun onNodePositioned(node: LayoutNode) {
layoutNodes += node
@@ -39,12 +42,28 @@
fun dispatch() {
// sort layoutNodes so that the root is at the end and leaves are at the front
layoutNodes.sortWith(DepthComparator)
- layoutNodes.forEachReversed { layoutNode ->
+ val cache: Array<LayoutNode?>
+ val size = layoutNodes.size
+ val cachedNodes = this.cachedNodes
+ if (cachedNodes == null || cachedNodes.size < size) {
+ cache = arrayOfNulls(maxOf(MinArraySize, layoutNodes.size))
+ } else {
+ cache = cachedNodes
+ }
+ this.cachedNodes = null
+
+ // copy to cache to prevent reentrancy being a problem
+ for (i in 0 until size) {
+ cache[i] = layoutNodes[i]
+ }
+ layoutNodes.clear()
+ for (i in size - 1 downTo 0) {
+ val layoutNode = cache[i]!!
if (layoutNode.needsOnPositionedDispatch) {
dispatchHierarchy(layoutNode)
}
}
- layoutNodes.clear()
+ this.cachedNodes = cache
}
private fun dispatchHierarchy(layoutNode: LayoutNode) {
@@ -59,6 +78,8 @@
}
internal companion object {
+ private const val MinArraySize = 16
+
private object DepthComparator : Comparator<LayoutNode> {
override fun compare(a: LayoutNode, b: LayoutNode): Int {
val depthDiff = b.depth.compareTo(a.depth)
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
index cb55b7c..426e1f7 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
@@ -33,7 +33,6 @@
import androidx.compose.ui.platform.TextToolbar
import androidx.compose.ui.platform.ViewConfiguration
import androidx.compose.ui.platform.WindowInfo
-import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.PlatformTextInputPluginRegistry
@@ -112,7 +111,6 @@
val textInputService: TextInputService
- @OptIn(ExperimentalTextApi::class)
val platformTextInputPluginRegistry: PlatformTextInputPluginRegistry
val pointerIconService: PointerIconService
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/CompositionLocals.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/CompositionLocals.kt
index 67ca21c..d1d8cd0 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/CompositionLocals.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/CompositionLocals.kt
@@ -29,7 +29,6 @@
import androidx.compose.ui.input.pointer.PointerIconService
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.node.Owner
-import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.PlatformTextInputPluginRegistry
@@ -144,9 +143,6 @@
* Higher-level text input APIs in the Foundation library are more appropriate for most cases.
*/
// Experimental in desktop.
-@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-@ExperimentalTextApi
-@get:ExperimentalTextApi
val LocalPlatformTextInputPluginRegistry =
staticCompositionLocalOf<PlatformTextInputPluginRegistry> {
error("No PlatformTextInputPluginRegistry provided")
@@ -184,7 +180,6 @@
null
}
-@OptIn(ExperimentalTextApi::class)
@ExperimentalComposeUiApi
@Composable
internal fun ProvideCommonCompositionLocals(
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
index b967ae8..96d0e6b 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
@@ -202,6 +202,16 @@
)
/**
+ * @see SemanticsPropertyReceiver.originalText
+ */
+ val OriginalText = SemanticsPropertyKey<AnnotatedString>(name = "OriginalText")
+
+ /**
+ * @see SemanticsPropertyReceiver.isShowingTextSubstitution
+ */
+ val IsShowingTextSubstitution = SemanticsPropertyKey<Boolean>("IsShowingTextSubstitution")
+
+ /**
* @see SemanticsPropertyReceiver.editableText
*/
val EditableText = SemanticsPropertyKey<AnnotatedString>(name = "EditableText")
@@ -212,7 +222,7 @@
val TextSelectionRange = SemanticsPropertyKey<TextRange>("TextSelectionRange")
/**
- * @see SemanticsPropertyReceiver.performImeAction
+ * @see SemanticsPropertyReceiver.onImeAction
*/
val ImeAction = SemanticsPropertyKey<ImeAction>("ImeAction")
@@ -293,14 +303,29 @@
val SetText = ActionPropertyKey<(AnnotatedString) -> Boolean>("SetText")
/**
+ * @see SemanticsPropertyReceiver.setTextSubstitution
+ */
+ val SetTextSubstitution = ActionPropertyKey<(AnnotatedString) -> Boolean>("SetTextSubstitution")
+
+ /**
+ * @see SemanticsPropertyReceiver.showTextSubstitution
+ */
+ val ShowTextSubstitution = ActionPropertyKey<(Boolean) -> Boolean>("ShowTextSubstitution")
+
+ /**
+ * @see SemanticsPropertyReceiver.clearTextSubstitution
+ */
+ val ClearTextSubstitution = ActionPropertyKey<() -> Boolean>("ClearTextSubstitution")
+
+ /**
* @see SemanticsPropertyReceiver.insertTextAtCursor
*/
val InsertTextAtCursor = ActionPropertyKey<(AnnotatedString) -> Boolean>("InsertTextAtCursor")
/**
- * @see SemanticsPropertyReceiver.performImeAction
+ * @see SemanticsPropertyReceiver.onImeAction
*/
- val PerformImeAction = ActionPropertyKey<() -> Boolean>("PerformImeAction")
+ val OnImeAction = ActionPropertyKey<() -> Boolean>("PerformImeAction")
/**
* @see SemanticsPropertyReceiver.copyText
@@ -902,6 +927,8 @@
/**
* Text of the semantics node. It must be real text instead of developer-set content description.
*
+ * Represents the text substitution if [SemanticsActions.ShowTextSubstitution] is called.
+ *
* @see SemanticsPropertyReceiver.editableText
*/
var SemanticsPropertyReceiver.text: AnnotatedString
@@ -911,6 +938,20 @@
}
/**
+ * Original text of the semantics node. This property is only available after calling
+ * [SemanticsActions.ShowTextSubstitution]. The value should be equal to the [text] before calling
+ * [SemanticsActions.SetTextSubstitution].
+ */
+var SemanticsPropertyReceiver.originalText by SemanticsProperties.OriginalText
+
+/**
+ * Whether this element is showing the text substitution. This property is only available after
+ * calling [SemanticsActions.SetTextSubstitution].
+ */
+var SemanticsPropertyReceiver.isShowingTextSubstitution
+ by SemanticsProperties.IsShowingTextSubstitution
+
+/**
* Input text of the text field with visual transformation applied to it. It must be a real text
* entered by the user with visual transformation applied on top of the input text instead of a
* developer-set content description.
@@ -928,11 +969,11 @@
* For example, "go to next form field" or "submit".
*
* A node that specifies an action should also specify a callback to perform the action via
- * [performImeAction].
+ * [onImeAction].
*/
-@Deprecated("Pass the ImeAction to performImeAction instead.")
-@get:Deprecated("Pass the ImeAction to performImeAction instead.")
-@set:Deprecated("Pass the ImeAction to performImeAction instead.")
+@Deprecated("Pass the ImeAction to onImeAction instead.")
+@get:Deprecated("Pass the ImeAction to onImeAction instead.")
+@set:Deprecated("Pass the ImeAction to onImeAction instead.")
var SemanticsPropertyReceiver.imeAction by SemanticsProperties.ImeAction
/**
@@ -1096,6 +1137,56 @@
}
/**
+ * Action to set the text substitution of this node.
+ *
+ * Expected to be used on non-editable text.
+ *
+ * Note, this action doesn't show the text substitution. Please call
+ * [SemanticsPropertyReceiver.showTextSubstitution] to show the text substitution.
+ *
+ * @param label Optional label for this action.
+ * @param action Action to be performed when [SemanticsActions.SetTextSubstitution] is called.
+ */
+fun SemanticsPropertyReceiver.setTextSubstitution(
+ label: String? = null,
+ action: ((AnnotatedString) -> Boolean)?
+) {
+ this[SemanticsActions.SetTextSubstitution] = AccessibilityAction(label, action)
+}
+
+/**
+ * Action to show or hide the text substitution of this node.
+ *
+ * Expected to be used on non-editable text.
+ *
+ * Note, this action only takes effect when the node has the text substitution.
+ *
+ * @param label Optional label for this action.
+ * @param action Action to be performed when [SemanticsActions.ShowTextSubstitution] is called.
+ */
+fun SemanticsPropertyReceiver.showTextSubstitution(
+ label: String? = null,
+ action: ((Boolean) -> Boolean)?
+) {
+ this[SemanticsActions.ShowTextSubstitution] = AccessibilityAction(label, action)
+}
+
+/**
+ * Action to clear the text substitution of this node.
+ *
+ * Expected to be used on non-editable text.
+ *
+ * @param label Optional label for this action.
+ * @param action Action to be performed when [SemanticsActions.ClearTextSubstitution] is called.
+ */
+fun SemanticsPropertyReceiver.clearTextSubstitution(
+ label: String? = null,
+ action: (() -> Boolean)?
+) {
+ this[SemanticsActions.ClearTextSubstitution] = AccessibilityAction(label, action)
+}
+
+/**
* Action to insert text into this node at the current cursor position, or replacing the selection
* if text is selected.
*
@@ -1119,18 +1210,18 @@
*
* @param imeActionType The IME type, such as [ImeAction.Next] or [ImeAction.Search]
* @param label Optional label for this action.
- * @param action Action to be performed when [SemanticsActions.PerformImeAction] is called.
+ * @param action Action to be performed when [SemanticsActions.OnImeAction] is called.
*
* @see SemanticsProperties.ImeAction
- * @see SemanticsActions.PerformImeAction
+ * @see SemanticsActions.OnImeAction
*/
-fun SemanticsPropertyReceiver.performImeAction(
+fun SemanticsPropertyReceiver.onImeAction(
imeActionType: ImeAction,
label: String? = null,
action: (() -> Boolean)?
) {
this[SemanticsProperties.ImeAction] = imeActionType
- this[SemanticsActions.PerformImeAction] = AccessibilityAction(label, action)
+ this[SemanticsActions.OnImeAction] = AccessibilityAction(label, action)
}
/**
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurerHelper.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurerHelper.kt
index b94e5ef..5b6565a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurerHelper.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurerHelper.kt
@@ -28,14 +28,17 @@
private val DefaultCacheSize: Int = 8
/**
- * Creates and remembers a [TextMeasurer]. All parameters that are required for TextMeasurer except
- * [cacheSize] are read from CompositionLocals. Created TextMeasurer carries an internal
+ * Creates and remembers a [TextMeasurer]. All parameters that are required for [TextMeasurer]
+ * except [cacheSize] are read from CompositionLocals. Created [TextMeasurer] carries an internal
* [TextLayoutCache] with [cacheSize] capacity. Provide 0 for [cacheSize] to opt-out from internal
- * caching behavior. Moreover, the cache can be disabled at will during measure by passing in
- * skipCache as true.
+ * caching behavior.
*
- * @param cacheSize Capacity of internal cache inside TextMeasurer. Size unit is the number of
- * unique text layout inputs that are measured.
+ * @param cacheSize Capacity of internal cache inside [TextMeasurer]. Size unit is the number of
+ * unique text layout inputs that are measured. Value of this parameter highly depends on the
+ * consumer use case. Provide a cache size that is in line with how many distinct text layouts are
+ * going to be calculated by this measurer repeatedly. If you are animating font attributes, or any
+ * other layout affecting input, cache can be skipped because most repeated measure calls would miss
+ * the cache.
*/
@Composable
fun rememberTextMeasurer(
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerEvent.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerEvent.desktop.kt
index 0a0d316..0bd66bd 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerEvent.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/input/pointer/InternalPointerEvent.desktop.kt
@@ -16,17 +16,18 @@
package androidx.compose.ui.input.pointer
+import androidx.collection.LongSparseArray
import java.awt.event.MouseEvent
internal actual class InternalPointerEvent constructor(
val type: PointerEventType,
- actual val changes: Map<PointerId, PointerInputChange>,
+ actual val changes: LongSparseArray<PointerInputChange>,
val buttons: PointerButtons,
val keyboardModifiers: PointerKeyboardModifiers,
val mouseEvent: MouseEvent?
) {
actual constructor(
- changes: Map<PointerId, PointerInputChange>,
+ changes: LongSparseArray<PointerInputChange>,
pointerInputEvent: PointerInputEvent
) : this(
pointerInputEvent.eventType,
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/pointer/PointerInputTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/pointer/PointerInputTest.kt
index ce8d51b..ec0e9b0 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/pointer/PointerInputTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/pointer/PointerInputTest.kt
@@ -17,11 +17,15 @@
package androidx.compose.ui.input.pointer
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.pointer.util.PointerIdArray
import com.google.common.truth.FailureMetadata
import com.google.common.truth.Subject
import com.google.common.truth.Subject.Factory
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual.equalTo
@@ -487,6 +491,48 @@
PointerInputChangeSubject.assertThat(actual2).positionChangeConsumed()
}
+ @Test
+ fun pointerIdArrayTest() {
+ val pointerIdArray = PointerIdArray()
+
+ assertEquals(0, pointerIdArray.size)
+
+ // These should not only set the values in the array, but also cause it to be resized
+ // to hold more than the initial default number of items (currently 2)
+ pointerIdArray[0] = PointerId(10)
+ pointerIdArray[1] = 11
+ pointerIdArray[2] = 12
+
+ assertEquals(3, pointerIdArray.size)
+ assertEquals(PointerId(10), pointerIdArray[0])
+ assertEquals(PointerId(11), pointerIdArray[1])
+ assertEquals(PointerId(12), pointerIdArray[2])
+
+ pointerIdArray.removeAt(0)
+ assertEquals(2, pointerIdArray.size)
+ assertEquals(PointerId(11), pointerIdArray[0])
+ assertEquals(PointerId(12), pointerIdArray[1])
+
+ pointerIdArray.clear()
+ assertEquals(0, pointerIdArray.size)
+
+ pointerIdArray.add(20)
+ pointerIdArray.add(21)
+ pointerIdArray.add(22)
+ pointerIdArray.add(23)
+ assertEquals(4, pointerIdArray.size)
+ pointerIdArray.remove(PointerId(21))
+ pointerIdArray.remove(22)
+ assertEquals(2, pointerIdArray.size)
+ assertEquals(PointerId(20), pointerIdArray[0])
+ assertEquals(PointerId(23), pointerIdArray[1])
+
+ assertTrue { pointerIdArray.contains(20) }
+ assertTrue { pointerIdArray.contains(PointerId(23)) }
+ assertFalse { pointerIdArray.contains(21) }
+ assertFalse { pointerIdArray.contains(PointerId(21)) }
+ }
+
// Private Helper
private fun createPointerInputChange(
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
index df004df..defab69 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
@@ -62,7 +62,6 @@
import androidx.compose.ui.semantics.SemanticsConfiguration
import androidx.compose.ui.semantics.SemanticsModifier
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
-import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.PlatformTextInputPluginRegistry
@@ -521,10 +520,10 @@
@Test
fun testLocalPositionOfWithSiblings() {
- val node0 = LayoutNode()
+ val node0 = ZeroSizedLayoutNode()
node0.attach(MockOwner())
- val node1 = LayoutNode()
- val node2 = LayoutNode()
+ val node1 = ZeroSizedLayoutNode()
+ val node2 = ZeroSizedLayoutNode()
node0.insertAt(0, node1)
node0.insertAt(1, node2)
node1.place(10, 20)
@@ -2530,7 +2529,6 @@
get() = Density(1f)
override val textInputService: TextInputService
get() = TODO("Not yet implemented")
- @OptIn(ExperimentalTextApi::class)
override val platformTextInputPluginRegistry: PlatformTextInputPluginRegistry
get() = TODO("Not yet implemented")
override val pointerIconService: PointerIconService
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
index 2a8fa30..62a2b15 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
@@ -41,7 +41,6 @@
import androidx.compose.ui.platform.TextToolbar
import androidx.compose.ui.platform.ViewConfiguration
import androidx.compose.ui.platform.WindowInfo
-import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.PlatformTextInputPluginRegistry
@@ -348,7 +347,6 @@
get() = TODO("Not yet implemented")
override val textInputService: TextInputService
get() = TODO("Not yet implemented")
- @OptIn(ExperimentalTextApi::class)
override val platformTextInputPluginRegistry: PlatformTextInputPluginRegistry
get() = TODO("Not yet implemented")
override val pointerIconService: PointerIconService
diff --git a/constraintlayout/constraintlayout-compose/api/current.txt b/constraintlayout/constraintlayout-compose/api/current.txt
index c0e3103..b0fdb82 100644
--- a/constraintlayout/constraintlayout-compose/api/current.txt
+++ b/constraintlayout/constraintlayout-compose/api/current.txt
@@ -917,18 +917,18 @@
public final class TransitionScope {
method public androidx.constraintlayout.compose.ConstrainedLayoutReference createRefFor(Object id);
+ method public float getMaxStaggerDelay();
method public androidx.constraintlayout.compose.Arc getMotionArc();
method public androidx.constraintlayout.compose.OnSwipe? getOnSwipe();
- method public float getStaggered();
method public void keyAttributes(androidx.constraintlayout.compose.ConstrainedLayoutReference![] targets, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.KeyAttributesScope,kotlin.Unit> keyAttributesContent);
method public void keyCycles(androidx.constraintlayout.compose.ConstrainedLayoutReference![] targets, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.KeyCyclesScope,kotlin.Unit> keyCyclesContent);
method public void keyPositions(androidx.constraintlayout.compose.ConstrainedLayoutReference![] targets, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.KeyPositionsScope,kotlin.Unit> keyPositionsContent);
+ method public void setMaxStaggerDelay(float);
method public void setMotionArc(androidx.constraintlayout.compose.Arc);
method public void setOnSwipe(androidx.constraintlayout.compose.OnSwipe?);
- method public void setStaggered(float);
+ property public final float maxStaggerDelay;
property public final androidx.constraintlayout.compose.Arc motionArc;
property public final androidx.constraintlayout.compose.OnSwipe? onSwipe;
- property public final float staggered;
}
public final class TransitionScopeKt {
diff --git a/constraintlayout/constraintlayout-compose/api/restricted_current.txt b/constraintlayout/constraintlayout-compose/api/restricted_current.txt
index 05b9702..19dadf9 100644
--- a/constraintlayout/constraintlayout-compose/api/restricted_current.txt
+++ b/constraintlayout/constraintlayout-compose/api/restricted_current.txt
@@ -998,18 +998,18 @@
public final class TransitionScope {
method public androidx.constraintlayout.compose.ConstrainedLayoutReference createRefFor(Object id);
+ method public float getMaxStaggerDelay();
method public androidx.constraintlayout.compose.Arc getMotionArc();
method public androidx.constraintlayout.compose.OnSwipe? getOnSwipe();
- method public float getStaggered();
method public void keyAttributes(androidx.constraintlayout.compose.ConstrainedLayoutReference![] targets, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.KeyAttributesScope,kotlin.Unit> keyAttributesContent);
method public void keyCycles(androidx.constraintlayout.compose.ConstrainedLayoutReference![] targets, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.KeyCyclesScope,kotlin.Unit> keyCyclesContent);
method public void keyPositions(androidx.constraintlayout.compose.ConstrainedLayoutReference![] targets, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.KeyPositionsScope,kotlin.Unit> keyPositionsContent);
+ method public void setMaxStaggerDelay(float);
method public void setMotionArc(androidx.constraintlayout.compose.Arc);
method public void setOnSwipe(androidx.constraintlayout.compose.OnSwipe?);
- method public void setStaggered(float);
+ property public final float maxStaggerDelay;
property public final androidx.constraintlayout.compose.Arc motionArc;
property public final androidx.constraintlayout.compose.OnSwipe? onSwipe;
- property public final float staggered;
}
public final class TransitionScopeKt {
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/demos/src/main/java/androidx/constraintlayout/compose/demos/StaggeredDemo.kt b/constraintlayout/constraintlayout-compose/integration-tests/demos/src/main/java/androidx/constraintlayout/compose/demos/StaggeredDemo.kt
index 39169ab..a3b52d1 100644
--- a/constraintlayout/constraintlayout-compose/integration-tests/demos/src/main/java/androidx/constraintlayout/compose/demos/StaggeredDemo.kt
+++ b/constraintlayout/constraintlayout-compose/integration-tests/demos/src/main/java/androidx/constraintlayout/compose/demos/StaggeredDemo.kt
@@ -93,7 +93,7 @@
}
}
) {
- staggered = staggeredValue
+ maxStaggerDelay = staggeredValue
}
}
},
diff --git a/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/MotionLayoutTest.kt b/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/MotionLayoutTest.kt
index 0098c1f..e815f8e 100644
--- a/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/MotionLayoutTest.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/MotionLayoutTest.kt
@@ -537,7 +537,7 @@
}
}
) {
- staggered = staggeredValue.value
+ maxStaggerDelay = staggeredValue.value
}
}
}
diff --git a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionSceneScope.kt b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionSceneScope.kt
index 102e092..4aee90f 100644
--- a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionSceneScope.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionSceneScope.kt
@@ -367,7 +367,7 @@
* The value is `Float.NaN` by default. Note that when all widgets are set to `Float.NaN`,
* MotionLayout will use the default way of calculating the weight.
*
- * @see TransitionScope.staggered
+ * @see TransitionScope.maxStaggerDelay
*/
var ConstrainScope.staggeredWeight: Float
get() {
diff --git a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/TransitionScope.kt b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/TransitionScope.kt
index 4fd540b..f40a4ba 100644
--- a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/TransitionScope.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/TransitionScope.kt
@@ -145,27 +145,54 @@
var onSwipe: OnSwipe? = null
/**
- * Defines the maximum delay (in progress percent) between a group of staggered widgets.
+ * Defines the maximum delay (in progress value) between a group of staggered widgets.
*
*
*
- * The amount of delay for each widget is on proportion to their final position on the layout,
- * weighted against each other.
- *
- * Where the weight is calculated as the Manhattan Distance from the top-left corner of the
- * layout.
- *
- * So the widget with the lowest weight will receive the most delay. A negative [staggered]
- * value inverts this logic, in which case, the widget with the lowest weight will receive no
- * delay.
+ * The amount of delay for each widget is decided based on its weight. Where the widget with the
+ * lowest weight will receive the full delay. A negative [maxStaggerDelay] value inverts this logic, so
+ * that the widget with the highest weight will receive the full delay.
*
*
*
- * You may set [MotionSceneScope.staggeredWeight] on a per-widget basis to get a custom
- * staggered order.
+ * By default, the weight of each widget is calculated as the Manhattan Distance from the
+ * top-left corner of the layout. You may set custom weights using
+ * [MotionSceneScope.staggeredWeight] on a per-widget basis, this essentially allows you to set
+ * a custom staggering order. Note that when you set custom weights, widgets without a custom
+ * weight will be ignored for this calculation and will animate without delay.
+ *
+ *
+ *
+ * The remaining widgets will receive a portion of this delay, based on their weight calculated
+ * against each other.
+ *
+ * This is the formula to calculate the progress delay for a widget **i**, where
+ * **Max/MinWeight** is defined by the maximum and minimum calculated (or custom) weight:
+ *
+ * ```
+ * progressDelay[i] = maxStaggerDelay * (1 - ((weight[i] - MinWeight) / (MaxWeight - MinWeight)))
+ * ```
+ *
+ * To simplify, this is the formula normalized against **MinWeight**:
+ *
+ * ```
+ * progressDelay[i] = maxStaggerDelay * (1 - weight[i] / MaxWeight)
+ * ```
+ *
+ * Example:
+ *
+ * Given three widgets with custom weights `[1, 2, 3]` and [maxStaggerDelay] = 0.7f.
+ *
+ * - Widget0 will start animating at `progress == 0.7f` for having the lowest weight.
+ *
+ * - Widget1 will start animating at `progress == 0.35f`
+ *
+ * - Widget2 will start animating at `progress == 0.0f`
+ *
+ * This is because the weights are distributed linearly among the widgets.
*/
@FloatRange(-1.0, 1.0, fromInclusive = false, toInclusive = false)
- var staggered: Float = 0.0f
+ var maxStaggerDelay: Float = 0.0f
/**
* Define KeyAttribute KeyFrames for the given [targets].
@@ -226,7 +253,7 @@
// `progress` value. Eg: `animateFloat(tween(duration, LinearEasing))`
// containerObject.putString("interpolator", easing.name)
// containerObject.putNumber("duration", durationMs.toFloat())
- containerObject.putNumber("staggered", staggered)
+ containerObject.putNumber("staggered", maxStaggerDelay)
onSwipe?.let {
containerObject.put("onSwipe", onSwipeObject)
onSwipeObject.putString("direction", it.direction.name)
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintSet.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintSet.java
index 4b86246..0a608ac 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintSet.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintSet.java
@@ -2833,8 +2833,8 @@
/**
* Center widget between the other two widgets.
- * (for sides see: {@link #TOP, {@link #BOTTOM}, {@link #START,
- * {@link #END}, {@link #LEFT, {@link #RIGHT})
+ * (for sides see: {@link #TOP}, {@link #BOTTOM}, {@link #START},
+ * {@link #END}, {@link #LEFT}, {@link #RIGHT})
* Note, sides must be all vertical or horizontal sides.
*
* @param centerID ID of the widget to be centered
@@ -2888,7 +2888,7 @@
/**
* Centers the widget horizontally to the left and right side on another widgets sides.
- * (for sides see: {@link #START, {@link #END}, {@link #LEFT, {@link #RIGHT})
+ * (for sides see: {@link #START}, {@link #END}, {@link #LEFT}, {@link #RIGHT})
*
* @param centerID ID of widget to be centered
* @param leftId The Id of the widget on the left side
@@ -2942,7 +2942,7 @@
/**
* Centers the widgets vertically to the top and bottom side on another widgets sides.
- * (for sides see: {@link #TOP, {@link #BOTTOM})
+ * (for sides see: {@link #TOP}, {@link #BOTTOM})
*
* @param centerID ID of widget to be centered
* @param topId The Id of the widget on the top side
@@ -2969,7 +2969,7 @@
* Widgets can be spaced with weights.
* This operation sets all the related margins to 0.
* <p>
- * (for sides see: {@link #TOP, {@link #BOTTOM})
+ * (for sides see: {@link #TOP}, {@link #BOTTOM})
*
* @param topId The id of the widget to connect to or PARENT_ID
* @param topSide the side of the start to connect to
@@ -3013,8 +3013,8 @@
* Widgets can be spaced with weights.
* This operation sets all the related margins to 0.
* <p>
- * (for sides see: {@link #START, {@link #END},
- * {@link #LEFT, {@link #RIGHT}
+ * (for sides see: {@link #START}, {@link #END},
+ * {@link #LEFT}, {@link #RIGHT})
*
* @param leftId The id of the widget to connect to or PARENT_ID
* @param leftSide the side of the start to connect to
@@ -3038,8 +3038,8 @@
/**
* Spaces a set of widgets horizontal between the view startID and endId.
* Widgets can be spaced with weights.
- * (for sides see: {@link #START, {@link #END},
- * {@link #LEFT, {@link #RIGHT})
+ * (for sides see: {@link #START}, {@link #END},
+ * {@link #LEFT}, {@link #RIGHT})
*
* @param startId The id of the widget to connect to or PARENT_ID
* @param startSide the side of the start to connect to
@@ -3094,8 +3094,8 @@
/**
* Create a constraint between two widgets.
- * (for sides see: {@link #TOP, {@link #BOTTOM}, {@link #START, {@link #END},
- * {@link #LEFT, {@link #RIGHT}, {@link #BASELINE})
+ * (for sides see: {@link #TOP}, {@link #BOTTOM}, {@link #START}, {@link #END},
+ * {@link #LEFT}, {@link #RIGHT}, {@link #BASELINE})
*
* @param startID the ID of the widget to be constrained
* @param startSide the side of the widget to constrain
@@ -3237,8 +3237,8 @@
/**
* Create a constraint between two widgets.
- * (for sides see: {@link #TOP, {@link #BOTTOM}, {@link #START,
- * {@link #END}, {@link #LEFT, {@link #RIGHT}, {@link #BASELINE})
+ * (for sides see: {@link #TOP}, {@link #BOTTOM}, {@link #START},
+ * {@link #END}, {@link #LEFT}, {@link #RIGHT}, {@link #BASELINE})
*
* @param startID the ID of the widget to be constrained
* @param startSide the side of the widget to constrain
diff --git a/core/core-ktx/api/1.11.0-beta02.txt b/core/core-ktx/api/1.11.0-beta02.txt
new file mode 100644
index 0000000..7a12effb
--- /dev/null
+++ b/core/core-ktx/api/1.11.0-beta02.txt
@@ -0,0 +1,634 @@
+// Signature format: 4.0
+package androidx.core.animation {
+
+ public final class AnimatorKt {
+ method public static inline android.animation.Animator.AnimatorListener addListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onRepeat);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener addPauseListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onPause);
+ method public static inline android.animation.Animator.AnimatorListener doOnCancel(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnEnd(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnPause(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnRepeat(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnResume(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnStart(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.content {
+
+ public final class ContentValuesKt {
+ method public static android.content.ContentValues contentValuesOf(kotlin.Pair<java.lang.String,?>... pairs);
+ }
+
+ public final class ContextKt {
+ method public static inline <reified T> T! getSystemService(android.content.Context);
+ method public static inline void withStyledAttributes(android.content.Context, optional android.util.AttributeSet? set, int[] attrs, optional @AttrRes int defStyleAttr, optional @StyleRes int defStyleRes, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+ method public static inline void withStyledAttributes(android.content.Context, @StyleRes int resourceId, int[] attrs, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+ }
+
+ public final class SharedPreferencesKt {
+ method public static inline void edit(android.content.SharedPreferences, optional boolean commit, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.content.res {
+
+ public final class TypedArrayKt {
+ method public static boolean getBooleanOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @ColorInt public static int getColorOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static android.content.res.ColorStateList getColorStateListOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static float getDimensionOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @Dimension public static int getDimensionPixelOffsetOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @Dimension public static int getDimensionPixelSizeOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static android.graphics.drawable.Drawable getDrawableOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static float getFloatOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @RequiresApi(26) public static android.graphics.Typeface getFontOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static int getIntOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static int getIntegerOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @AnyRes public static int getResourceIdOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static String getStringOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static CharSequence![] getTextArrayOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static CharSequence getTextOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static inline <R> R use(android.content.res.TypedArray, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,? extends R> block);
+ }
+
+}
+
+package androidx.core.database {
+
+ public final class CursorKt {
+ method public static inline byte[]? getBlobOrNull(android.database.Cursor, int index);
+ method public static inline Double? getDoubleOrNull(android.database.Cursor, int index);
+ method public static inline Float? getFloatOrNull(android.database.Cursor, int index);
+ method public static inline Integer? getIntOrNull(android.database.Cursor, int index);
+ method public static inline Long? getLongOrNull(android.database.Cursor, int index);
+ method public static inline Short? getShortOrNull(android.database.Cursor, int index);
+ method public static inline String? getStringOrNull(android.database.Cursor, int index);
+ }
+
+}
+
+package androidx.core.database.sqlite {
+
+ public final class SQLiteDatabaseKt {
+ method public static inline <T> T transaction(android.database.sqlite.SQLiteDatabase, optional boolean exclusive, kotlin.jvm.functions.Function1<? super android.database.sqlite.SQLiteDatabase,? extends T> body);
+ }
+
+}
+
+package androidx.core.graphics {
+
+ public final class BitmapKt {
+ method public static inline android.graphics.Bitmap applyCanvas(android.graphics.Bitmap, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.Point p);
+ method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.PointF p);
+ method public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config);
+ method @RequiresApi(26) public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config, optional boolean hasAlpha, optional android.graphics.ColorSpace colorSpace);
+ method public static inline operator int get(android.graphics.Bitmap, int x, int y);
+ method public static inline android.graphics.Bitmap scale(android.graphics.Bitmap, int width, int height, optional boolean filter);
+ method public static inline operator void set(android.graphics.Bitmap, int x, int y, @ColorInt int color);
+ }
+
+ public final class CanvasKt {
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.Path clipPath, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.Rect clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.RectF clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, int left, int top, int right, int bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withMatrix(android.graphics.Canvas, optional android.graphics.Matrix matrix, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withRotation(android.graphics.Canvas, optional float degrees, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withSave(android.graphics.Canvas, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withScale(android.graphics.Canvas, optional float x, optional float y, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withSkew(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withTranslation(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ }
+
+ public final class ColorKt {
+ method @RequiresApi(26) public static inline operator float component1(android.graphics.Color);
+ method public static inline operator int component1(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component1(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component2(android.graphics.Color);
+ method public static inline operator int component2(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component2(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component3(android.graphics.Color);
+ method public static inline operator int component3(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component3(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component4(android.graphics.Color);
+ method public static inline operator int component4(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component4(@ColorLong long);
+ method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace colorSpace);
+ method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace.Named colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace.Named colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace.Named colorSpace);
+ method public static inline int getAlpha(@ColorInt int);
+ method @RequiresApi(26) public static inline float getAlpha(@ColorLong long);
+ method public static inline int getBlue(@ColorInt int);
+ method @RequiresApi(26) public static inline float getBlue(@ColorLong long);
+ method @RequiresApi(26) public static inline android.graphics.ColorSpace getColorSpace(@ColorLong long);
+ method public static inline int getGreen(@ColorInt int);
+ method @RequiresApi(26) public static inline float getGreen(@ColorLong long);
+ method @RequiresApi(26) public static inline float getLuminance(@ColorInt int);
+ method @RequiresApi(26) public static inline float getLuminance(@ColorLong long);
+ method public static inline int getRed(@ColorInt int);
+ method @RequiresApi(26) public static inline float getRed(@ColorLong long);
+ method @RequiresApi(26) public static inline boolean isSrgb(@ColorLong long);
+ method @RequiresApi(26) public static inline boolean isWideGamut(@ColorLong long);
+ method @RequiresApi(26) public static operator android.graphics.Color plus(android.graphics.Color, android.graphics.Color c);
+ method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorInt int);
+ method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorLong long);
+ method @ColorInt public static inline int toColorInt(String);
+ method @ColorInt @RequiresApi(26) public static inline int toColorInt(@ColorLong long);
+ method @ColorLong @RequiresApi(26) public static inline long toColorLong(@ColorInt int);
+ }
+
+ public final class ImageDecoderKt {
+ method @RequiresApi(28) public static inline android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+ method @RequiresApi(28) public static inline android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+ }
+
+ public final class MatrixKt {
+ method public static android.graphics.Matrix rotationMatrix(float degrees, optional float px, optional float py);
+ method public static android.graphics.Matrix scaleMatrix(optional float sx, optional float sy);
+ method public static inline operator android.graphics.Matrix times(android.graphics.Matrix, android.graphics.Matrix m);
+ method public static android.graphics.Matrix translationMatrix(optional float tx, optional float ty);
+ method public static inline float[] values(android.graphics.Matrix);
+ }
+
+ public final class PaintKt {
+ method public static inline boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat? blendModeCompat);
+ }
+
+ public final class PathKt {
+ method @RequiresApi(19) public static inline infix android.graphics.Path and(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(26) public static Iterable<androidx.core.graphics.PathSegment> flatten(android.graphics.Path, optional float error);
+ method @RequiresApi(19) public static inline operator android.graphics.Path minus(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline infix android.graphics.Path or(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline operator android.graphics.Path plus(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline infix android.graphics.Path xor(android.graphics.Path, android.graphics.Path p);
+ }
+
+ public final class PictureKt {
+ method public static inline android.graphics.Picture record(android.graphics.Picture, int width, int height, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ }
+
+ public final class PointKt {
+ method public static inline operator int component1(android.graphics.Point);
+ method public static inline operator float component1(android.graphics.PointF);
+ method public static inline operator int component2(android.graphics.Point);
+ method public static inline operator float component2(android.graphics.PointF);
+ method public static inline operator android.graphics.Point div(android.graphics.Point, float scalar);
+ method public static inline operator android.graphics.PointF div(android.graphics.PointF, float scalar);
+ method public static inline operator android.graphics.Point minus(android.graphics.Point, android.graphics.Point p);
+ method public static inline operator android.graphics.Point minus(android.graphics.Point, int xy);
+ method public static inline operator android.graphics.PointF minus(android.graphics.PointF, android.graphics.PointF p);
+ method public static inline operator android.graphics.PointF minus(android.graphics.PointF, float xy);
+ method public static inline operator android.graphics.Point plus(android.graphics.Point, android.graphics.Point p);
+ method public static inline operator android.graphics.Point plus(android.graphics.Point, int xy);
+ method public static inline operator android.graphics.PointF plus(android.graphics.PointF, android.graphics.PointF p);
+ method public static inline operator android.graphics.PointF plus(android.graphics.PointF, float xy);
+ method public static inline operator android.graphics.Point times(android.graphics.Point, float scalar);
+ method public static inline operator android.graphics.PointF times(android.graphics.PointF, float scalar);
+ method public static inline android.graphics.Point toPoint(android.graphics.PointF);
+ method public static inline android.graphics.PointF toPointF(android.graphics.Point);
+ method public static inline operator android.graphics.Point unaryMinus(android.graphics.Point);
+ method public static inline operator android.graphics.PointF unaryMinus(android.graphics.PointF);
+ }
+
+ public final class PorterDuffKt {
+ method public static inline android.graphics.PorterDuffColorFilter toColorFilter(android.graphics.PorterDuff.Mode, int color);
+ method public static inline android.graphics.PorterDuffXfermode toXfermode(android.graphics.PorterDuff.Mode);
+ }
+
+ public final class RectKt {
+ method public static inline infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.RectF and(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator int component1(android.graphics.Rect);
+ method public static inline operator float component1(android.graphics.RectF);
+ method public static inline operator int component2(android.graphics.Rect);
+ method public static inline operator float component2(android.graphics.RectF);
+ method public static inline operator int component3(android.graphics.Rect);
+ method public static inline operator float component3(android.graphics.RectF);
+ method public static inline operator int component4(android.graphics.Rect);
+ method public static inline operator float component4(android.graphics.RectF);
+ method public static inline operator boolean contains(android.graphics.Rect, android.graphics.Point p);
+ method public static inline operator boolean contains(android.graphics.RectF, android.graphics.PointF p);
+ method public static inline operator android.graphics.Rect minus(android.graphics.Rect, android.graphics.Point xy);
+ method public static inline operator android.graphics.Region minus(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline operator android.graphics.Rect minus(android.graphics.Rect, int xy);
+ method public static inline operator android.graphics.RectF minus(android.graphics.RectF, android.graphics.PointF xy);
+ method public static inline operator android.graphics.Region minus(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.RectF minus(android.graphics.RectF, float xy);
+ method public static inline infix android.graphics.Rect or(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.RectF or(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Point xy);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, int xy);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.PointF xy);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, float xy);
+ method public static inline operator android.graphics.Rect times(android.graphics.Rect, int factor);
+ method public static inline operator android.graphics.RectF times(android.graphics.RectF, float factor);
+ method public static inline operator android.graphics.RectF times(android.graphics.RectF, int factor);
+ method public static inline android.graphics.Rect toRect(android.graphics.RectF);
+ method public static inline android.graphics.RectF toRectF(android.graphics.Rect);
+ method public static inline android.graphics.Region toRegion(android.graphics.Rect);
+ method public static inline android.graphics.Region toRegion(android.graphics.RectF);
+ method public static inline android.graphics.RectF transform(android.graphics.RectF, android.graphics.Matrix m);
+ method public static inline infix android.graphics.Region xor(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region xor(android.graphics.RectF, android.graphics.RectF r);
+ }
+
+ public final class RegionKt {
+ method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator boolean contains(android.graphics.Region, android.graphics.Point p);
+ method public static inline void forEach(android.graphics.Region, kotlin.jvm.functions.Function1<? super android.graphics.Rect,kotlin.Unit> action);
+ method public static operator java.util.Iterator<android.graphics.Rect> iterator(android.graphics.Region);
+ method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region not(android.graphics.Region);
+ method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region unaryMinus(android.graphics.Region);
+ method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Region r);
+ }
+
+ public final class ShaderKt {
+ method public static inline void transform(android.graphics.Shader, kotlin.jvm.functions.Function1<? super android.graphics.Matrix,kotlin.Unit> block);
+ }
+
+}
+
+package androidx.core.graphics.drawable {
+
+ public final class BitmapDrawableKt {
+ method public static inline android.graphics.drawable.BitmapDrawable toDrawable(android.graphics.Bitmap, android.content.res.Resources resources);
+ }
+
+ public final class ColorDrawableKt {
+ method @RequiresApi(26) public static inline android.graphics.drawable.ColorDrawable toDrawable(android.graphics.Color);
+ method public static inline android.graphics.drawable.ColorDrawable toDrawable(@ColorInt int);
+ }
+
+ public final class DrawableKt {
+ method public static android.graphics.Bitmap toBitmap(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+ method public static android.graphics.Bitmap? toBitmapOrNull(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+ method public static void updateBounds(android.graphics.drawable.Drawable, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ }
+
+ public final class IconKt {
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toAdaptiveIcon(android.graphics.Bitmap);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.graphics.Bitmap);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.net.Uri);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(byte[]);
+ }
+
+}
+
+package androidx.core.location {
+
+ public final class LocationKt {
+ method public static inline operator double component1(android.location.Location);
+ method public static inline operator double component2(android.location.Location);
+ }
+
+}
+
+package androidx.core.net {
+
+ public final class UriKt {
+ method public static java.io.File toFile(android.net.Uri);
+ method public static inline android.net.Uri toUri(java.io.File);
+ method public static inline android.net.Uri toUri(String);
+ }
+
+}
+
+package androidx.core.os {
+
+ public final class BundleKt {
+ method public static android.os.Bundle bundleOf();
+ method public static android.os.Bundle bundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+ }
+
+ public final class HandlerKt {
+ method public static inline Runnable postAtTime(android.os.Handler, long uptimeMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public static inline Runnable postDelayed(android.os.Handler, long delayInMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ }
+
+ @RequiresApi(31) public final class OutcomeReceiverKt {
+ method @RequiresApi(31) public static <R, E extends java.lang.Throwable> android.os.OutcomeReceiver<R,E> asOutcomeReceiver(kotlin.coroutines.Continuation<? super R>);
+ }
+
+ public final class PersistableBundleKt {
+ method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf();
+ method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+ method @RequiresApi(21) public static android.os.PersistableBundle toPersistableBundle(java.util.Map<java.lang.String,?>);
+ }
+
+ public final class TraceKt {
+ method @Deprecated public static inline <T> T trace(String sectionName, kotlin.jvm.functions.Function0<? extends T> block);
+ }
+
+}
+
+package androidx.core.text {
+
+ public final class CharSequenceKt {
+ method public static inline boolean isDigitsOnly(CharSequence);
+ method public static inline int trimmedLength(CharSequence);
+ }
+
+ public final class HtmlKt {
+ method public static inline android.text.Spanned parseAsHtml(String, optional int flags, optional android.text.Html.ImageGetter? imageGetter, optional android.text.Html.TagHandler? tagHandler);
+ method public static inline String toHtml(android.text.Spanned, optional int option);
+ }
+
+ public final class LocaleKt {
+ method @RequiresApi(17) public static inline int getLayoutDirection(java.util.Locale);
+ }
+
+ public final class SpannableStringBuilderKt {
+ method public static inline android.text.SpannableStringBuilder backgroundColor(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder bold(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannedString buildSpannedString(kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder color(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object span, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object![] spans, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder italic(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder scale(android.text.SpannableStringBuilder, float proportion, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder strikeThrough(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder subscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder superscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder underline(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ }
+
+ public final class SpannableStringKt {
+ method public static inline void clearSpans(android.text.Spannable);
+ method public static inline operator void set(android.text.Spannable, int start, int end, Object span);
+ method public static inline operator void set(android.text.Spannable, kotlin.ranges.IntRange range, Object span);
+ method public static inline android.text.Spannable toSpannable(CharSequence);
+ }
+
+ public final class SpannedStringKt {
+ method public static inline <reified T> T![] getSpans(android.text.Spanned, optional int start, optional int end);
+ method public static inline android.text.Spanned toSpanned(CharSequence);
+ }
+
+ public final class StringKt {
+ method public static inline String htmlEncode(String);
+ }
+
+}
+
+package androidx.core.transition {
+
+ public final class TransitionKt {
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener addListener(android.transition.Transition, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onPause);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnCancel(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnEnd(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnPause(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnResume(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnStart(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.util {
+
+ public final class AndroidXConsumerKt {
+ method public static <T> androidx.core.util.Consumer<T> asAndroidXConsumer(kotlin.coroutines.Continuation<? super T>);
+ }
+
+ public final class AtomicFileKt {
+ method @RequiresApi(17) public static inline byte[] readBytes(android.util.AtomicFile);
+ method @RequiresApi(17) public static String readText(android.util.AtomicFile, optional java.nio.charset.Charset charset);
+ method @RequiresApi(17) public static inline void tryWrite(android.util.AtomicFile, kotlin.jvm.functions.Function1<? super java.io.FileOutputStream,kotlin.Unit> block);
+ method @RequiresApi(17) public static void writeBytes(android.util.AtomicFile, byte[] array);
+ method @RequiresApi(17) public static void writeText(android.util.AtomicFile, String text, optional java.nio.charset.Charset charset);
+ }
+
+ @RequiresApi(24) public final class ConsumerKt {
+ method @RequiresApi(24) public static <T> java.util.function.Consumer<T> asConsumer(kotlin.coroutines.Continuation<? super T>);
+ }
+
+ public final class HalfKt {
+ method @RequiresApi(26) public static inline android.util.Half toHalf(double);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(float);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(String);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(@HalfFloat short);
+ }
+
+ public final class LongSparseArrayKt {
+ method @RequiresApi(16) public static inline operator <T> boolean contains(android.util.LongSparseArray<T>, long key);
+ method @RequiresApi(16) public static inline <T> boolean containsKey(android.util.LongSparseArray<T>, long key);
+ method @RequiresApi(16) public static inline <T> boolean containsValue(android.util.LongSparseArray<T>, T value);
+ method @RequiresApi(16) public static inline <T> void forEach(android.util.LongSparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Long,? super T,kotlin.Unit> action);
+ method @RequiresApi(16) public static inline <T> T getOrDefault(android.util.LongSparseArray<T>, long key, T defaultValue);
+ method @RequiresApi(16) public static inline <T> T getOrElse(android.util.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method @RequiresApi(16) public static inline <T> int getSize(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static inline <T> boolean isEmpty(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static inline <T> boolean isNotEmpty(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static <T> kotlin.collections.LongIterator keyIterator(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static operator <T> android.util.LongSparseArray<T> plus(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+ method @RequiresApi(16) public static <T> void putAll(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+ method @RequiresApi(16) public static <T> boolean remove(android.util.LongSparseArray<T>, long key, T value);
+ method @RequiresApi(16) public static inline operator <T> void set(android.util.LongSparseArray<T>, long key, T value);
+ method @RequiresApi(16) public static <T> java.util.Iterator<T> valueIterator(android.util.LongSparseArray<T>);
+ }
+
+ public final class LruCacheKt {
+ method public static inline <K, V> android.util.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 final class PairKt {
+ method public static inline operator <F, S> F component1(android.util.Pair<F,S>);
+ method public static inline operator <F, S> F component1(androidx.core.util.Pair<F,S>);
+ method public static inline operator <F, S> S component2(android.util.Pair<F,S>);
+ method public static inline operator <F, S> S component2(androidx.core.util.Pair<F,S>);
+ method public static inline <F, S> android.util.Pair<F,S> toAndroidPair(kotlin.Pair<? extends F,? extends S>);
+ method public static inline <F, S> androidx.core.util.Pair<F,S> toAndroidXPair(kotlin.Pair<? extends F,? extends S>);
+ method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(android.util.Pair<F,S>);
+ method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(androidx.core.util.Pair<F,S>);
+ }
+
+ public final class RangeKt {
+ method @RequiresApi(21) public static inline infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> and(android.util.Range<T>, android.util.Range<T> other);
+ method @RequiresApi(21) public static inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, android.util.Range<T> other);
+ method @RequiresApi(21) public static inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, T value);
+ method @RequiresApi(21) public static inline infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> rangeTo(T, T that);
+ method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> kotlin.ranges.ClosedRange<T> toClosedRange(android.util.Range<T>);
+ method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> toRange(kotlin.ranges.ClosedRange<T>);
+ }
+
+ public final class RunnableKt {
+ method public static Runnable asRunnable(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ }
+
+ public final class SizeKt {
+ method @RequiresApi(21) public static inline operator int component1(android.util.Size);
+ method @RequiresApi(21) public static inline operator float component1(android.util.SizeF);
+ method public static inline operator float component1(androidx.core.util.SizeFCompat);
+ method @RequiresApi(21) public static inline operator int component2(android.util.Size);
+ method @RequiresApi(21) public static inline operator float component2(android.util.SizeF);
+ method public static inline operator float component2(androidx.core.util.SizeFCompat);
+ }
+
+ public final class SparseArrayKt {
+ method public static inline operator <T> boolean contains(android.util.SparseArray<T>, int key);
+ method public static inline <T> boolean containsKey(android.util.SparseArray<T>, int key);
+ method public static inline <T> boolean containsValue(android.util.SparseArray<T>, T value);
+ method public static inline <T> void forEach(android.util.SparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,kotlin.Unit> action);
+ method public static inline <T> T getOrDefault(android.util.SparseArray<T>, int key, T defaultValue);
+ method public static inline <T> T getOrElse(android.util.SparseArray<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method public static inline <T> int getSize(android.util.SparseArray<T>);
+ method public static inline <T> boolean isEmpty(android.util.SparseArray<T>);
+ method public static inline <T> boolean isNotEmpty(android.util.SparseArray<T>);
+ method public static <T> kotlin.collections.IntIterator keyIterator(android.util.SparseArray<T>);
+ method public static operator <T> android.util.SparseArray<T> plus(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+ method public static <T> void putAll(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+ method public static <T> boolean remove(android.util.SparseArray<T>, int key, T value);
+ method public static inline operator <T> void set(android.util.SparseArray<T>, int key, T value);
+ method public static <T> java.util.Iterator<T> valueIterator(android.util.SparseArray<T>);
+ }
+
+ public final class SparseBooleanArrayKt {
+ method public static inline operator boolean contains(android.util.SparseBooleanArray, int key);
+ method public static inline boolean containsKey(android.util.SparseBooleanArray, int key);
+ method public static inline boolean containsValue(android.util.SparseBooleanArray, boolean value);
+ method public static inline void forEach(android.util.SparseBooleanArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> action);
+ method public static inline boolean getOrDefault(android.util.SparseBooleanArray, int key, boolean defaultValue);
+ method public static inline boolean getOrElse(android.util.SparseBooleanArray, int key, kotlin.jvm.functions.Function0<java.lang.Boolean> defaultValue);
+ method public static inline int getSize(android.util.SparseBooleanArray);
+ method public static inline boolean isEmpty(android.util.SparseBooleanArray);
+ method public static inline boolean isNotEmpty(android.util.SparseBooleanArray);
+ method public static kotlin.collections.IntIterator keyIterator(android.util.SparseBooleanArray);
+ method public static operator android.util.SparseBooleanArray plus(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+ method public static void putAll(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+ method public static boolean remove(android.util.SparseBooleanArray, int key, boolean value);
+ method public static inline operator void set(android.util.SparseBooleanArray, int key, boolean value);
+ method public static kotlin.collections.BooleanIterator valueIterator(android.util.SparseBooleanArray);
+ }
+
+ public final class SparseIntArrayKt {
+ method public static inline operator boolean contains(android.util.SparseIntArray, int key);
+ method public static inline boolean containsKey(android.util.SparseIntArray, int key);
+ method public static inline boolean containsValue(android.util.SparseIntArray, int value);
+ method public static inline void forEach(android.util.SparseIntArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ method public static inline int getOrDefault(android.util.SparseIntArray, int key, int defaultValue);
+ method public static inline int getOrElse(android.util.SparseIntArray, int key, kotlin.jvm.functions.Function0<java.lang.Integer> defaultValue);
+ method public static inline int getSize(android.util.SparseIntArray);
+ method public static inline boolean isEmpty(android.util.SparseIntArray);
+ method public static inline boolean isNotEmpty(android.util.SparseIntArray);
+ method public static kotlin.collections.IntIterator keyIterator(android.util.SparseIntArray);
+ method public static operator android.util.SparseIntArray plus(android.util.SparseIntArray, android.util.SparseIntArray other);
+ method public static void putAll(android.util.SparseIntArray, android.util.SparseIntArray other);
+ method public static boolean remove(android.util.SparseIntArray, int key, int value);
+ method public static inline operator void set(android.util.SparseIntArray, int key, int value);
+ method public static kotlin.collections.IntIterator valueIterator(android.util.SparseIntArray);
+ }
+
+ public final class SparseLongArrayKt {
+ method @RequiresApi(18) public static inline operator boolean contains(android.util.SparseLongArray, int key);
+ method @RequiresApi(18) public static inline boolean containsKey(android.util.SparseLongArray, int key);
+ method @RequiresApi(18) public static inline boolean containsValue(android.util.SparseLongArray, long value);
+ method @RequiresApi(18) public static inline void forEach(android.util.SparseLongArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Long,kotlin.Unit> action);
+ method @RequiresApi(18) public static inline long getOrDefault(android.util.SparseLongArray, int key, long defaultValue);
+ method @RequiresApi(18) public static inline long getOrElse(android.util.SparseLongArray, int key, kotlin.jvm.functions.Function0<java.lang.Long> defaultValue);
+ method @RequiresApi(18) public static inline int getSize(android.util.SparseLongArray);
+ method @RequiresApi(18) public static inline boolean isEmpty(android.util.SparseLongArray);
+ method @RequiresApi(18) public static inline boolean isNotEmpty(android.util.SparseLongArray);
+ method @RequiresApi(18) public static kotlin.collections.IntIterator keyIterator(android.util.SparseLongArray);
+ method @RequiresApi(18) public static operator android.util.SparseLongArray plus(android.util.SparseLongArray, android.util.SparseLongArray other);
+ method @RequiresApi(18) public static void putAll(android.util.SparseLongArray, android.util.SparseLongArray other);
+ method @RequiresApi(18) public static boolean remove(android.util.SparseLongArray, int key, long value);
+ method @RequiresApi(18) public static inline operator void set(android.util.SparseLongArray, int key, long value);
+ method @RequiresApi(18) public static kotlin.collections.LongIterator valueIterator(android.util.SparseLongArray);
+ }
+
+}
+
+package androidx.core.view {
+
+ public final class MenuKt {
+ method public static operator boolean contains(android.view.Menu, android.view.MenuItem item);
+ method public static inline void forEach(android.view.Menu, kotlin.jvm.functions.Function1<? super android.view.MenuItem,kotlin.Unit> action);
+ method public static inline void forEachIndexed(android.view.Menu, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.MenuItem,kotlin.Unit> action);
+ method public static inline operator android.view.MenuItem get(android.view.Menu, int index);
+ method public static kotlin.sequences.Sequence<android.view.MenuItem> getChildren(android.view.Menu);
+ method public static inline int getSize(android.view.Menu);
+ method public static inline boolean isEmpty(android.view.Menu);
+ method public static inline boolean isNotEmpty(android.view.Menu);
+ method public static operator java.util.Iterator<android.view.MenuItem> iterator(android.view.Menu);
+ method public static inline operator void minusAssign(android.view.Menu, android.view.MenuItem item);
+ method public static inline void removeItemAt(android.view.Menu, int index);
+ }
+
+ public final class ViewGroupKt {
+ method public static inline operator boolean contains(android.view.ViewGroup, android.view.View view);
+ method public static inline void forEach(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void forEachIndexed(android.view.ViewGroup, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.View,kotlin.Unit> action);
+ method public static operator android.view.View get(android.view.ViewGroup, int index);
+ method public static kotlin.sequences.Sequence<android.view.View> getChildren(android.view.ViewGroup);
+ method public static kotlin.sequences.Sequence<android.view.View> getDescendants(android.view.ViewGroup);
+ method public static inline kotlin.ranges.IntRange getIndices(android.view.ViewGroup);
+ method public static inline int getSize(android.view.ViewGroup);
+ method public static inline boolean isEmpty(android.view.ViewGroup);
+ method public static inline boolean isNotEmpty(android.view.ViewGroup);
+ method public static operator java.util.Iterator<android.view.View> iterator(android.view.ViewGroup);
+ method public static inline operator void minusAssign(android.view.ViewGroup, android.view.View view);
+ method public static inline operator void plusAssign(android.view.ViewGroup, android.view.View view);
+ method public static inline void setMargins(android.view.ViewGroup.MarginLayoutParams, @Px int size);
+ method public static inline void updateMargins(android.view.ViewGroup.MarginLayoutParams, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ method @RequiresApi(17) public static inline void updateMarginsRelative(android.view.ViewGroup.MarginLayoutParams, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+ }
+
+ public final class ViewKt {
+ method public static inline void doOnAttach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnDetach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnNextLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline androidx.core.view.OneShotPreDrawListener doOnPreDraw(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static android.graphics.Bitmap drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config);
+ method public static kotlin.sequences.Sequence<android.view.View> getAllViews(android.view.View);
+ method public static kotlin.sequences.Sequence<android.view.ViewParent> getAncestors(android.view.View);
+ method public static inline int getMarginBottom(android.view.View);
+ method public static inline int getMarginEnd(android.view.View);
+ method public static inline int getMarginLeft(android.view.View);
+ method public static inline int getMarginRight(android.view.View);
+ method public static inline int getMarginStart(android.view.View);
+ method public static inline int getMarginTop(android.view.View);
+ method public static inline boolean isGone(android.view.View);
+ method public static inline boolean isInvisible(android.view.View);
+ method public static inline boolean isVisible(android.view.View);
+ method public static inline Runnable postDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method @RequiresApi(16) public static Runnable postOnAnimationDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public static inline void setGone(android.view.View, boolean);
+ method public static inline void setInvisible(android.view.View, boolean);
+ method public static inline void setPadding(android.view.View, @Px int size);
+ method public static inline void setVisible(android.view.View, boolean);
+ method public static inline void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
+ method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParamsTyped(android.view.View, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
+ method public static inline void updatePadding(android.view.View, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ method @RequiresApi(17) public static inline void updatePaddingRelative(android.view.View, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+ }
+
+}
+
+package androidx.core.widget {
+
+ public final class TextViewKt {
+ method public static inline android.text.TextWatcher addTextChangedListener(android.widget.TextView, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> beforeTextChanged, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> onTextChanged, optional kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> afterTextChanged);
+ method public static inline android.text.TextWatcher doAfterTextChanged(android.widget.TextView, kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> action);
+ method public static inline android.text.TextWatcher doBeforeTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ method public static inline android.text.TextWatcher doOnTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ }
+
+}
+
diff --git a/core/core-ktx/api/current.ignore b/core/core-ktx/api/current.ignore
deleted file mode 100644
index 6557477..0000000
--- a/core/core-ktx/api/current.ignore
+++ /dev/null
@@ -1,17 +0,0 @@
-// Baseline format: 1.0
-InvalidNullConversion: androidx.core.util.LongSparseArrayKt#containsValue(android.util.LongSparseArray<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.LongSparseArrayKt.containsValue(android.util.LongSparseArray<T> arg1, T value)
-InvalidNullConversion: androidx.core.util.LongSparseArrayKt#getOrDefault(android.util.LongSparseArray<T>, long, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter defaultValue in androidx.core.util.LongSparseArrayKt.getOrDefault(android.util.LongSparseArray<T> arg1, long key, T defaultValue)
-InvalidNullConversion: androidx.core.util.LongSparseArrayKt#remove(android.util.LongSparseArray<T>, long, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.LongSparseArrayKt.remove(android.util.LongSparseArray<T> arg1, long key, T value)
-InvalidNullConversion: androidx.core.util.LongSparseArrayKt#set(android.util.LongSparseArray<T>, long, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.LongSparseArrayKt.set(android.util.LongSparseArray<T> arg1, long key, T value)
-InvalidNullConversion: androidx.core.util.SparseArrayKt#containsValue(android.util.SparseArray<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.SparseArrayKt.containsValue(android.util.SparseArray<T> arg1, T value)
-InvalidNullConversion: androidx.core.util.SparseArrayKt#getOrDefault(android.util.SparseArray<T>, int, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter defaultValue in androidx.core.util.SparseArrayKt.getOrDefault(android.util.SparseArray<T> arg1, int key, T defaultValue)
-InvalidNullConversion: androidx.core.util.SparseArrayKt#remove(android.util.SparseArray<T>, int, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.SparseArrayKt.remove(android.util.SparseArray<T> arg1, int key, T value)
-InvalidNullConversion: androidx.core.util.SparseArrayKt#set(android.util.SparseArray<T>, int, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.SparseArrayKt.set(android.util.SparseArray<T> arg1, int key, T value)
diff --git a/core/core-ktx/api/res-1.11.0-beta02.txt b/core/core-ktx/api/res-1.11.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/core-ktx/api/res-1.11.0-beta02.txt
diff --git a/core/core-ktx/api/restricted_1.11.0-beta02.txt b/core/core-ktx/api/restricted_1.11.0-beta02.txt
new file mode 100644
index 0000000..7a12effb
--- /dev/null
+++ b/core/core-ktx/api/restricted_1.11.0-beta02.txt
@@ -0,0 +1,634 @@
+// Signature format: 4.0
+package androidx.core.animation {
+
+ public final class AnimatorKt {
+ method public static inline android.animation.Animator.AnimatorListener addListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onRepeat);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener addPauseListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onPause);
+ method public static inline android.animation.Animator.AnimatorListener doOnCancel(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnEnd(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnPause(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnRepeat(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnResume(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnStart(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.content {
+
+ public final class ContentValuesKt {
+ method public static android.content.ContentValues contentValuesOf(kotlin.Pair<java.lang.String,?>... pairs);
+ }
+
+ public final class ContextKt {
+ method public static inline <reified T> T! getSystemService(android.content.Context);
+ method public static inline void withStyledAttributes(android.content.Context, optional android.util.AttributeSet? set, int[] attrs, optional @AttrRes int defStyleAttr, optional @StyleRes int defStyleRes, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+ method public static inline void withStyledAttributes(android.content.Context, @StyleRes int resourceId, int[] attrs, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+ }
+
+ public final class SharedPreferencesKt {
+ method public static inline void edit(android.content.SharedPreferences, optional boolean commit, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.content.res {
+
+ public final class TypedArrayKt {
+ method public static boolean getBooleanOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @ColorInt public static int getColorOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static android.content.res.ColorStateList getColorStateListOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static float getDimensionOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @Dimension public static int getDimensionPixelOffsetOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @Dimension public static int getDimensionPixelSizeOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static android.graphics.drawable.Drawable getDrawableOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static float getFloatOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @RequiresApi(26) public static android.graphics.Typeface getFontOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static int getIntOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static int getIntegerOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @AnyRes public static int getResourceIdOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static String getStringOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static CharSequence![] getTextArrayOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static CharSequence getTextOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static inline <R> R use(android.content.res.TypedArray, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,? extends R> block);
+ }
+
+}
+
+package androidx.core.database {
+
+ public final class CursorKt {
+ method public static inline byte[]? getBlobOrNull(android.database.Cursor, int index);
+ method public static inline Double? getDoubleOrNull(android.database.Cursor, int index);
+ method public static inline Float? getFloatOrNull(android.database.Cursor, int index);
+ method public static inline Integer? getIntOrNull(android.database.Cursor, int index);
+ method public static inline Long? getLongOrNull(android.database.Cursor, int index);
+ method public static inline Short? getShortOrNull(android.database.Cursor, int index);
+ method public static inline String? getStringOrNull(android.database.Cursor, int index);
+ }
+
+}
+
+package androidx.core.database.sqlite {
+
+ public final class SQLiteDatabaseKt {
+ method public static inline <T> T transaction(android.database.sqlite.SQLiteDatabase, optional boolean exclusive, kotlin.jvm.functions.Function1<? super android.database.sqlite.SQLiteDatabase,? extends T> body);
+ }
+
+}
+
+package androidx.core.graphics {
+
+ public final class BitmapKt {
+ method public static inline android.graphics.Bitmap applyCanvas(android.graphics.Bitmap, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.Point p);
+ method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.PointF p);
+ method public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config);
+ method @RequiresApi(26) public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config, optional boolean hasAlpha, optional android.graphics.ColorSpace colorSpace);
+ method public static inline operator int get(android.graphics.Bitmap, int x, int y);
+ method public static inline android.graphics.Bitmap scale(android.graphics.Bitmap, int width, int height, optional boolean filter);
+ method public static inline operator void set(android.graphics.Bitmap, int x, int y, @ColorInt int color);
+ }
+
+ public final class CanvasKt {
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.Path clipPath, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.Rect clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.RectF clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, int left, int top, int right, int bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withMatrix(android.graphics.Canvas, optional android.graphics.Matrix matrix, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withRotation(android.graphics.Canvas, optional float degrees, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withSave(android.graphics.Canvas, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withScale(android.graphics.Canvas, optional float x, optional float y, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withSkew(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withTranslation(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ }
+
+ public final class ColorKt {
+ method @RequiresApi(26) public static inline operator float component1(android.graphics.Color);
+ method public static inline operator int component1(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component1(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component2(android.graphics.Color);
+ method public static inline operator int component2(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component2(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component3(android.graphics.Color);
+ method public static inline operator int component3(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component3(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component4(android.graphics.Color);
+ method public static inline operator int component4(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component4(@ColorLong long);
+ method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace colorSpace);
+ method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace.Named colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace.Named colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace.Named colorSpace);
+ method public static inline int getAlpha(@ColorInt int);
+ method @RequiresApi(26) public static inline float getAlpha(@ColorLong long);
+ method public static inline int getBlue(@ColorInt int);
+ method @RequiresApi(26) public static inline float getBlue(@ColorLong long);
+ method @RequiresApi(26) public static inline android.graphics.ColorSpace getColorSpace(@ColorLong long);
+ method public static inline int getGreen(@ColorInt int);
+ method @RequiresApi(26) public static inline float getGreen(@ColorLong long);
+ method @RequiresApi(26) public static inline float getLuminance(@ColorInt int);
+ method @RequiresApi(26) public static inline float getLuminance(@ColorLong long);
+ method public static inline int getRed(@ColorInt int);
+ method @RequiresApi(26) public static inline float getRed(@ColorLong long);
+ method @RequiresApi(26) public static inline boolean isSrgb(@ColorLong long);
+ method @RequiresApi(26) public static inline boolean isWideGamut(@ColorLong long);
+ method @RequiresApi(26) public static operator android.graphics.Color plus(android.graphics.Color, android.graphics.Color c);
+ method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorInt int);
+ method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorLong long);
+ method @ColorInt public static inline int toColorInt(String);
+ method @ColorInt @RequiresApi(26) public static inline int toColorInt(@ColorLong long);
+ method @ColorLong @RequiresApi(26) public static inline long toColorLong(@ColorInt int);
+ }
+
+ public final class ImageDecoderKt {
+ method @RequiresApi(28) public static inline android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+ method @RequiresApi(28) public static inline android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+ }
+
+ public final class MatrixKt {
+ method public static android.graphics.Matrix rotationMatrix(float degrees, optional float px, optional float py);
+ method public static android.graphics.Matrix scaleMatrix(optional float sx, optional float sy);
+ method public static inline operator android.graphics.Matrix times(android.graphics.Matrix, android.graphics.Matrix m);
+ method public static android.graphics.Matrix translationMatrix(optional float tx, optional float ty);
+ method public static inline float[] values(android.graphics.Matrix);
+ }
+
+ public final class PaintKt {
+ method public static inline boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat? blendModeCompat);
+ }
+
+ public final class PathKt {
+ method @RequiresApi(19) public static inline infix android.graphics.Path and(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(26) public static Iterable<androidx.core.graphics.PathSegment> flatten(android.graphics.Path, optional float error);
+ method @RequiresApi(19) public static inline operator android.graphics.Path minus(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline infix android.graphics.Path or(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline operator android.graphics.Path plus(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline infix android.graphics.Path xor(android.graphics.Path, android.graphics.Path p);
+ }
+
+ public final class PictureKt {
+ method public static inline android.graphics.Picture record(android.graphics.Picture, int width, int height, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ }
+
+ public final class PointKt {
+ method public static inline operator int component1(android.graphics.Point);
+ method public static inline operator float component1(android.graphics.PointF);
+ method public static inline operator int component2(android.graphics.Point);
+ method public static inline operator float component2(android.graphics.PointF);
+ method public static inline operator android.graphics.Point div(android.graphics.Point, float scalar);
+ method public static inline operator android.graphics.PointF div(android.graphics.PointF, float scalar);
+ method public static inline operator android.graphics.Point minus(android.graphics.Point, android.graphics.Point p);
+ method public static inline operator android.graphics.Point minus(android.graphics.Point, int xy);
+ method public static inline operator android.graphics.PointF minus(android.graphics.PointF, android.graphics.PointF p);
+ method public static inline operator android.graphics.PointF minus(android.graphics.PointF, float xy);
+ method public static inline operator android.graphics.Point plus(android.graphics.Point, android.graphics.Point p);
+ method public static inline operator android.graphics.Point plus(android.graphics.Point, int xy);
+ method public static inline operator android.graphics.PointF plus(android.graphics.PointF, android.graphics.PointF p);
+ method public static inline operator android.graphics.PointF plus(android.graphics.PointF, float xy);
+ method public static inline operator android.graphics.Point times(android.graphics.Point, float scalar);
+ method public static inline operator android.graphics.PointF times(android.graphics.PointF, float scalar);
+ method public static inline android.graphics.Point toPoint(android.graphics.PointF);
+ method public static inline android.graphics.PointF toPointF(android.graphics.Point);
+ method public static inline operator android.graphics.Point unaryMinus(android.graphics.Point);
+ method public static inline operator android.graphics.PointF unaryMinus(android.graphics.PointF);
+ }
+
+ public final class PorterDuffKt {
+ method public static inline android.graphics.PorterDuffColorFilter toColorFilter(android.graphics.PorterDuff.Mode, int color);
+ method public static inline android.graphics.PorterDuffXfermode toXfermode(android.graphics.PorterDuff.Mode);
+ }
+
+ public final class RectKt {
+ method public static inline infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.RectF and(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator int component1(android.graphics.Rect);
+ method public static inline operator float component1(android.graphics.RectF);
+ method public static inline operator int component2(android.graphics.Rect);
+ method public static inline operator float component2(android.graphics.RectF);
+ method public static inline operator int component3(android.graphics.Rect);
+ method public static inline operator float component3(android.graphics.RectF);
+ method public static inline operator int component4(android.graphics.Rect);
+ method public static inline operator float component4(android.graphics.RectF);
+ method public static inline operator boolean contains(android.graphics.Rect, android.graphics.Point p);
+ method public static inline operator boolean contains(android.graphics.RectF, android.graphics.PointF p);
+ method public static inline operator android.graphics.Rect minus(android.graphics.Rect, android.graphics.Point xy);
+ method public static inline operator android.graphics.Region minus(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline operator android.graphics.Rect minus(android.graphics.Rect, int xy);
+ method public static inline operator android.graphics.RectF minus(android.graphics.RectF, android.graphics.PointF xy);
+ method public static inline operator android.graphics.Region minus(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.RectF minus(android.graphics.RectF, float xy);
+ method public static inline infix android.graphics.Rect or(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.RectF or(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Point xy);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, int xy);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.PointF xy);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, float xy);
+ method public static inline operator android.graphics.Rect times(android.graphics.Rect, int factor);
+ method public static inline operator android.graphics.RectF times(android.graphics.RectF, float factor);
+ method public static inline operator android.graphics.RectF times(android.graphics.RectF, int factor);
+ method public static inline android.graphics.Rect toRect(android.graphics.RectF);
+ method public static inline android.graphics.RectF toRectF(android.graphics.Rect);
+ method public static inline android.graphics.Region toRegion(android.graphics.Rect);
+ method public static inline android.graphics.Region toRegion(android.graphics.RectF);
+ method public static inline android.graphics.RectF transform(android.graphics.RectF, android.graphics.Matrix m);
+ method public static inline infix android.graphics.Region xor(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region xor(android.graphics.RectF, android.graphics.RectF r);
+ }
+
+ public final class RegionKt {
+ method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator boolean contains(android.graphics.Region, android.graphics.Point p);
+ method public static inline void forEach(android.graphics.Region, kotlin.jvm.functions.Function1<? super android.graphics.Rect,kotlin.Unit> action);
+ method public static operator java.util.Iterator<android.graphics.Rect> iterator(android.graphics.Region);
+ method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region not(android.graphics.Region);
+ method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region unaryMinus(android.graphics.Region);
+ method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Region r);
+ }
+
+ public final class ShaderKt {
+ method public static inline void transform(android.graphics.Shader, kotlin.jvm.functions.Function1<? super android.graphics.Matrix,kotlin.Unit> block);
+ }
+
+}
+
+package androidx.core.graphics.drawable {
+
+ public final class BitmapDrawableKt {
+ method public static inline android.graphics.drawable.BitmapDrawable toDrawable(android.graphics.Bitmap, android.content.res.Resources resources);
+ }
+
+ public final class ColorDrawableKt {
+ method @RequiresApi(26) public static inline android.graphics.drawable.ColorDrawable toDrawable(android.graphics.Color);
+ method public static inline android.graphics.drawable.ColorDrawable toDrawable(@ColorInt int);
+ }
+
+ public final class DrawableKt {
+ method public static android.graphics.Bitmap toBitmap(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+ method public static android.graphics.Bitmap? toBitmapOrNull(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+ method public static void updateBounds(android.graphics.drawable.Drawable, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ }
+
+ public final class IconKt {
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toAdaptiveIcon(android.graphics.Bitmap);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.graphics.Bitmap);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.net.Uri);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(byte[]);
+ }
+
+}
+
+package androidx.core.location {
+
+ public final class LocationKt {
+ method public static inline operator double component1(android.location.Location);
+ method public static inline operator double component2(android.location.Location);
+ }
+
+}
+
+package androidx.core.net {
+
+ public final class UriKt {
+ method public static java.io.File toFile(android.net.Uri);
+ method public static inline android.net.Uri toUri(java.io.File);
+ method public static inline android.net.Uri toUri(String);
+ }
+
+}
+
+package androidx.core.os {
+
+ public final class BundleKt {
+ method public static android.os.Bundle bundleOf();
+ method public static android.os.Bundle bundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+ }
+
+ public final class HandlerKt {
+ method public static inline Runnable postAtTime(android.os.Handler, long uptimeMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public static inline Runnable postDelayed(android.os.Handler, long delayInMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ }
+
+ @RequiresApi(31) public final class OutcomeReceiverKt {
+ method @RequiresApi(31) public static <R, E extends java.lang.Throwable> android.os.OutcomeReceiver<R,E> asOutcomeReceiver(kotlin.coroutines.Continuation<? super R>);
+ }
+
+ public final class PersistableBundleKt {
+ method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf();
+ method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+ method @RequiresApi(21) public static android.os.PersistableBundle toPersistableBundle(java.util.Map<java.lang.String,?>);
+ }
+
+ public final class TraceKt {
+ method @Deprecated public static inline <T> T trace(String sectionName, kotlin.jvm.functions.Function0<? extends T> block);
+ }
+
+}
+
+package androidx.core.text {
+
+ public final class CharSequenceKt {
+ method public static inline boolean isDigitsOnly(CharSequence);
+ method public static inline int trimmedLength(CharSequence);
+ }
+
+ public final class HtmlKt {
+ method public static inline android.text.Spanned parseAsHtml(String, optional int flags, optional android.text.Html.ImageGetter? imageGetter, optional android.text.Html.TagHandler? tagHandler);
+ method public static inline String toHtml(android.text.Spanned, optional int option);
+ }
+
+ public final class LocaleKt {
+ method @RequiresApi(17) public static inline int getLayoutDirection(java.util.Locale);
+ }
+
+ public final class SpannableStringBuilderKt {
+ method public static inline android.text.SpannableStringBuilder backgroundColor(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder bold(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannedString buildSpannedString(kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder color(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object span, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object![] spans, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder italic(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder scale(android.text.SpannableStringBuilder, float proportion, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder strikeThrough(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder subscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder superscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder underline(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ }
+
+ public final class SpannableStringKt {
+ method public static inline void clearSpans(android.text.Spannable);
+ method public static inline operator void set(android.text.Spannable, int start, int end, Object span);
+ method public static inline operator void set(android.text.Spannable, kotlin.ranges.IntRange range, Object span);
+ method public static inline android.text.Spannable toSpannable(CharSequence);
+ }
+
+ public final class SpannedStringKt {
+ method public static inline <reified T> T![] getSpans(android.text.Spanned, optional int start, optional int end);
+ method public static inline android.text.Spanned toSpanned(CharSequence);
+ }
+
+ public final class StringKt {
+ method public static inline String htmlEncode(String);
+ }
+
+}
+
+package androidx.core.transition {
+
+ public final class TransitionKt {
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener addListener(android.transition.Transition, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onPause);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnCancel(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnEnd(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnPause(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnResume(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnStart(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.util {
+
+ public final class AndroidXConsumerKt {
+ method public static <T> androidx.core.util.Consumer<T> asAndroidXConsumer(kotlin.coroutines.Continuation<? super T>);
+ }
+
+ public final class AtomicFileKt {
+ method @RequiresApi(17) public static inline byte[] readBytes(android.util.AtomicFile);
+ method @RequiresApi(17) public static String readText(android.util.AtomicFile, optional java.nio.charset.Charset charset);
+ method @RequiresApi(17) public static inline void tryWrite(android.util.AtomicFile, kotlin.jvm.functions.Function1<? super java.io.FileOutputStream,kotlin.Unit> block);
+ method @RequiresApi(17) public static void writeBytes(android.util.AtomicFile, byte[] array);
+ method @RequiresApi(17) public static void writeText(android.util.AtomicFile, String text, optional java.nio.charset.Charset charset);
+ }
+
+ @RequiresApi(24) public final class ConsumerKt {
+ method @RequiresApi(24) public static <T> java.util.function.Consumer<T> asConsumer(kotlin.coroutines.Continuation<? super T>);
+ }
+
+ public final class HalfKt {
+ method @RequiresApi(26) public static inline android.util.Half toHalf(double);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(float);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(String);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(@HalfFloat short);
+ }
+
+ public final class LongSparseArrayKt {
+ method @RequiresApi(16) public static inline operator <T> boolean contains(android.util.LongSparseArray<T>, long key);
+ method @RequiresApi(16) public static inline <T> boolean containsKey(android.util.LongSparseArray<T>, long key);
+ method @RequiresApi(16) public static inline <T> boolean containsValue(android.util.LongSparseArray<T>, T value);
+ method @RequiresApi(16) public static inline <T> void forEach(android.util.LongSparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Long,? super T,kotlin.Unit> action);
+ method @RequiresApi(16) public static inline <T> T getOrDefault(android.util.LongSparseArray<T>, long key, T defaultValue);
+ method @RequiresApi(16) public static inline <T> T getOrElse(android.util.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method @RequiresApi(16) public static inline <T> int getSize(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static inline <T> boolean isEmpty(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static inline <T> boolean isNotEmpty(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static <T> kotlin.collections.LongIterator keyIterator(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static operator <T> android.util.LongSparseArray<T> plus(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+ method @RequiresApi(16) public static <T> void putAll(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+ method @RequiresApi(16) public static <T> boolean remove(android.util.LongSparseArray<T>, long key, T value);
+ method @RequiresApi(16) public static inline operator <T> void set(android.util.LongSparseArray<T>, long key, T value);
+ method @RequiresApi(16) public static <T> java.util.Iterator<T> valueIterator(android.util.LongSparseArray<T>);
+ }
+
+ public final class LruCacheKt {
+ method public static inline <K, V> android.util.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 final class PairKt {
+ method public static inline operator <F, S> F component1(android.util.Pair<F,S>);
+ method public static inline operator <F, S> F component1(androidx.core.util.Pair<F,S>);
+ method public static inline operator <F, S> S component2(android.util.Pair<F,S>);
+ method public static inline operator <F, S> S component2(androidx.core.util.Pair<F,S>);
+ method public static inline <F, S> android.util.Pair<F,S> toAndroidPair(kotlin.Pair<? extends F,? extends S>);
+ method public static inline <F, S> androidx.core.util.Pair<F,S> toAndroidXPair(kotlin.Pair<? extends F,? extends S>);
+ method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(android.util.Pair<F,S>);
+ method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(androidx.core.util.Pair<F,S>);
+ }
+
+ public final class RangeKt {
+ method @RequiresApi(21) public static inline infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> and(android.util.Range<T>, android.util.Range<T> other);
+ method @RequiresApi(21) public static inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, android.util.Range<T> other);
+ method @RequiresApi(21) public static inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, T value);
+ method @RequiresApi(21) public static inline infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> rangeTo(T, T that);
+ method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> kotlin.ranges.ClosedRange<T> toClosedRange(android.util.Range<T>);
+ method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> toRange(kotlin.ranges.ClosedRange<T>);
+ }
+
+ public final class RunnableKt {
+ method public static Runnable asRunnable(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ }
+
+ public final class SizeKt {
+ method @RequiresApi(21) public static inline operator int component1(android.util.Size);
+ method @RequiresApi(21) public static inline operator float component1(android.util.SizeF);
+ method public static inline operator float component1(androidx.core.util.SizeFCompat);
+ method @RequiresApi(21) public static inline operator int component2(android.util.Size);
+ method @RequiresApi(21) public static inline operator float component2(android.util.SizeF);
+ method public static inline operator float component2(androidx.core.util.SizeFCompat);
+ }
+
+ public final class SparseArrayKt {
+ method public static inline operator <T> boolean contains(android.util.SparseArray<T>, int key);
+ method public static inline <T> boolean containsKey(android.util.SparseArray<T>, int key);
+ method public static inline <T> boolean containsValue(android.util.SparseArray<T>, T value);
+ method public static inline <T> void forEach(android.util.SparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,kotlin.Unit> action);
+ method public static inline <T> T getOrDefault(android.util.SparseArray<T>, int key, T defaultValue);
+ method public static inline <T> T getOrElse(android.util.SparseArray<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method public static inline <T> int getSize(android.util.SparseArray<T>);
+ method public static inline <T> boolean isEmpty(android.util.SparseArray<T>);
+ method public static inline <T> boolean isNotEmpty(android.util.SparseArray<T>);
+ method public static <T> kotlin.collections.IntIterator keyIterator(android.util.SparseArray<T>);
+ method public static operator <T> android.util.SparseArray<T> plus(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+ method public static <T> void putAll(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+ method public static <T> boolean remove(android.util.SparseArray<T>, int key, T value);
+ method public static inline operator <T> void set(android.util.SparseArray<T>, int key, T value);
+ method public static <T> java.util.Iterator<T> valueIterator(android.util.SparseArray<T>);
+ }
+
+ public final class SparseBooleanArrayKt {
+ method public static inline operator boolean contains(android.util.SparseBooleanArray, int key);
+ method public static inline boolean containsKey(android.util.SparseBooleanArray, int key);
+ method public static inline boolean containsValue(android.util.SparseBooleanArray, boolean value);
+ method public static inline void forEach(android.util.SparseBooleanArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> action);
+ method public static inline boolean getOrDefault(android.util.SparseBooleanArray, int key, boolean defaultValue);
+ method public static inline boolean getOrElse(android.util.SparseBooleanArray, int key, kotlin.jvm.functions.Function0<java.lang.Boolean> defaultValue);
+ method public static inline int getSize(android.util.SparseBooleanArray);
+ method public static inline boolean isEmpty(android.util.SparseBooleanArray);
+ method public static inline boolean isNotEmpty(android.util.SparseBooleanArray);
+ method public static kotlin.collections.IntIterator keyIterator(android.util.SparseBooleanArray);
+ method public static operator android.util.SparseBooleanArray plus(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+ method public static void putAll(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+ method public static boolean remove(android.util.SparseBooleanArray, int key, boolean value);
+ method public static inline operator void set(android.util.SparseBooleanArray, int key, boolean value);
+ method public static kotlin.collections.BooleanIterator valueIterator(android.util.SparseBooleanArray);
+ }
+
+ public final class SparseIntArrayKt {
+ method public static inline operator boolean contains(android.util.SparseIntArray, int key);
+ method public static inline boolean containsKey(android.util.SparseIntArray, int key);
+ method public static inline boolean containsValue(android.util.SparseIntArray, int value);
+ method public static inline void forEach(android.util.SparseIntArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ method public static inline int getOrDefault(android.util.SparseIntArray, int key, int defaultValue);
+ method public static inline int getOrElse(android.util.SparseIntArray, int key, kotlin.jvm.functions.Function0<java.lang.Integer> defaultValue);
+ method public static inline int getSize(android.util.SparseIntArray);
+ method public static inline boolean isEmpty(android.util.SparseIntArray);
+ method public static inline boolean isNotEmpty(android.util.SparseIntArray);
+ method public static kotlin.collections.IntIterator keyIterator(android.util.SparseIntArray);
+ method public static operator android.util.SparseIntArray plus(android.util.SparseIntArray, android.util.SparseIntArray other);
+ method public static void putAll(android.util.SparseIntArray, android.util.SparseIntArray other);
+ method public static boolean remove(android.util.SparseIntArray, int key, int value);
+ method public static inline operator void set(android.util.SparseIntArray, int key, int value);
+ method public static kotlin.collections.IntIterator valueIterator(android.util.SparseIntArray);
+ }
+
+ public final class SparseLongArrayKt {
+ method @RequiresApi(18) public static inline operator boolean contains(android.util.SparseLongArray, int key);
+ method @RequiresApi(18) public static inline boolean containsKey(android.util.SparseLongArray, int key);
+ method @RequiresApi(18) public static inline boolean containsValue(android.util.SparseLongArray, long value);
+ method @RequiresApi(18) public static inline void forEach(android.util.SparseLongArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Long,kotlin.Unit> action);
+ method @RequiresApi(18) public static inline long getOrDefault(android.util.SparseLongArray, int key, long defaultValue);
+ method @RequiresApi(18) public static inline long getOrElse(android.util.SparseLongArray, int key, kotlin.jvm.functions.Function0<java.lang.Long> defaultValue);
+ method @RequiresApi(18) public static inline int getSize(android.util.SparseLongArray);
+ method @RequiresApi(18) public static inline boolean isEmpty(android.util.SparseLongArray);
+ method @RequiresApi(18) public static inline boolean isNotEmpty(android.util.SparseLongArray);
+ method @RequiresApi(18) public static kotlin.collections.IntIterator keyIterator(android.util.SparseLongArray);
+ method @RequiresApi(18) public static operator android.util.SparseLongArray plus(android.util.SparseLongArray, android.util.SparseLongArray other);
+ method @RequiresApi(18) public static void putAll(android.util.SparseLongArray, android.util.SparseLongArray other);
+ method @RequiresApi(18) public static boolean remove(android.util.SparseLongArray, int key, long value);
+ method @RequiresApi(18) public static inline operator void set(android.util.SparseLongArray, int key, long value);
+ method @RequiresApi(18) public static kotlin.collections.LongIterator valueIterator(android.util.SparseLongArray);
+ }
+
+}
+
+package androidx.core.view {
+
+ public final class MenuKt {
+ method public static operator boolean contains(android.view.Menu, android.view.MenuItem item);
+ method public static inline void forEach(android.view.Menu, kotlin.jvm.functions.Function1<? super android.view.MenuItem,kotlin.Unit> action);
+ method public static inline void forEachIndexed(android.view.Menu, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.MenuItem,kotlin.Unit> action);
+ method public static inline operator android.view.MenuItem get(android.view.Menu, int index);
+ method public static kotlin.sequences.Sequence<android.view.MenuItem> getChildren(android.view.Menu);
+ method public static inline int getSize(android.view.Menu);
+ method public static inline boolean isEmpty(android.view.Menu);
+ method public static inline boolean isNotEmpty(android.view.Menu);
+ method public static operator java.util.Iterator<android.view.MenuItem> iterator(android.view.Menu);
+ method public static inline operator void minusAssign(android.view.Menu, android.view.MenuItem item);
+ method public static inline void removeItemAt(android.view.Menu, int index);
+ }
+
+ public final class ViewGroupKt {
+ method public static inline operator boolean contains(android.view.ViewGroup, android.view.View view);
+ method public static inline void forEach(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void forEachIndexed(android.view.ViewGroup, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.View,kotlin.Unit> action);
+ method public static operator android.view.View get(android.view.ViewGroup, int index);
+ method public static kotlin.sequences.Sequence<android.view.View> getChildren(android.view.ViewGroup);
+ method public static kotlin.sequences.Sequence<android.view.View> getDescendants(android.view.ViewGroup);
+ method public static inline kotlin.ranges.IntRange getIndices(android.view.ViewGroup);
+ method public static inline int getSize(android.view.ViewGroup);
+ method public static inline boolean isEmpty(android.view.ViewGroup);
+ method public static inline boolean isNotEmpty(android.view.ViewGroup);
+ method public static operator java.util.Iterator<android.view.View> iterator(android.view.ViewGroup);
+ method public static inline operator void minusAssign(android.view.ViewGroup, android.view.View view);
+ method public static inline operator void plusAssign(android.view.ViewGroup, android.view.View view);
+ method public static inline void setMargins(android.view.ViewGroup.MarginLayoutParams, @Px int size);
+ method public static inline void updateMargins(android.view.ViewGroup.MarginLayoutParams, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ method @RequiresApi(17) public static inline void updateMarginsRelative(android.view.ViewGroup.MarginLayoutParams, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+ }
+
+ public final class ViewKt {
+ method public static inline void doOnAttach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnDetach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnNextLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline androidx.core.view.OneShotPreDrawListener doOnPreDraw(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static android.graphics.Bitmap drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config);
+ method public static kotlin.sequences.Sequence<android.view.View> getAllViews(android.view.View);
+ method public static kotlin.sequences.Sequence<android.view.ViewParent> getAncestors(android.view.View);
+ method public static inline int getMarginBottom(android.view.View);
+ method public static inline int getMarginEnd(android.view.View);
+ method public static inline int getMarginLeft(android.view.View);
+ method public static inline int getMarginRight(android.view.View);
+ method public static inline int getMarginStart(android.view.View);
+ method public static inline int getMarginTop(android.view.View);
+ method public static inline boolean isGone(android.view.View);
+ method public static inline boolean isInvisible(android.view.View);
+ method public static inline boolean isVisible(android.view.View);
+ method public static inline Runnable postDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method @RequiresApi(16) public static Runnable postOnAnimationDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public static inline void setGone(android.view.View, boolean);
+ method public static inline void setInvisible(android.view.View, boolean);
+ method public static inline void setPadding(android.view.View, @Px int size);
+ method public static inline void setVisible(android.view.View, boolean);
+ method public static inline void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
+ method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParamsTyped(android.view.View, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
+ method public static inline void updatePadding(android.view.View, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ method @RequiresApi(17) public static inline void updatePaddingRelative(android.view.View, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+ }
+
+}
+
+package androidx.core.widget {
+
+ public final class TextViewKt {
+ method public static inline android.text.TextWatcher addTextChangedListener(android.widget.TextView, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> beforeTextChanged, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> onTextChanged, optional kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> afterTextChanged);
+ method public static inline android.text.TextWatcher doAfterTextChanged(android.widget.TextView, kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> action);
+ method public static inline android.text.TextWatcher doBeforeTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ method public static inline android.text.TextWatcher doOnTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ }
+
+}
+
diff --git a/core/core-ktx/api/restricted_current.ignore b/core/core-ktx/api/restricted_current.ignore
deleted file mode 100644
index 6557477..0000000
--- a/core/core-ktx/api/restricted_current.ignore
+++ /dev/null
@@ -1,17 +0,0 @@
-// Baseline format: 1.0
-InvalidNullConversion: androidx.core.util.LongSparseArrayKt#containsValue(android.util.LongSparseArray<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.LongSparseArrayKt.containsValue(android.util.LongSparseArray<T> arg1, T value)
-InvalidNullConversion: androidx.core.util.LongSparseArrayKt#getOrDefault(android.util.LongSparseArray<T>, long, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter defaultValue in androidx.core.util.LongSparseArrayKt.getOrDefault(android.util.LongSparseArray<T> arg1, long key, T defaultValue)
-InvalidNullConversion: androidx.core.util.LongSparseArrayKt#remove(android.util.LongSparseArray<T>, long, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.LongSparseArrayKt.remove(android.util.LongSparseArray<T> arg1, long key, T value)
-InvalidNullConversion: androidx.core.util.LongSparseArrayKt#set(android.util.LongSparseArray<T>, long, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.LongSparseArrayKt.set(android.util.LongSparseArray<T> arg1, long key, T value)
-InvalidNullConversion: androidx.core.util.SparseArrayKt#containsValue(android.util.SparseArray<T>, T) parameter #1:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.SparseArrayKt.containsValue(android.util.SparseArray<T> arg1, T value)
-InvalidNullConversion: androidx.core.util.SparseArrayKt#getOrDefault(android.util.SparseArray<T>, int, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter defaultValue in androidx.core.util.SparseArrayKt.getOrDefault(android.util.SparseArray<T> arg1, int key, T defaultValue)
-InvalidNullConversion: androidx.core.util.SparseArrayKt#remove(android.util.SparseArray<T>, int, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.SparseArrayKt.remove(android.util.SparseArray<T> arg1, int key, T value)
-InvalidNullConversion: androidx.core.util.SparseArrayKt#set(android.util.SparseArray<T>, int, T) parameter #2:
- Attempted to change parameter from @Nullable to @NonNull: incompatible change for parameter value in androidx.core.util.SparseArrayKt.set(android.util.SparseArray<T> arg1, int key, T value)
diff --git a/core/core-ktx/src/main/java/androidx/core/os/Trace.kt b/core/core-ktx/src/main/java/androidx/core/os/Trace.kt
index f7f9462..da489ef 100644
--- a/core/core-ktx/src/main/java/androidx/core/os/Trace.kt
+++ b/core/core-ktx/src/main/java/androidx/core/os/Trace.kt
@@ -25,7 +25,7 @@
@Deprecated(
"Use androidx.tracing.Trace instead",
replaceWith = ReplaceWith(
- "trace(sectionName)",
+ "trace(sectionName, block)",
imports = arrayOf("androidx.tracing.trace")
)
)
diff --git a/core/core-testing/api/1.11.0-beta02.txt b/core/core-testing/api/1.11.0-beta02.txt
new file mode 100644
index 0000000..40c6d07
--- /dev/null
+++ b/core/core-testing/api/1.11.0-beta02.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.core.testing.util {
+
+ public final class TestConsumer<T> implements androidx.core.util.Consumer<T> {
+ ctor public TestConsumer();
+ method public void accept(T t);
+ method public void assertValues(java.util.List<? extends T> values);
+ }
+
+}
+
diff --git a/core/core-testing/api/res-1.11.0-beta02.txt b/core/core-testing/api/res-1.11.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/core-testing/api/res-1.11.0-beta02.txt
diff --git a/core/core-testing/api/restricted_1.11.0-beta02.txt b/core/core-testing/api/restricted_1.11.0-beta02.txt
new file mode 100644
index 0000000..40c6d07
--- /dev/null
+++ b/core/core-testing/api/restricted_1.11.0-beta02.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.core.testing.util {
+
+ public final class TestConsumer<T> implements androidx.core.util.Consumer<T> {
+ ctor public TestConsumer();
+ method public void accept(T t);
+ method public void assertValues(java.util.List<? extends T> values);
+ }
+
+}
+
diff --git a/core/core/api/1.11.0-beta01.txt b/core/core/api/1.11.0-beta01.txt
index 0c385e3..128f0c4 100644
--- a/core/core/api/1.11.0-beta01.txt
+++ b/core/core/api/1.11.0-beta01.txt
@@ -1446,7 +1446,7 @@
method @ColorInt public static int HSLToColor(float[]);
method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
- method @ColorInt public static int M3HCTtoColor(float, float, float);
+ method @ColorInt public static int M3HCTToColor(@FloatRange(from=0.0, to=360, toInclusive=false) float, @FloatRange(from=0.0, to=java.lang.Double.POSITIVE_INFINITY, toInclusive=false) float, @FloatRange(from=0.0, to=100) float);
method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
@@ -1460,7 +1460,7 @@
method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
method public static void colorToHSL(@ColorInt int, float[]);
method public static void colorToLAB(@ColorInt int, double[]);
- method public static void colorToM3HCT(@ColorInt int, float[]);
+ method public static void colorToM3HCT(@ColorInt int, @Size(3) float[]);
method public static void colorToXYZ(@ColorInt int, double[]);
method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
method public static int compositeColors(@ColorInt int, @ColorInt int);
diff --git a/core/core/api/1.11.0-beta02.txt b/core/core/api/1.11.0-beta02.txt
new file mode 100644
index 0000000..128f0c4
--- /dev/null
+++ b/core/core/api/1.11.0-beta02.txt
@@ -0,0 +1,4061 @@
+// Signature format: 4.0
+package androidx.core.accessibilityservice {
+
+ public final class AccessibilityServiceInfoCompat {
+ method public static String capabilityToString(int);
+ method public static String feedbackTypeToString(int);
+ method public static String? flagToString(int);
+ method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+ method public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+ field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+ field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+ field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+ field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+ field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+ field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+ field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+ field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+ field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+ field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+ field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+ }
+
+}
+
+package androidx.core.app {
+
+ public class ActivityCompat extends androidx.core.content.ContextCompat {
+ ctor protected ActivityCompat();
+ method public static void finishAffinity(android.app.Activity);
+ method public static void finishAfterTransition(android.app.Activity);
+ method public static android.net.Uri? getReferrer(android.app.Activity);
+ method @Deprecated public static boolean invalidateOptionsMenu(android.app.Activity!);
+ method public static boolean isLaunchedFromBubble(android.app.Activity);
+ method public static void postponeEnterTransition(android.app.Activity);
+ method public static void recreate(android.app.Activity);
+ method public static androidx.core.view.DragAndDropPermissionsCompat? requestDragAndDropPermissions(android.app.Activity, android.view.DragEvent);
+ method public static void requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+ method public static <T extends android.view.View> T requireViewById(android.app.Activity, @IdRes int);
+ method public static void setEnterSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+ method public static void setExitSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+ method public static void setLocusContext(android.app.Activity, androidx.core.content.LocusIdCompat?, android.os.Bundle?);
+ method public static void setPermissionCompatDelegate(androidx.core.app.ActivityCompat.PermissionCompatDelegate?);
+ method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, String);
+ method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle?);
+ method public static void startIntentSenderForResult(android.app.Activity, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public static void startPostponedEnterTransition(android.app.Activity);
+ }
+
+ public static interface ActivityCompat.OnRequestPermissionsResultCallback {
+ method public void onRequestPermissionsResult(int, String![], int[]);
+ }
+
+ public static interface ActivityCompat.PermissionCompatDelegate {
+ method public boolean onActivityResult(android.app.Activity, @IntRange(from=0) int, int, android.content.Intent?);
+ method public boolean requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+ }
+
+ public final class ActivityManagerCompat {
+ method public static boolean isLowRamDevice(android.app.ActivityManager);
+ }
+
+ public class ActivityOptionsCompat {
+ ctor protected ActivityOptionsCompat();
+ method public android.graphics.Rect? getLaunchBounds();
+ method public static androidx.core.app.ActivityOptionsCompat makeBasic();
+ method public static androidx.core.app.ActivityOptionsCompat makeClipRevealAnimation(android.view.View, int, int, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, String);
+ method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, androidx.core.util.Pair<android.view.View!,java.lang.String!>!...);
+ method public static androidx.core.app.ActivityOptionsCompat makeTaskLaunchBehind();
+ method public static androidx.core.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+ method public void requestUsageTimeReport(android.app.PendingIntent);
+ method public androidx.core.app.ActivityOptionsCompat setLaunchBounds(android.graphics.Rect?);
+ method public android.os.Bundle? toBundle();
+ method public void update(androidx.core.app.ActivityOptionsCompat);
+ field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
+ field public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+ }
+
+ public final class AlarmManagerCompat {
+ method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
+ method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ }
+
+ @RequiresApi(28) public class AppComponentFactory extends android.app.AppComponentFactory {
+ ctor public AppComponentFactory();
+ method public final android.app.Activity instantiateActivity(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Activity instantiateActivityCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.app.Application instantiateApplication(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Application instantiateApplicationCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.content.ContentProvider instantiateProvider(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.ContentProvider instantiateProviderCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.content.BroadcastReceiver instantiateReceiver(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.BroadcastReceiver instantiateReceiverCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.app.Service instantiateService(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Service instantiateServiceCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ }
+
+ public class AppLaunchChecker {
+ ctor @Deprecated public AppLaunchChecker();
+ method public static boolean hasStartedFromLauncher(android.content.Context);
+ method public static void onActivityCreate(android.app.Activity);
+ }
+
+ public final class AppOpsManagerCompat {
+ method public static int checkOrNoteProxyOp(android.content.Context, int, String, String);
+ method public static int noteOp(android.content.Context, String, int, String);
+ method public static int noteOpNoThrow(android.content.Context, String, int, String);
+ method public static int noteProxyOp(android.content.Context, String, String);
+ method public static int noteProxyOpNoThrow(android.content.Context, String, String);
+ method public static String? permissionToOp(String);
+ field public static final int MODE_ALLOWED = 0; // 0x0
+ field public static final int MODE_DEFAULT = 3; // 0x3
+ field public static final int MODE_ERRORED = 2; // 0x2
+ field public static final int MODE_IGNORED = 1; // 0x1
+ }
+
+ @Deprecated public final class BundleCompat {
+ method @Deprecated public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+ method @Deprecated public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+ }
+
+ public class DialogCompat {
+ method public static android.view.View requireViewById(android.app.Dialog, int);
+ }
+
+ public class FrameMetricsAggregator {
+ ctor public FrameMetricsAggregator();
+ ctor public FrameMetricsAggregator(int);
+ method public void add(android.app.Activity);
+ method public android.util.SparseIntArray![]? getMetrics();
+ method public android.util.SparseIntArray![]? remove(android.app.Activity);
+ method public android.util.SparseIntArray![]? reset();
+ method public android.util.SparseIntArray![]? stop();
+ field public static final int ANIMATION_DURATION = 256; // 0x100
+ field public static final int ANIMATION_INDEX = 8; // 0x8
+ field public static final int COMMAND_DURATION = 32; // 0x20
+ field public static final int COMMAND_INDEX = 5; // 0x5
+ field public static final int DELAY_DURATION = 128; // 0x80
+ field public static final int DELAY_INDEX = 7; // 0x7
+ field public static final int DRAW_DURATION = 8; // 0x8
+ field public static final int DRAW_INDEX = 3; // 0x3
+ field public static final int EVERY_DURATION = 511; // 0x1ff
+ field public static final int INPUT_DURATION = 2; // 0x2
+ field public static final int INPUT_INDEX = 1; // 0x1
+ field public static final int LAYOUT_MEASURE_DURATION = 4; // 0x4
+ field public static final int LAYOUT_MEASURE_INDEX = 2; // 0x2
+ field public static final int SWAP_DURATION = 64; // 0x40
+ field public static final int SWAP_INDEX = 6; // 0x6
+ field public static final int SYNC_DURATION = 16; // 0x10
+ field public static final int SYNC_INDEX = 4; // 0x4
+ field public static final int TOTAL_DURATION = 1; // 0x1
+ field public static final int TOTAL_INDEX = 0; // 0x0
+ }
+
+ @Deprecated public abstract class JobIntentService extends android.app.Service {
+ ctor @Deprecated public JobIntentService();
+ method @Deprecated public static void enqueueWork(android.content.Context, android.content.ComponentName, int, android.content.Intent);
+ method @Deprecated public static void enqueueWork(android.content.Context, Class<?>, int, android.content.Intent);
+ method @Deprecated public boolean isStopped();
+ method @Deprecated public android.os.IBinder! onBind(android.content.Intent);
+ method @Deprecated protected abstract void onHandleWork(android.content.Intent);
+ method @Deprecated public boolean onStopCurrentWork();
+ method @Deprecated public void setInterruptIfStopped(boolean);
+ }
+
+ public final class LocaleManagerCompat {
+ method @AnyThread public static androidx.core.os.LocaleListCompat getApplicationLocales(android.content.Context);
+ method @AnyThread public static androidx.core.os.LocaleListCompat getSystemLocales(android.content.Context);
+ }
+
+ public final class MultiWindowModeChangedInfo {
+ ctor public MultiWindowModeChangedInfo(boolean);
+ ctor @RequiresApi(26) public MultiWindowModeChangedInfo(boolean, android.content.res.Configuration);
+ method @RequiresApi(26) public android.content.res.Configuration getNewConfig();
+ method public boolean isInMultiWindowMode();
+ }
+
+ public final class NavUtils {
+ method public static android.content.Intent? getParentActivityIntent(android.app.Activity);
+ method public static android.content.Intent? getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static android.content.Intent? getParentActivityIntent(android.content.Context, Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static String? getParentActivityName(android.app.Activity);
+ method public static String? getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static void navigateUpFromSameTask(android.app.Activity);
+ method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+ method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+ field public static final String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+ }
+
+ public class NotificationChannelCompat {
+ method public boolean canBubble();
+ method public boolean canBypassDnd();
+ method public boolean canShowBadge();
+ method public android.media.AudioAttributes? getAudioAttributes();
+ method public String? getConversationId();
+ method public String? getDescription();
+ method public String? getGroup();
+ method public String getId();
+ method public int getImportance();
+ method public int getLightColor();
+ method public int getLockscreenVisibility();
+ method public CharSequence? getName();
+ method public String? getParentChannelId();
+ method public android.net.Uri? getSound();
+ method public long[]? getVibrationPattern();
+ method public boolean isImportantConversation();
+ method public boolean shouldShowLights();
+ method public boolean shouldVibrate();
+ method public androidx.core.app.NotificationChannelCompat.Builder toBuilder();
+ field public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
+ }
+
+ public static class NotificationChannelCompat.Builder {
+ ctor public NotificationChannelCompat.Builder(String, int);
+ method public androidx.core.app.NotificationChannelCompat build();
+ method public androidx.core.app.NotificationChannelCompat.Builder setConversationId(String, String);
+ method public androidx.core.app.NotificationChannelCompat.Builder setDescription(String?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setGroup(String?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setImportance(int);
+ method public androidx.core.app.NotificationChannelCompat.Builder setLightColor(int);
+ method public androidx.core.app.NotificationChannelCompat.Builder setLightsEnabled(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setName(CharSequence?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setShowBadge(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setSound(android.net.Uri?, android.media.AudioAttributes?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setVibrationEnabled(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setVibrationPattern(long[]?);
+ }
+
+ public class NotificationChannelGroupCompat {
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getChannels();
+ method public String? getDescription();
+ method public String getId();
+ method public CharSequence? getName();
+ method public boolean isBlocked();
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder toBuilder();
+ }
+
+ public static class NotificationChannelGroupCompat.Builder {
+ ctor public NotificationChannelGroupCompat.Builder(String);
+ method public androidx.core.app.NotificationChannelGroupCompat build();
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder setDescription(String?);
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder setName(CharSequence?);
+ }
+
+ public class NotificationCompat {
+ ctor @Deprecated public NotificationCompat();
+ method public static androidx.core.app.NotificationCompat.Action? getAction(android.app.Notification, int);
+ method public static int getActionCount(android.app.Notification);
+ method public static boolean getAllowSystemGeneratedContextualActions(android.app.Notification);
+ method public static boolean getAutoCancel(android.app.Notification);
+ method public static int getBadgeIconType(android.app.Notification);
+ method public static androidx.core.app.NotificationCompat.BubbleMetadata? getBubbleMetadata(android.app.Notification);
+ method public static String? getCategory(android.app.Notification);
+ method public static String? getChannelId(android.app.Notification);
+ method public static int getColor(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentInfo(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentText(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentTitle(android.app.Notification);
+ method public static android.os.Bundle? getExtras(android.app.Notification);
+ method public static String? getGroup(android.app.Notification);
+ method public static int getGroupAlertBehavior(android.app.Notification);
+ method @RequiresApi(21) public static java.util.List<androidx.core.app.NotificationCompat.Action!> getInvisibleActions(android.app.Notification);
+ method public static boolean getLocalOnly(android.app.Notification);
+ method public static androidx.core.content.LocusIdCompat? getLocusId(android.app.Notification);
+ method public static boolean getOngoing(android.app.Notification);
+ method public static boolean getOnlyAlertOnce(android.app.Notification);
+ method public static java.util.List<androidx.core.app.Person!> getPeople(android.app.Notification);
+ method public static android.app.Notification? getPublicVersion(android.app.Notification);
+ method public static CharSequence? getSettingsText(android.app.Notification);
+ method public static String? getShortcutId(android.app.Notification);
+ method @RequiresApi(19) public static boolean getShowWhen(android.app.Notification);
+ method public static String? getSortKey(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getSubText(android.app.Notification);
+ method public static long getTimeoutAfter(android.app.Notification);
+ method @RequiresApi(19) public static boolean getUsesChronometer(android.app.Notification);
+ method public static int getVisibility(android.app.Notification);
+ method public static boolean isGroupSummary(android.app.Notification);
+ method public static android.graphics.Bitmap? reduceLargeIconSize(android.content.Context, android.graphics.Bitmap?);
+ field public static final int BADGE_ICON_LARGE = 2; // 0x2
+ field public static final int BADGE_ICON_NONE = 0; // 0x0
+ field public static final int BADGE_ICON_SMALL = 1; // 0x1
+ field public static final String CATEGORY_ALARM = "alarm";
+ field public static final String CATEGORY_CALL = "call";
+ field public static final String CATEGORY_EMAIL = "email";
+ field public static final String CATEGORY_ERROR = "err";
+ field public static final String CATEGORY_EVENT = "event";
+ field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
+ field public static final String CATEGORY_MESSAGE = "msg";
+ field public static final String CATEGORY_MISSED_CALL = "missed_call";
+ field public static final String CATEGORY_NAVIGATION = "navigation";
+ field public static final String CATEGORY_PROGRESS = "progress";
+ field public static final String CATEGORY_PROMO = "promo";
+ field public static final String CATEGORY_RECOMMENDATION = "recommendation";
+ field public static final String CATEGORY_REMINDER = "reminder";
+ field public static final String CATEGORY_SERVICE = "service";
+ field public static final String CATEGORY_SOCIAL = "social";
+ field public static final String CATEGORY_STATUS = "status";
+ field public static final String CATEGORY_STOPWATCH = "stopwatch";
+ field public static final String CATEGORY_SYSTEM = "sys";
+ field public static final String CATEGORY_TRANSPORT = "transport";
+ field public static final String CATEGORY_WORKOUT = "workout";
+ field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
+ field public static final int DEFAULT_ALL = -1; // 0xffffffff
+ field public static final int DEFAULT_LIGHTS = 4; // 0x4
+ field public static final int DEFAULT_SOUND = 1; // 0x1
+ field public static final int DEFAULT_VIBRATE = 2; // 0x2
+ field public static final String EXTRA_ANSWER_COLOR = "android.answerColor";
+ field public static final String EXTRA_ANSWER_INTENT = "android.answerIntent";
+ field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+ field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+ field public static final String EXTRA_BIG_TEXT = "android.bigText";
+ field public static final String EXTRA_CALL_IS_VIDEO = "android.callIsVideo";
+ field public static final String EXTRA_CALL_PERSON = "android.callPerson";
+ field public static final String EXTRA_CALL_PERSON_COMPAT = "android.callPersonCompat";
+ field public static final String EXTRA_CALL_TYPE = "android.callType";
+ field public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
+ field public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
+ field public static final String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+ field public static final String EXTRA_COLORIZED = "android.colorized";
+ field public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+ field public static final String EXTRA_COMPAT_TEMPLATE = "androidx.core.app.extra.COMPAT_TEMPLATE";
+ field public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+ field public static final String EXTRA_DECLINE_COLOR = "android.declineColor";
+ field public static final String EXTRA_DECLINE_INTENT = "android.declineIntent";
+ field public static final String EXTRA_HANG_UP_INTENT = "android.hangUpIntent";
+ field public static final String EXTRA_HIDDEN_CONVERSATION_TITLE = "android.hiddenConversationTitle";
+ field public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
+ field public static final String EXTRA_INFO_TEXT = "android.infoText";
+ field public static final String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
+ field public static final String EXTRA_LARGE_ICON = "android.largeIcon";
+ field public static final String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+ field public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
+ field public static final String EXTRA_MESSAGES = "android.messages";
+ field public static final String EXTRA_MESSAGING_STYLE_USER = "android.messagingStyleUser";
+ field public static final String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
+ field public static final String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
+ field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
+ field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
+ field public static final String EXTRA_PICTURE = "android.picture";
+ field public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION = "android.pictureContentDescription";
+ field public static final String EXTRA_PICTURE_ICON = "android.pictureIcon";
+ field public static final String EXTRA_PROGRESS = "android.progress";
+ field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+ field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+ field public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+ field public static final String EXTRA_SHOW_BIG_PICTURE_WHEN_COLLAPSED = "android.showBigPictureWhenCollapsed";
+ field public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+ field public static final String EXTRA_SHOW_WHEN = "android.showWhen";
+ field public static final String EXTRA_SMALL_ICON = "android.icon";
+ field public static final String EXTRA_SUB_TEXT = "android.subText";
+ field public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
+ field public static final String EXTRA_TEMPLATE = "android.template";
+ field public static final String EXTRA_TEXT = "android.text";
+ field public static final String EXTRA_TEXT_LINES = "android.textLines";
+ field public static final String EXTRA_TITLE = "android.title";
+ field public static final String EXTRA_TITLE_BIG = "android.title.big";
+ field public static final String EXTRA_VERIFICATION_ICON = "android.verificationIcon";
+ field public static final String EXTRA_VERIFICATION_ICON_COMPAT = "android.verificationIconCompat";
+ field public static final String EXTRA_VERIFICATION_TEXT = "android.verificationText";
+ field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+ field public static final int FLAG_BUBBLE = 4096; // 0x1000
+ field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+ field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+ field @Deprecated public static final int FLAG_HIGH_PRIORITY = 128; // 0x80
+ field public static final int FLAG_INSISTENT = 4; // 0x4
+ field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+ field public static final int FLAG_NO_CLEAR = 32; // 0x20
+ field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+ field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+ field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int FOREGROUND_SERVICE_DEFAULT = 0; // 0x0
+ field public static final int FOREGROUND_SERVICE_DEFERRED = 2; // 0x2
+ field public static final int FOREGROUND_SERVICE_IMMEDIATE = 1; // 0x1
+ field public static final int GROUP_ALERT_ALL = 0; // 0x0
+ field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
+ field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+ field public static final String GROUP_KEY_SILENT = "silent";
+ field public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
+ field public static final int PRIORITY_DEFAULT = 0; // 0x0
+ field public static final int PRIORITY_HIGH = 1; // 0x1
+ field public static final int PRIORITY_LOW = -1; // 0xffffffff
+ field public static final int PRIORITY_MAX = 2; // 0x2
+ field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+ field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+ field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+ field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+ field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+ }
+
+ public static class NotificationCompat.Action {
+ ctor public NotificationCompat.Action(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action(int, CharSequence?, android.app.PendingIntent?);
+ method public android.app.PendingIntent? getActionIntent();
+ method public boolean getAllowGeneratedReplies();
+ method public androidx.core.app.RemoteInput![]? getDataOnlyRemoteInputs();
+ method public android.os.Bundle getExtras();
+ method @Deprecated public int getIcon();
+ method public androidx.core.graphics.drawable.IconCompat? getIconCompat();
+ method public androidx.core.app.RemoteInput![]? getRemoteInputs();
+ method @androidx.core.app.NotificationCompat.Action.SemanticAction public int getSemanticAction();
+ method public boolean getShowsUserInterface();
+ method public CharSequence? getTitle();
+ method public boolean isAuthenticationRequired();
+ method public boolean isContextual();
+ field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5
+ field public static final int SEMANTIC_ACTION_CALL = 10; // 0xa
+ field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4
+ field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2
+ field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3
+ field public static final int SEMANTIC_ACTION_MUTE = 6; // 0x6
+ field public static final int SEMANTIC_ACTION_NONE = 0; // 0x0
+ field public static final int SEMANTIC_ACTION_REPLY = 1; // 0x1
+ field public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; // 0x9
+ field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8
+ field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7
+ field public android.app.PendingIntent? actionIntent;
+ field @Deprecated public int icon;
+ field public CharSequence! title;
+ }
+
+ public static final class NotificationCompat.Action.Builder {
+ ctor public NotificationCompat.Action.Builder(androidx.core.app.NotificationCompat.Action);
+ ctor public NotificationCompat.Action.Builder(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action.Builder(int, CharSequence?, android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Action.Builder addRemoteInput(androidx.core.app.RemoteInput?);
+ method public androidx.core.app.NotificationCompat.Action build();
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Extender);
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.NotificationCompat.Action.Builder setAllowGeneratedReplies(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setAuthenticationRequired(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setContextual(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setSemanticAction(@androidx.core.app.NotificationCompat.Action.SemanticAction int);
+ method public androidx.core.app.NotificationCompat.Action.Builder setShowsUserInterface(boolean);
+ }
+
+ public static interface NotificationCompat.Action.Extender {
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_NONE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_REPLY, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_UNREAD, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_DELETE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_ARCHIVE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_UNMUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_UP, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_DOWN, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_CALL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.Action.SemanticAction {
+ }
+
+ public static final class NotificationCompat.Action.WearableExtender implements androidx.core.app.NotificationCompat.Action.Extender {
+ ctor public NotificationCompat.Action.WearableExtender();
+ ctor public NotificationCompat.Action.WearableExtender(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender clone();
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+ method @Deprecated public CharSequence? getCancelLabel();
+ method @Deprecated public CharSequence? getConfirmLabel();
+ method public boolean getHintDisplayActionInline();
+ method public boolean getHintLaunchesActivity();
+ method @Deprecated public CharSequence? getInProgressLabel();
+ method public boolean isAvailableOffline();
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setCancelLabel(CharSequence?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setConfirmLabel(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintDisplayActionInline(boolean);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintLaunchesActivity(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setInProgressLabel(CharSequence?);
+ }
+
+ public static class NotificationCompat.BigPictureStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigPictureStyle();
+ ctor public NotificationCompat.BigPictureStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap?);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle setBigContentTitle(CharSequence?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle setContentDescription(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle setSummaryText(CharSequence?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle showBigPictureWhenCollapsed(boolean);
+ }
+
+ public static class NotificationCompat.BigTextStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigTextStyle();
+ ctor public NotificationCompat.BigTextStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle bigText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle setBigContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle setSummaryText(CharSequence?);
+ }
+
+ public static final class NotificationCompat.BubbleMetadata {
+ method public static androidx.core.app.NotificationCompat.BubbleMetadata? fromPlatform(android.app.Notification.BubbleMetadata?);
+ method public boolean getAutoExpandBubble();
+ method public android.app.PendingIntent? getDeleteIntent();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public int getDesiredHeight();
+ method @DimenRes public int getDesiredHeightResId();
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public android.app.PendingIntent? getIntent();
+ method public String? getShortcutId();
+ method public boolean isNotificationSuppressed();
+ method public static android.app.Notification.BubbleMetadata? toPlatform(androidx.core.app.NotificationCompat.BubbleMetadata?);
+ }
+
+ public static final class NotificationCompat.BubbleMetadata.Builder {
+ ctor @Deprecated public NotificationCompat.BubbleMetadata.Builder();
+ ctor public NotificationCompat.BubbleMetadata.Builder(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat);
+ ctor @RequiresApi(30) public NotificationCompat.BubbleMetadata.Builder(String);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata build();
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setAutoExpandBubble(boolean);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeight(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIcon(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setSuppressNotification(boolean);
+ }
+
+ public static class NotificationCompat.Builder {
+ ctor @Deprecated public NotificationCompat.Builder(android.content.Context);
+ ctor @RequiresApi(19) public NotificationCompat.Builder(android.content.Context, android.app.Notification);
+ ctor public NotificationCompat.Builder(android.content.Context, String);
+ method public androidx.core.app.NotificationCompat.Builder addAction(androidx.core.app.NotificationCompat.Action?);
+ method public androidx.core.app.NotificationCompat.Builder addAction(int, CharSequence?, android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder addExtras(android.os.Bundle?);
+ method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(androidx.core.app.NotificationCompat.Action?);
+ method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(int, CharSequence?, android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder addPerson(androidx.core.app.Person?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder addPerson(String?);
+ method public android.app.Notification build();
+ method public androidx.core.app.NotificationCompat.Builder clearActions();
+ method public androidx.core.app.NotificationCompat.Builder clearInvisibleActions();
+ method public androidx.core.app.NotificationCompat.Builder clearPeople();
+ method public android.widget.RemoteViews? createBigContentView();
+ method public android.widget.RemoteViews? createContentView();
+ method public android.widget.RemoteViews? createHeadsUpContentView();
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Extender);
+ method public android.os.Bundle getExtras();
+ method @Deprecated public android.app.Notification getNotification();
+ method protected static CharSequence? limitCharSequenceLength(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setAllowSystemGeneratedContextualActions(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setAutoCancel(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setBadgeIconType(int);
+ method public androidx.core.app.NotificationCompat.Builder setBubbleMetadata(androidx.core.app.NotificationCompat.BubbleMetadata?);
+ method public androidx.core.app.NotificationCompat.Builder setCategory(String?);
+ method public androidx.core.app.NotificationCompat.Builder setChannelId(String);
+ method @RequiresApi(24) public androidx.core.app.NotificationCompat.Builder setChronometerCountDown(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setColor(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.Builder setColorized(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setContent(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setContentInfo(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder setContentText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomBigContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomHeadsUpContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setDefaults(int);
+ method public androidx.core.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Builder setForegroundServiceBehavior(int);
+ method public androidx.core.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent?, boolean);
+ method public androidx.core.app.NotificationCompat.Builder setGroup(String?);
+ method public androidx.core.app.NotificationCompat.Builder setGroupAlertBehavior(int);
+ method public androidx.core.app.NotificationCompat.Builder setGroupSummary(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap?);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.Builder setLargeIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.Builder setLights(@ColorInt int, int, int);
+ method public androidx.core.app.NotificationCompat.Builder setLocalOnly(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
+ method public androidx.core.app.NotificationCompat.Builder setNumber(int);
+ method public androidx.core.app.NotificationCompat.Builder setOngoing(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setPriority(int);
+ method public androidx.core.app.NotificationCompat.Builder setProgress(int, int, boolean);
+ method public androidx.core.app.NotificationCompat.Builder setPublicVersion(android.app.Notification?);
+ method public androidx.core.app.NotificationCompat.Builder setRemoteInputHistory(CharSequence![]?);
+ method public androidx.core.app.NotificationCompat.Builder setSettingsText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setShortcutId(String?);
+ method public androidx.core.app.NotificationCompat.Builder setShortcutInfo(androidx.core.content.pm.ShortcutInfoCompat?);
+ method public androidx.core.app.NotificationCompat.Builder setShowWhen(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setSilent(boolean);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.Builder setSmallIcon(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int);
+ method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int, int);
+ method public androidx.core.app.NotificationCompat.Builder setSortKey(String?);
+ method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?);
+ method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?, int);
+ method public androidx.core.app.NotificationCompat.Builder setStyle(androidx.core.app.NotificationCompat.Style?);
+ method public androidx.core.app.NotificationCompat.Builder setSubText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?, android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setTimeoutAfter(long);
+ method public androidx.core.app.NotificationCompat.Builder setUsesChronometer(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setVibrate(long[]?);
+ method public androidx.core.app.NotificationCompat.Builder setVisibility(int);
+ method public androidx.core.app.NotificationCompat.Builder setWhen(long);
+ field @Deprecated public java.util.ArrayList<java.lang.String!>! mPeople;
+ }
+
+ public static class NotificationCompat.CallStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.CallStyle();
+ ctor public NotificationCompat.CallStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public static androidx.core.app.NotificationCompat.CallStyle forIncomingCall(androidx.core.app.Person, android.app.PendingIntent, android.app.PendingIntent);
+ method public static androidx.core.app.NotificationCompat.CallStyle forOngoingCall(androidx.core.app.Person, android.app.PendingIntent);
+ method public static androidx.core.app.NotificationCompat.CallStyle forScreeningCall(androidx.core.app.Person, android.app.PendingIntent, android.app.PendingIntent);
+ method public androidx.core.app.NotificationCompat.CallStyle setAnswerButtonColorHint(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CallStyle setDeclineButtonColorHint(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CallStyle setIsVideo(boolean);
+ method public androidx.core.app.NotificationCompat.CallStyle setVerificationIcon(android.graphics.Bitmap?);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.CallStyle setVerificationIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.CallStyle setVerificationText(CharSequence?);
+ field public static final int CALL_TYPE_INCOMING = 1; // 0x1
+ field public static final int CALL_TYPE_ONGOING = 2; // 0x2
+ field public static final int CALL_TYPE_SCREENING = 3; // 0x3
+ field public static final int CALL_TYPE_UNKNOWN = 0; // 0x0
+ }
+
+ public static final class NotificationCompat.CarExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.CarExtender();
+ ctor public NotificationCompat.CarExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method @ColorInt public int getColor();
+ method public android.graphics.Bitmap? getLargeIcon();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation? getUnreadConversation();
+ method public androidx.core.app.NotificationCompat.CarExtender setColor(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation?);
+ }
+
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+ method @Deprecated public long getLatestTimestamp();
+ method @Deprecated public String![]? getMessages();
+ method @Deprecated public String? getParticipant();
+ method @Deprecated public String![]? getParticipants();
+ method @Deprecated public android.app.PendingIntent? getReadPendingIntent();
+ method @Deprecated public androidx.core.app.RemoteInput? getRemoteInput();
+ method @Deprecated public android.app.PendingIntent? getReplyPendingIntent();
+ }
+
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(String?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation build();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent?, androidx.core.app.RemoteInput?);
+ }
+
+ public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.DecoratedCustomViewStyle();
+ }
+
+ public static interface NotificationCompat.Extender {
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ }
+
+ public static class NotificationCompat.InboxStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.InboxStyle();
+ ctor public NotificationCompat.InboxStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.InboxStyle addLine(CharSequence?);
+ method public androidx.core.app.NotificationCompat.InboxStyle setBigContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.InboxStyle setSummaryText(CharSequence?);
+ }
+
+ public static class NotificationCompat.MessagingStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.MessagingStyle(androidx.core.app.Person);
+ ctor @Deprecated public NotificationCompat.MessagingStyle(CharSequence);
+ method public void addCompatExtras(android.os.Bundle);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addHistoricMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, androidx.core.app.Person?);
+ method @Deprecated public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, CharSequence?);
+ method public static androidx.core.app.NotificationCompat.MessagingStyle? extractMessagingStyleFromNotification(android.app.Notification);
+ method public CharSequence? getConversationTitle();
+ method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getHistoricMessages();
+ method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getMessages();
+ method public androidx.core.app.Person getUser();
+ method @Deprecated public CharSequence? getUserDisplayName();
+ method public boolean isGroupConversation();
+ method public androidx.core.app.NotificationCompat.MessagingStyle setConversationTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle setGroupConversation(boolean);
+ field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
+ }
+
+ public static final class NotificationCompat.MessagingStyle.Message {
+ ctor public NotificationCompat.MessagingStyle.Message(CharSequence?, long, androidx.core.app.Person?);
+ ctor @Deprecated public NotificationCompat.MessagingStyle.Message(CharSequence?, long, CharSequence?);
+ method public String? getDataMimeType();
+ method public android.net.Uri? getDataUri();
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.Person? getPerson();
+ method @Deprecated public CharSequence? getSender();
+ method public CharSequence? getText();
+ method public long getTimestamp();
+ method public androidx.core.app.NotificationCompat.MessagingStyle.Message setData(String?, android.net.Uri?);
+ }
+
+ public abstract static class NotificationCompat.Style {
+ ctor public NotificationCompat.Style();
+ method public android.app.Notification? build();
+ method public void setBuilder(androidx.core.app.NotificationCompat.Builder?);
+ }
+
+ public static final class NotificationCompat.TvExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.TvExtender();
+ ctor public NotificationCompat.TvExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method public String? getChannelId();
+ method public android.app.PendingIntent? getContentIntent();
+ method public android.app.PendingIntent? getDeleteIntent();
+ method public boolean isAvailableOnTv();
+ method public boolean isSuppressShowOverApps();
+ method public androidx.core.app.NotificationCompat.TvExtender setChannelId(String?);
+ method public androidx.core.app.NotificationCompat.TvExtender setContentIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.TvExtender setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.TvExtender setSuppressShowOverApps(boolean);
+ }
+
+ public static final class NotificationCompat.WearableExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.WearableExtender();
+ ctor public NotificationCompat.WearableExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.WearableExtender addAction(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.WearableExtender addActions(java.util.List<androidx.core.app.NotificationCompat.Action!>);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification!>);
+ method public androidx.core.app.NotificationCompat.WearableExtender clearActions();
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender clearPages();
+ method public androidx.core.app.NotificationCompat.WearableExtender clone();
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method public java.util.List<androidx.core.app.NotificationCompat.Action!> getActions();
+ method @Deprecated public android.graphics.Bitmap? getBackground();
+ method public String? getBridgeTag();
+ method public int getContentAction();
+ method @Deprecated public int getContentIcon();
+ method @Deprecated public int getContentIconGravity();
+ method public boolean getContentIntentAvailableOffline();
+ method @Deprecated public int getCustomContentHeight();
+ method @Deprecated public int getCustomSizePreset();
+ method public String? getDismissalId();
+ method @Deprecated public android.app.PendingIntent? getDisplayIntent();
+ method @Deprecated public int getGravity();
+ method @Deprecated public boolean getHintAmbientBigPicture();
+ method @Deprecated public boolean getHintAvoidBackgroundClipping();
+ method public boolean getHintContentIntentLaunchesActivity();
+ method @Deprecated public boolean getHintHideIcon();
+ method @Deprecated public int getHintScreenTimeout();
+ method @Deprecated public boolean getHintShowBackgroundOnly();
+ method @Deprecated public java.util.List<android.app.Notification!> getPages();
+ method public boolean getStartScrollBottom();
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap?);
+ method public androidx.core.app.NotificationCompat.WearableExtender setBridgeTag(String?);
+ method public androidx.core.app.NotificationCompat.WearableExtender setContentAction(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIcon(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+ method public androidx.core.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+ method public androidx.core.app.NotificationCompat.WearableExtender setDismissalId(String?);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent?);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setGravity(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAmbientBigPicture(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+ method public androidx.core.app.NotificationCompat.WearableExtender setHintContentIntentLaunchesActivity(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+ method public androidx.core.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+ field @Deprecated public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+ field @Deprecated public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+ field @Deprecated public static final int SIZE_DEFAULT = 0; // 0x0
+ field @Deprecated public static final int SIZE_FULL_SCREEN = 5; // 0x5
+ field @Deprecated public static final int SIZE_LARGE = 4; // 0x4
+ field @Deprecated public static final int SIZE_MEDIUM = 3; // 0x3
+ field @Deprecated public static final int SIZE_SMALL = 2; // 0x2
+ field @Deprecated public static final int SIZE_XSMALL = 1; // 0x1
+ field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+ }
+
+ public final class NotificationCompatExtras {
+ field public static final String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+ field public static final String EXTRA_GROUP_KEY = "android.support.groupKey";
+ field public static final String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+ field public static final String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+ field public static final String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+ field public static final String EXTRA_SORT_KEY = "android.support.sortKey";
+ }
+
+ public abstract class NotificationCompatSideChannelService extends android.app.Service {
+ ctor public NotificationCompatSideChannelService();
+ method public abstract void cancel(String!, int, String!);
+ method public abstract void cancelAll(String!);
+ method public abstract void notify(String!, int, String!, android.app.Notification!);
+ method public android.os.IBinder! onBind(android.content.Intent!);
+ }
+
+ public final class NotificationManagerCompat {
+ method public boolean areNotificationsEnabled();
+ method public void cancel(int);
+ method public void cancel(String?, int);
+ method public void cancelAll();
+ method public void createNotificationChannel(android.app.NotificationChannel);
+ method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+ method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
+ method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+ method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup!>);
+ method public void createNotificationChannelGroupsCompat(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+ method public void createNotificationChannels(java.util.List<android.app.NotificationChannel!>);
+ method public void createNotificationChannelsCompat(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.core.app.NotificationManagerCompat from(android.content.Context);
+ method public java.util.List<android.service.notification.StatusBarNotification!> getActiveNotifications();
+ method public int getCurrentInterruptionFilter();
+ method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+ method public int getImportance();
+ method public android.app.NotificationChannel? getNotificationChannel(String);
+ method public android.app.NotificationChannel? getNotificationChannel(String, String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String, String);
+ method public android.app.NotificationChannelGroup? getNotificationChannelGroup(String);
+ method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroupCompat(String);
+ method public java.util.List<android.app.NotificationChannelGroup!> getNotificationChannelGroups();
+ method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroupsCompat();
+ method public java.util.List<android.app.NotificationChannel!> getNotificationChannels();
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannelsCompat();
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(int, android.app.Notification);
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(String?, int, android.app.Notification);
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(java.util.List<androidx.core.app.NotificationManagerCompat.NotificationWithIdAndTag!>);
+ field public static final String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+ field public static final String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+ field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+ field public static final int IMPORTANCE_HIGH = 4; // 0x4
+ field public static final int IMPORTANCE_LOW = 2; // 0x2
+ field public static final int IMPORTANCE_MAX = 5; // 0x5
+ field public static final int IMPORTANCE_MIN = 1; // 0x1
+ field public static final int IMPORTANCE_NONE = 0; // 0x0
+ field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
+ field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
+ field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
+ field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
+ field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
+ field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
+ }
+
+ public static class NotificationManagerCompat.NotificationWithIdAndTag {
+ ctor public NotificationManagerCompat.NotificationWithIdAndTag(int, android.app.Notification);
+ ctor public NotificationManagerCompat.NotificationWithIdAndTag(String?, int, android.app.Notification);
+ }
+
+ public interface OnMultiWindowModeChangedProvider {
+ method public void addOnMultiWindowModeChangedListener(androidx.core.util.Consumer<androidx.core.app.MultiWindowModeChangedInfo!>);
+ method public void removeOnMultiWindowModeChangedListener(androidx.core.util.Consumer<androidx.core.app.MultiWindowModeChangedInfo!>);
+ }
+
+ public interface OnNewIntentProvider {
+ method public void addOnNewIntentListener(androidx.core.util.Consumer<android.content.Intent!>);
+ method public void removeOnNewIntentListener(androidx.core.util.Consumer<android.content.Intent!>);
+ }
+
+ public interface OnPictureInPictureModeChangedProvider {
+ method public void addOnPictureInPictureModeChangedListener(androidx.core.util.Consumer<androidx.core.app.PictureInPictureModeChangedInfo!>);
+ method public void removeOnPictureInPictureModeChangedListener(androidx.core.util.Consumer<androidx.core.app.PictureInPictureModeChangedInfo!>);
+ }
+
+ public final class PendingIntentCompat {
+ method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent![], int, android.os.Bundle, boolean);
+ method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent![], int, boolean);
+ method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, android.os.Bundle, boolean);
+ method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, boolean);
+ method public static android.app.PendingIntent? getBroadcast(android.content.Context, int, android.content.Intent, int, boolean);
+ method @RequiresApi(26) public static android.app.PendingIntent getForegroundService(android.content.Context, int, android.content.Intent, int, boolean);
+ method public static android.app.PendingIntent getService(android.content.Context, int, android.content.Intent, int, boolean);
+ }
+
+ public class Person {
+ method public static androidx.core.app.Person fromBundle(android.os.Bundle);
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public String? getKey();
+ method public CharSequence? getName();
+ method public String? getUri();
+ method public boolean isBot();
+ method public boolean isImportant();
+ method public androidx.core.app.Person.Builder toBuilder();
+ method public android.os.Bundle toBundle();
+ }
+
+ public static class Person.Builder {
+ ctor public Person.Builder();
+ method public androidx.core.app.Person build();
+ method public androidx.core.app.Person.Builder setBot(boolean);
+ method public androidx.core.app.Person.Builder setIcon(androidx.core.graphics.drawable.IconCompat?);
+ method public androidx.core.app.Person.Builder setImportant(boolean);
+ method public androidx.core.app.Person.Builder setKey(String?);
+ method public androidx.core.app.Person.Builder setName(CharSequence?);
+ method public androidx.core.app.Person.Builder setUri(String?);
+ }
+
+ public final class PictureInPictureModeChangedInfo {
+ ctor public PictureInPictureModeChangedInfo(boolean);
+ ctor @RequiresApi(26) public PictureInPictureModeChangedInfo(boolean, android.content.res.Configuration);
+ method @RequiresApi(26) public android.content.res.Configuration getNewConfig();
+ method public boolean isInPictureInPictureMode();
+ }
+
+ public final class RemoteActionCompat implements androidx.versionedparcelable.VersionedParcelable {
+ ctor public RemoteActionCompat(androidx.core.app.RemoteActionCompat);
+ ctor public RemoteActionCompat(androidx.core.graphics.drawable.IconCompat, CharSequence, CharSequence, android.app.PendingIntent);
+ method @RequiresApi(26) public static androidx.core.app.RemoteActionCompat createFromRemoteAction(android.app.RemoteAction);
+ method public android.app.PendingIntent getActionIntent();
+ method public CharSequence getContentDescription();
+ method public androidx.core.graphics.drawable.IconCompat getIcon();
+ method public CharSequence getTitle();
+ method public boolean isEnabled();
+ method public void setEnabled(boolean);
+ method public void setShouldShowIcon(boolean);
+ method public boolean shouldShowIcon();
+ method @RequiresApi(26) public android.app.RemoteAction toRemoteAction();
+ }
+
+ public final class RemoteInput {
+ method public static void addDataResultToIntent(androidx.core.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String!,android.net.Uri!>);
+ method public static void addResultsToIntent(androidx.core.app.RemoteInput![], android.content.Intent, android.os.Bundle);
+ method public boolean getAllowFreeFormInput();
+ method public java.util.Set<java.lang.String!>? getAllowedDataTypes();
+ method public CharSequence![]? getChoices();
+ method public static java.util.Map<java.lang.String!,android.net.Uri!>? getDataResultsFromIntent(android.content.Intent, String);
+ method public int getEditChoicesBeforeSending();
+ method public android.os.Bundle getExtras();
+ method public CharSequence? getLabel();
+ method public String getResultKey();
+ method public static android.os.Bundle? getResultsFromIntent(android.content.Intent);
+ method public static int getResultsSource(android.content.Intent);
+ method public boolean isDataOnly();
+ method public static void setResultsSource(android.content.Intent, int);
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; // 0x0
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; // 0x1
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; // 0x2
+ field public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+ field public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+ field public static final int SOURCE_CHOICE = 1; // 0x1
+ field public static final int SOURCE_FREE_FORM_INPUT = 0; // 0x0
+ }
+
+ public static final class RemoteInput.Builder {
+ ctor public RemoteInput.Builder(String);
+ method public androidx.core.app.RemoteInput.Builder addExtras(android.os.Bundle);
+ method public androidx.core.app.RemoteInput build();
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.RemoteInput.Builder setAllowDataType(String, boolean);
+ method public androidx.core.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+ method public androidx.core.app.RemoteInput.Builder setChoices(CharSequence![]?);
+ method public androidx.core.app.RemoteInput.Builder setEditChoicesBeforeSending(int);
+ method public androidx.core.app.RemoteInput.Builder setLabel(CharSequence?);
+ }
+
+ public final class ServiceCompat {
+ method public static void stopForeground(android.app.Service, int);
+ field public static final int START_STICKY = 1; // 0x1
+ field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+ field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
+ }
+
+ public final class ShareCompat {
+ method @Deprecated public static void configureMenuItem(android.view.Menu, @IdRes int, androidx.core.app.ShareCompat.IntentBuilder);
+ method @Deprecated public static void configureMenuItem(android.view.MenuItem, androidx.core.app.ShareCompat.IntentBuilder);
+ method public static android.content.ComponentName? getCallingActivity(android.app.Activity);
+ method public static String? getCallingPackage(android.app.Activity);
+ field public static final String EXTRA_CALLING_ACTIVITY = "androidx.core.app.EXTRA_CALLING_ACTIVITY";
+ field public static final String EXTRA_CALLING_ACTIVITY_INTEROP = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+ field public static final String EXTRA_CALLING_PACKAGE = "androidx.core.app.EXTRA_CALLING_PACKAGE";
+ field public static final String EXTRA_CALLING_PACKAGE_INTEROP = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+ }
+
+ public static class ShareCompat.IntentBuilder {
+ ctor public ShareCompat.IntentBuilder(android.content.Context);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+ method public android.content.Intent createChooserIntent();
+ method @Deprecated public static androidx.core.app.ShareCompat.IntentBuilder from(android.app.Activity);
+ method public android.content.Intent getIntent();
+ method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(@StringRes int);
+ method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(CharSequence?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailBcc(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailCc(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailTo(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setHtmlText(String?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setStream(android.net.Uri?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setSubject(String?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setText(CharSequence?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setType(String?);
+ method public void startChooser();
+ }
+
+ public static class ShareCompat.IntentReader {
+ ctor public ShareCompat.IntentReader(android.app.Activity);
+ ctor public ShareCompat.IntentReader(android.content.Context, android.content.Intent);
+ method @Deprecated public static androidx.core.app.ShareCompat.IntentReader from(android.app.Activity);
+ method public android.content.ComponentName? getCallingActivity();
+ method public android.graphics.drawable.Drawable? getCallingActivityIcon();
+ method public android.graphics.drawable.Drawable? getCallingApplicationIcon();
+ method public CharSequence? getCallingApplicationLabel();
+ method public String? getCallingPackage();
+ method public String![]? getEmailBcc();
+ method public String![]? getEmailCc();
+ method public String![]? getEmailTo();
+ method public String? getHtmlText();
+ method public android.net.Uri? getStream();
+ method public android.net.Uri? getStream(int);
+ method public int getStreamCount();
+ method public String? getSubject();
+ method public CharSequence? getText();
+ method public String? getType();
+ method public boolean isMultipleShare();
+ method public boolean isShareIntent();
+ method public boolean isSingleShare();
+ }
+
+ public abstract class SharedElementCallback {
+ ctor public SharedElementCallback();
+ method public android.os.Parcelable! onCaptureSharedElementSnapshot(android.view.View!, android.graphics.Matrix!, android.graphics.RectF!);
+ method public android.view.View! onCreateSnapshotView(android.content.Context!, android.os.Parcelable!);
+ method public void onMapSharedElements(java.util.List<java.lang.String!>!, java.util.Map<java.lang.String!,android.view.View!>!);
+ method public void onRejectSharedElements(java.util.List<android.view.View!>!);
+ method public void onSharedElementEnd(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+ method public void onSharedElementStart(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+ method public void onSharedElementsArrived(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, androidx.core.app.SharedElementCallback.OnSharedElementsReadyListener!);
+ }
+
+ public static interface SharedElementCallback.OnSharedElementsReadyListener {
+ method public void onSharedElementsReady();
+ }
+
+ public final class TaskStackBuilder implements java.lang.Iterable<android.content.Intent> {
+ method public androidx.core.app.TaskStackBuilder addNextIntent(android.content.Intent);
+ method public androidx.core.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+ method public androidx.core.app.TaskStackBuilder addParentStack(android.app.Activity);
+ method public androidx.core.app.TaskStackBuilder addParentStack(android.content.ComponentName);
+ method public androidx.core.app.TaskStackBuilder addParentStack(Class<?>);
+ method public static androidx.core.app.TaskStackBuilder create(android.content.Context);
+ method public android.content.Intent? editIntentAt(int);
+ method @Deprecated public static androidx.core.app.TaskStackBuilder! from(android.content.Context!);
+ method @Deprecated public android.content.Intent! getIntent(int);
+ method public int getIntentCount();
+ method public android.content.Intent![] getIntents();
+ method public android.app.PendingIntent? getPendingIntent(int, int);
+ method public android.app.PendingIntent? getPendingIntent(int, int, android.os.Bundle?);
+ method @Deprecated public java.util.Iterator<android.content.Intent!> iterator();
+ method public void startActivities();
+ method public void startActivities(android.os.Bundle?);
+ }
+
+ public static interface TaskStackBuilder.SupportParentable {
+ method public android.content.Intent? getSupportParentActivityIntent();
+ }
+
+}
+
+package androidx.core.content {
+
+ public final class ContentProviderCompat {
+ method public static android.content.Context requireContext(android.content.ContentProvider);
+ }
+
+ public final class ContentResolverCompat {
+ method public static android.database.Cursor? query(android.content.ContentResolver, android.net.Uri, String![]?, String?, String![]?, String?, androidx.core.os.CancellationSignal?);
+ }
+
+ public class ContextCompat {
+ ctor protected ContextCompat();
+ method public static int checkSelfPermission(android.content.Context, String);
+ method public static android.content.Context? createDeviceProtectedStorageContext(android.content.Context);
+ method public static String? getAttributionTag(android.content.Context);
+ method public static java.io.File getCodeCacheDir(android.content.Context);
+ method @ColorInt public static int getColor(android.content.Context, @ColorRes int);
+ method public static android.content.res.ColorStateList? getColorStateList(android.content.Context, @ColorRes int);
+ method public static android.content.Context getContextForLanguage(android.content.Context);
+ method public static java.io.File? getDataDir(android.content.Context);
+ method public static android.view.Display getDisplayOrDefault(@DisplayContext android.content.Context);
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
+ method public static java.io.File![] getExternalCacheDirs(android.content.Context);
+ method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
+ method public static java.util.concurrent.Executor getMainExecutor(android.content.Context);
+ method public static java.io.File? getNoBackupFilesDir(android.content.Context);
+ method public static java.io.File![] getObbDirs(android.content.Context);
+ method public static String getString(android.content.Context, int);
+ method public static <T> T? getSystemService(android.content.Context, Class<T!>);
+ method public static String? getSystemServiceName(android.content.Context, Class<?>);
+ method public static boolean isDeviceProtectedStorage(android.content.Context);
+ method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, int);
+ method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, String?, android.os.Handler?, int);
+ method public static boolean startActivities(android.content.Context, android.content.Intent![]);
+ method public static boolean startActivities(android.content.Context, android.content.Intent![], android.os.Bundle?);
+ method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
+ method public static void startForegroundService(android.content.Context, android.content.Intent);
+ field public static final int RECEIVER_EXPORTED = 2; // 0x2
+ field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
+ field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
+ }
+
+ public class FileProvider extends android.content.ContentProvider {
+ ctor public FileProvider();
+ ctor protected FileProvider(@XmlRes int);
+ method public int delete(android.net.Uri, String?, String![]?);
+ method public String? getType(android.net.Uri);
+ method public String? getTypeAnonymous(android.net.Uri);
+ method public static android.net.Uri! getUriForFile(android.content.Context, String, java.io.File);
+ method public static android.net.Uri getUriForFile(android.content.Context, String, java.io.File, String);
+ method public android.net.Uri! insert(android.net.Uri, android.content.ContentValues);
+ method public boolean onCreate();
+ method public android.database.Cursor query(android.net.Uri, String![]?, String?, String![]?, String?);
+ method public int update(android.net.Uri, android.content.ContentValues, String?, String![]?);
+ }
+
+ public final class IntentCompat {
+ method public static android.content.Intent createManageUnusedAppRestrictionsIntent(android.content.Context, String);
+ method public static android.os.Parcelable![]? getParcelableArrayExtra(android.content.Intent, String?, Class<? extends android.os.Parcelable>);
+ method public static <T> java.util.ArrayList<T!>? getParcelableArrayListExtra(android.content.Intent, String?, Class<? extends T>);
+ method public static <T> T? getParcelableExtra(android.content.Intent, String?, Class<T!>);
+ method public static android.content.Intent makeMainSelectorActivity(String, String);
+ field public static final String ACTION_CREATE_REMINDER = "android.intent.action.CREATE_REMINDER";
+ field public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+ field public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+ field public static final String EXTRA_START_PLAYBACK = "android.intent.extra.START_PLAYBACK";
+ field public static final String EXTRA_TIME = "android.intent.extra.TIME";
+ }
+
+ public class IntentSanitizer {
+ method public android.content.Intent sanitize(android.content.Intent, androidx.core.util.Consumer<java.lang.String!>);
+ method public android.content.Intent sanitizeByFiltering(android.content.Intent);
+ method public android.content.Intent sanitizeByThrowing(android.content.Intent);
+ }
+
+ public static final class IntentSanitizer.Builder {
+ ctor public IntentSanitizer.Builder();
+ method public androidx.core.content.IntentSanitizer.Builder allowAction(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowAction(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowAnyComponent();
+ method public androidx.core.content.IntentSanitizer.Builder allowCategory(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowCategory(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipData(androidx.core.util.Predicate<android.content.ClipData!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataText();
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataUri(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataUriWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponent(android.content.ComponentName);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponent(androidx.core.util.Predicate<android.content.ComponentName!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponentWithPackage(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowData(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowDataWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtra(String, androidx.core.util.Predicate<java.lang.Object!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtra(String, Class<?>);
+ method public <T> androidx.core.content.IntentSanitizer.Builder allowExtra(String, Class<T!>, androidx.core.util.Predicate<T!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraOutput(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraOutput(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraStream(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraStreamUriWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowFlags(int);
+ method public androidx.core.content.IntentSanitizer.Builder allowHistoryStackFlags();
+ method public androidx.core.content.IntentSanitizer.Builder allowIdentifier();
+ method public androidx.core.content.IntentSanitizer.Builder allowPackage(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowPackage(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowReceiverFlags();
+ method public androidx.core.content.IntentSanitizer.Builder allowSelector();
+ method public androidx.core.content.IntentSanitizer.Builder allowSourceBounds();
+ method public androidx.core.content.IntentSanitizer.Builder allowType(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowType(String);
+ method public androidx.core.content.IntentSanitizer build();
+ }
+
+ public final class LocusIdCompat {
+ ctor public LocusIdCompat(String);
+ method public String getId();
+ method @RequiresApi(29) public android.content.LocusId toLocusId();
+ method @RequiresApi(29) public static androidx.core.content.LocusIdCompat toLocusIdCompat(android.content.LocusId);
+ }
+
+ public final class MimeTypeFilter {
+ method public static boolean matches(String?, String);
+ method public static String? matches(String?, String![]);
+ method public static String? matches(String![]?, String);
+ method public static String![] matchesMany(String![]?, String);
+ }
+
+ public interface OnConfigurationChangedProvider {
+ method public void addOnConfigurationChangedListener(androidx.core.util.Consumer<android.content.res.Configuration!>);
+ method public void removeOnConfigurationChangedListener(androidx.core.util.Consumer<android.content.res.Configuration!>);
+ }
+
+ public interface OnTrimMemoryProvider {
+ method public void addOnTrimMemoryListener(androidx.core.util.Consumer<java.lang.Integer!>);
+ method public void removeOnTrimMemoryListener(androidx.core.util.Consumer<java.lang.Integer!>);
+ }
+
+ public final class PackageManagerCompat {
+ method public static com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> getUnusedAppRestrictionsStatus(android.content.Context);
+ field public static final String ACTION_PERMISSION_REVOCATION_SETTINGS = "android.intent.action.AUTO_REVOKE_PERMISSIONS";
+ }
+
+ public final class PermissionChecker {
+ method public static int checkCallingOrSelfPermission(android.content.Context, String);
+ method public static int checkCallingPermission(android.content.Context, String, String?);
+ method public static int checkPermission(android.content.Context, String, int, int, String?);
+ method public static int checkSelfPermission(android.content.Context, String);
+ field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+ field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+ field public static final int PERMISSION_GRANTED = 0; // 0x0
+ }
+
+ @Deprecated public final class SharedPreferencesCompat {
+ }
+
+ @Deprecated public static final class SharedPreferencesCompat.EditorCompat {
+ method @Deprecated public void apply(android.content.SharedPreferences.Editor);
+ method @Deprecated public static androidx.core.content.SharedPreferencesCompat.EditorCompat! getInstance();
+ }
+
+ public class UnusedAppRestrictionsBackportCallback {
+ method public void onResult(boolean, boolean) throws android.os.RemoteException;
+ }
+
+ public abstract class UnusedAppRestrictionsBackportService extends android.app.Service {
+ ctor public UnusedAppRestrictionsBackportService();
+ method protected abstract void isPermissionRevocationEnabled(androidx.core.content.UnusedAppRestrictionsBackportCallback);
+ method public android.os.IBinder? onBind(android.content.Intent?);
+ field public static final String ACTION_UNUSED_APP_RESTRICTIONS_BACKPORT_CONNECTION = "android.support.unusedapprestrictions.action.CustomUnusedAppRestrictionsBackportService";
+ }
+
+ public final class UnusedAppRestrictionsConstants {
+ field public static final int API_30 = 4; // 0x4
+ field public static final int API_30_BACKPORT = 3; // 0x3
+ field public static final int API_31 = 5; // 0x5
+ field public static final int DISABLED = 2; // 0x2
+ field public static final int ERROR = 0; // 0x0
+ field public static final int FEATURE_NOT_AVAILABLE = 1; // 0x1
+ }
+
+ public class UriMatcherCompat {
+ method public static androidx.core.util.Predicate<android.net.Uri!> asPredicate(android.content.UriMatcher);
+ }
+
+}
+
+package androidx.core.content.pm {
+
+ @Deprecated public final class ActivityInfoCompat {
+ field @Deprecated public static final int CONFIG_UI_MODE = 512; // 0x200
+ }
+
+ public final class PackageInfoCompat {
+ method public static long getLongVersionCode(android.content.pm.PackageInfo);
+ method public static java.util.List<android.content.pm.Signature!> getSignatures(android.content.pm.PackageManager, String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static boolean hasSignatures(android.content.pm.PackageManager, String, @Size(min=1) java.util.Map<byte[]!,java.lang.Integer!>, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
+ }
+
+ public final class PermissionInfoCompat {
+ method public static int getProtection(android.content.pm.PermissionInfo);
+ method public static int getProtectionFlags(android.content.pm.PermissionInfo);
+ }
+
+ public class ShortcutInfoCompat {
+ method public android.content.ComponentName? getActivity();
+ method public java.util.Set<java.lang.String!>? getCategories();
+ method public CharSequence? getDisabledMessage();
+ method public int getDisabledReason();
+ method public int getExcludedFromSurfaces();
+ method public android.os.PersistableBundle? getExtras();
+ method public String getId();
+ method public android.content.Intent getIntent();
+ method public android.content.Intent![] getIntents();
+ method public long getLastChangedTimestamp();
+ method public androidx.core.content.LocusIdCompat? getLocusId();
+ method public CharSequence? getLongLabel();
+ method public String getPackage();
+ method public int getRank();
+ method public CharSequence getShortLabel();
+ method public android.os.UserHandle? getUserHandle();
+ method public boolean hasKeyFieldsOnly();
+ method public boolean isCached();
+ method public boolean isDeclaredInManifest();
+ method public boolean isDynamic();
+ method public boolean isEnabled();
+ method public boolean isExcludedFromSurfaces(int);
+ method public boolean isImmutable();
+ method public boolean isPinned();
+ method @RequiresApi(25) public android.content.pm.ShortcutInfo! toShortcutInfo();
+ field public static final int SURFACE_LAUNCHER = 1; // 0x1
+ }
+
+ public static class ShortcutInfoCompat.Builder {
+ ctor public ShortcutInfoCompat.Builder(android.content.Context, String);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder addCapabilityBinding(String);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder addCapabilityBinding(String, String, java.util.List<java.lang.String!>);
+ method public androidx.core.content.pm.ShortcutInfoCompat build();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setActivity(android.content.ComponentName);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setAlwaysBadged();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setCategories(java.util.Set<java.lang.String!>);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setDisabledMessage(CharSequence);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExcludedFromSurfaces(int);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExtras(android.os.PersistableBundle);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIcon(androidx.core.graphics.drawable.IconCompat!);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntent(android.content.Intent);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntents(android.content.Intent![]);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIsConversation();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLabel(CharSequence);
+ method @Deprecated public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived(boolean);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPerson(androidx.core.app.Person);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPersons(androidx.core.app.Person![]);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setRank(int);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setShortLabel(CharSequence);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setSliceUri(android.net.Uri);
+ }
+
+ public class ShortcutManagerCompat {
+ method public static boolean addDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static android.content.Intent createShortcutResultIntent(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+ method public static void disableShortcuts(android.content.Context, java.util.List<java.lang.String!>, CharSequence?);
+ method public static void enableShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getDynamicShortcuts(android.content.Context);
+ method public static int getIconMaxHeight(android.content.Context);
+ method public static int getIconMaxWidth(android.content.Context);
+ method public static int getMaxShortcutCountPerActivity(android.content.Context);
+ method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getShortcuts(android.content.Context, int);
+ method public static boolean isRateLimitingActive(android.content.Context);
+ method public static boolean isRequestPinShortcutSupported(android.content.Context);
+ method public static boolean pushDynamicShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+ method public static void removeAllDynamicShortcuts(android.content.Context);
+ method public static void removeDynamicShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+ method public static void removeLongLivedShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+ method public static void reportShortcutUsed(android.content.Context, String);
+ method public static boolean requestPinShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat, android.content.IntentSender?);
+ method public static boolean setDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static boolean updateShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ field public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
+ field public static final int FLAG_MATCH_CACHED = 8; // 0x8
+ field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2
+ field public static final int FLAG_MATCH_MANIFEST = 1; // 0x1
+ field public static final int FLAG_MATCH_PINNED = 4; // 0x4
+ }
+
+}
+
+package androidx.core.content.res {
+
+ public final class ConfigurationHelper {
+ method public static int getDensityDpi(android.content.res.Resources);
+ }
+
+ public final class ResourcesCompat {
+ method public static void clearCachesForTheme(android.content.res.Resources.Theme);
+ method public static android.graphics.Typeface? getCachedFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+ method @ColorInt public static int getColor(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.content.res.ColorStateList? getColorStateList(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable? getDrawableForDensity(android.content.res.Resources, @DrawableRes int, int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static float getFloat(android.content.res.Resources, @DimenRes int);
+ method public static android.graphics.Typeface? getFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+ method public static void getFont(android.content.Context, @FontRes int, androidx.core.content.res.ResourcesCompat.FontCallback, android.os.Handler?) throws android.content.res.Resources.NotFoundException;
+ field @AnyRes public static final int ID_NULL = 0; // 0x0
+ }
+
+ public abstract static class ResourcesCompat.FontCallback {
+ ctor public ResourcesCompat.FontCallback();
+ method public abstract void onFontRetrievalFailed(int);
+ method public abstract void onFontRetrieved(android.graphics.Typeface);
+ }
+
+ public static final class ResourcesCompat.ThemeCompat {
+ method public static void rebase(android.content.res.Resources.Theme);
+ }
+
+}
+
+package androidx.core.database {
+
+ public final class CursorWindowCompat {
+ method public static android.database.CursorWindow create(String?, long);
+ }
+
+ @Deprecated public final class DatabaseUtilsCompat {
+ method @Deprecated public static String![]! appendSelectionArgs(String![]!, String![]!);
+ method @Deprecated public static String! concatenateWhere(String!, String!);
+ }
+
+}
+
+package androidx.core.database.sqlite {
+
+ public final class SQLiteCursorCompat {
+ method public static void setFillWindowForwardOnly(android.database.sqlite.SQLiteCursor, boolean);
+ }
+
+}
+
+package androidx.core.graphics {
+
+ public final class BitmapCompat {
+ method public static android.graphics.Bitmap createScaledBitmap(android.graphics.Bitmap, int, int, android.graphics.Rect?, boolean);
+ method public static int getAllocationByteCount(android.graphics.Bitmap);
+ method public static boolean hasMipMap(android.graphics.Bitmap);
+ method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+ }
+
+ public class BlendModeColorFilterCompat {
+ method public static android.graphics.ColorFilter? createBlendModeColorFilterCompat(int, androidx.core.graphics.BlendModeCompat);
+ }
+
+ public enum BlendModeCompat {
+ enum_constant public static final androidx.core.graphics.BlendModeCompat CLEAR;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_BURN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_DODGE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DARKEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat DIFFERENCE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_ATOP;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_IN;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OUT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OVER;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat EXCLUSION;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HARD_LIGHT;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HUE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat LIGHTEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat LUMINOSITY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat MODULATE;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat MULTIPLY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat OVERLAY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat PLUS;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SATURATION;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SCREEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SOFT_LIGHT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_ATOP;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_IN;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OUT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OVER;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat XOR;
+ }
+
+ public final class ColorUtils {
+ method @ColorInt public static int HSLToColor(float[]);
+ method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
+ method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
+ method @ColorInt public static int M3HCTToColor(@FloatRange(from=0.0, to=360, toInclusive=false) float, @FloatRange(from=0.0, to=java.lang.Double.POSITIVE_INFINITY, toInclusive=false) float, @FloatRange(from=0.0, to=100) float);
+ method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
+ method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+ method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+ method @ColorInt public static int XYZToColor(@FloatRange(from=0.0f, to=95.047) double, @FloatRange(from=0.0f, to=0x64) double, @FloatRange(from=0.0f, to=108.883) double);
+ method public static void XYZToLAB(@FloatRange(from=0.0f, to=95.047) double, @FloatRange(from=0.0f, to=0x64) double, @FloatRange(from=0.0f, to=108.883) double, double[]);
+ method @ColorInt public static int blendARGB(@ColorInt int, @ColorInt int, @FloatRange(from=0.0, to=1.0) float);
+ method public static void blendHSL(float[], float[], @FloatRange(from=0.0, to=1.0) float, float[]);
+ method public static void blendLAB(double[], double[], @FloatRange(from=0.0, to=1.0) double, double[]);
+ method public static double calculateContrast(@ColorInt int, @ColorInt int);
+ method @FloatRange(from=0.0, to=1.0) public static double calculateLuminance(@ColorInt int);
+ method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
+ method public static void colorToHSL(@ColorInt int, float[]);
+ method public static void colorToLAB(@ColorInt int, double[]);
+ method public static void colorToM3HCT(@ColorInt int, @Size(3) float[]);
+ method public static void colorToXYZ(@ColorInt int, double[]);
+ method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
+ method public static int compositeColors(@ColorInt int, @ColorInt int);
+ method public static double distanceEuclidean(double[], double[]);
+ method @ColorInt public static int setAlphaComponent(@ColorInt int, @IntRange(from=0, to=255) int);
+ }
+
+ public final class Insets {
+ method public static androidx.core.graphics.Insets add(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets max(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets min(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets of(android.graphics.Rect);
+ method public static androidx.core.graphics.Insets of(int, int, int, int);
+ method public static androidx.core.graphics.Insets subtract(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method @RequiresApi(api=29) public static androidx.core.graphics.Insets toCompatInsets(android.graphics.Insets);
+ method @RequiresApi(29) public android.graphics.Insets toPlatformInsets();
+ field public static final androidx.core.graphics.Insets NONE;
+ field public final int bottom;
+ field public final int left;
+ field public final int right;
+ field public final int top;
+ }
+
+ public final class PaintCompat {
+ method public static boolean hasGlyph(android.graphics.Paint, String);
+ method public static boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat?);
+ }
+
+ public final class PathSegment {
+ ctor public PathSegment(android.graphics.PointF, float, android.graphics.PointF, float);
+ method public android.graphics.PointF getEnd();
+ method public float getEndFraction();
+ method public android.graphics.PointF getStart();
+ method public float getStartFraction();
+ }
+
+ public final class PathUtils {
+ method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path);
+ method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path, @FloatRange(from=0) float);
+ }
+
+ public class TypefaceCompat {
+ method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, int);
+ method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, @IntRange(from=1, to=1000) int, boolean);
+ }
+
+}
+
+package androidx.core.graphics.drawable {
+
+ public final class DrawableCompat {
+ method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
+ method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
+ method public static void clearColorFilter(android.graphics.drawable.Drawable);
+ method public static int getAlpha(android.graphics.drawable.Drawable);
+ method public static android.graphics.ColorFilter? getColorFilter(android.graphics.drawable.Drawable);
+ method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+ method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+ method @Deprecated public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+ method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+ method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+ method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+ method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
+ method public static void setTint(android.graphics.drawable.Drawable, @ColorInt int);
+ method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList?);
+ method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode?);
+ method public static <T extends android.graphics.drawable.Drawable> T! unwrap(android.graphics.drawable.Drawable);
+ method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
+ }
+
+ public class IconCompat implements androidx.versionedparcelable.VersionedParcelable {
+ method public static androidx.core.graphics.drawable.IconCompat? createFromBundle(android.os.Bundle);
+ method @RequiresApi(23) public static androidx.core.graphics.drawable.IconCompat? createFromIcon(android.content.Context, android.graphics.drawable.Icon);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmap(android.graphics.Bitmap);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(android.net.Uri);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(String);
+ method public static androidx.core.graphics.drawable.IconCompat createWithBitmap(android.graphics.Bitmap);
+ method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(android.net.Uri);
+ method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(String);
+ method public static androidx.core.graphics.drawable.IconCompat createWithData(byte[], int, int);
+ method public static androidx.core.graphics.drawable.IconCompat createWithResource(android.content.Context, @DrawableRes int);
+ method @DrawableRes public int getResId();
+ method public String getResPackage();
+ method public int getType();
+ method public android.net.Uri getUri();
+ method public android.graphics.drawable.Drawable? loadDrawable(android.content.Context);
+ method public void onPostParceling();
+ method public void onPreParceling(boolean);
+ method public androidx.core.graphics.drawable.IconCompat setTint(@ColorInt int);
+ method public androidx.core.graphics.drawable.IconCompat setTintList(android.content.res.ColorStateList?);
+ method public androidx.core.graphics.drawable.IconCompat setTintMode(android.graphics.PorterDuff.Mode?);
+ method public android.os.Bundle toBundle();
+ method @Deprecated @RequiresApi(23) public android.graphics.drawable.Icon toIcon();
+ method @RequiresApi(23) public android.graphics.drawable.Icon toIcon(android.content.Context?);
+ field public static final int TYPE_ADAPTIVE_BITMAP = 5; // 0x5
+ field public static final int TYPE_BITMAP = 1; // 0x1
+ field public static final int TYPE_DATA = 3; // 0x3
+ field public static final int TYPE_RESOURCE = 2; // 0x2
+ field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+ field public static final int TYPE_URI = 4; // 0x4
+ field public static final int TYPE_URI_ADAPTIVE_BITMAP = 6; // 0x6
+ }
+
+ public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+ method public void draw(android.graphics.Canvas);
+ method public final android.graphics.Bitmap? getBitmap();
+ method public float getCornerRadius();
+ method public int getGravity();
+ method public int getOpacity();
+ method public final android.graphics.Paint getPaint();
+ method public boolean hasAntiAlias();
+ method public boolean hasMipMap();
+ method public boolean isCircular();
+ method public void setAlpha(int);
+ method public void setAntiAlias(boolean);
+ method public void setCircular(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter!);
+ method public void setCornerRadius(float);
+ method public void setDither(boolean);
+ method public void setGravity(int);
+ method public void setMipMap(boolean);
+ method public void setTargetDensity(android.graphics.Canvas);
+ method public void setTargetDensity(android.util.DisplayMetrics);
+ method public void setTargetDensity(int);
+ }
+
+ public final class RoundedBitmapDrawableFactory {
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap?);
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, String);
+ }
+
+}
+
+package androidx.core.hardware.display {
+
+ public final class DisplayManagerCompat {
+ method public android.view.Display? getDisplay(int);
+ method public android.view.Display![] getDisplays();
+ method public android.view.Display![] getDisplays(String?);
+ method public static androidx.core.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+ field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+ }
+
+}
+
+package androidx.core.hardware.fingerprint {
+
+ @Deprecated public class FingerprintManagerCompat {
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public void authenticate(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject?, int, androidx.core.os.CancellationSignal?, androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler?);
+ method @Deprecated public static androidx.core.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+ }
+
+ @Deprecated public abstract static class FingerprintManagerCompat.AuthenticationCallback {
+ ctor @Deprecated public FingerprintManagerCompat.AuthenticationCallback();
+ method @Deprecated public void onAuthenticationError(int, CharSequence!);
+ method @Deprecated public void onAuthenticationFailed();
+ method @Deprecated public void onAuthenticationHelp(int, CharSequence!);
+ method @Deprecated public void onAuthenticationSucceeded(androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult!);
+ }
+
+ @Deprecated public static final class FingerprintManagerCompat.AuthenticationResult {
+ ctor @Deprecated public FingerprintManagerCompat.AuthenticationResult(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject!);
+ method @Deprecated public androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject! getCryptoObject();
+ }
+
+ @Deprecated public static class FingerprintManagerCompat.CryptoObject {
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+ method @Deprecated public javax.crypto.Cipher? getCipher();
+ method @Deprecated public javax.crypto.Mac? getMac();
+ method @Deprecated public java.security.Signature? getSignature();
+ }
+
+}
+
+package androidx.core.location {
+
+ public abstract class GnssStatusCompat {
+ method @FloatRange(from=0, to=360) public abstract float getAzimuthDegrees(@IntRange(from=0) int);
+ method @FloatRange(from=0, to=63) public abstract float getBasebandCn0DbHz(@IntRange(from=0) int);
+ method @FloatRange(from=0) public abstract float getCarrierFrequencyHz(@IntRange(from=0) int);
+ method @FloatRange(from=0, to=63) public abstract float getCn0DbHz(@IntRange(from=0) int);
+ method public abstract int getConstellationType(@IntRange(from=0) int);
+ method @FloatRange(from=0xffffffa6, to=90) public abstract float getElevationDegrees(@IntRange(from=0) int);
+ method @IntRange(from=0) public abstract int getSatelliteCount();
+ method @IntRange(from=1, to=200) public abstract int getSvid(@IntRange(from=0) int);
+ method public abstract boolean hasAlmanacData(@IntRange(from=0) int);
+ method public abstract boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
+ method public abstract boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
+ method public abstract boolean hasEphemerisData(@IntRange(from=0) int);
+ method public abstract boolean usedInFix(@IntRange(from=0) int);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) public static androidx.core.location.GnssStatusCompat wrap(android.location.GnssStatus);
+ method public static androidx.core.location.GnssStatusCompat wrap(android.location.GpsStatus);
+ field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_IRNSS = 7; // 0x7
+ field public static final int CONSTELLATION_QZSS = 4; // 0x4
+ field public static final int CONSTELLATION_SBAS = 2; // 0x2
+ field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public abstract static class GnssStatusCompat.Callback {
+ ctor public GnssStatusCompat.Callback();
+ method public void onFirstFix(@IntRange(from=0) int);
+ method public void onSatelliteStatusChanged(androidx.core.location.GnssStatusCompat);
+ method public void onStarted();
+ method public void onStopped();
+ }
+
+ public final class LocationCompat {
+ method public static float getBearingAccuracyDegrees(android.location.Location);
+ method public static long getElapsedRealtimeMillis(android.location.Location);
+ method public static long getElapsedRealtimeNanos(android.location.Location);
+ method @FloatRange(from=0.0) public static float getMslAltitudeAccuracyMeters(android.location.Location);
+ method public static double getMslAltitudeMeters(android.location.Location);
+ method public static float getSpeedAccuracyMetersPerSecond(android.location.Location);
+ method public static float getVerticalAccuracyMeters(android.location.Location);
+ method public static boolean hasBearingAccuracy(android.location.Location);
+ method public static boolean hasMslAltitude(android.location.Location);
+ method public static boolean hasMslAltitudeAccuracy(android.location.Location);
+ method public static boolean hasSpeedAccuracy(android.location.Location);
+ method public static boolean hasVerticalAccuracy(android.location.Location);
+ method public static boolean isMock(android.location.Location);
+ method public static void removeMslAltitude(android.location.Location);
+ method public static void removeMslAltitudeAccuracy(android.location.Location);
+ method public static void setBearingAccuracyDegrees(android.location.Location, float);
+ method public static void setMock(android.location.Location, boolean);
+ method public static void setMslAltitudeAccuracyMeters(android.location.Location, @FloatRange(from=0.0) float);
+ method public static void setMslAltitudeMeters(android.location.Location, double);
+ method public static void setSpeedAccuracyMetersPerSecond(android.location.Location, float);
+ method public static void setVerticalAccuracyMeters(android.location.Location, float);
+ field public static final String EXTRA_BEARING_ACCURACY = "bearingAccuracy";
+ field public static final String EXTRA_IS_MOCK = "mockLocation";
+ field public static final String EXTRA_MSL_ALTITUDE = "androidx.core.location.extra.MSL_ALTITUDE";
+ field public static final String EXTRA_MSL_ALTITUDE_ACCURACY = "androidx.core.location.extra.MSL_ALTITUDE_ACCURACY";
+ field public static final String EXTRA_SPEED_ACCURACY = "speedAccuracy";
+ field public static final String EXTRA_VERTICAL_ACCURACY = "verticalAccuracy";
+ }
+
+ public interface LocationListenerCompat extends android.location.LocationListener {
+ method public default void onStatusChanged(String, int, android.os.Bundle?);
+ }
+
+ public final class LocationManagerCompat {
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void getCurrentLocation(android.location.LocationManager, String, androidx.core.os.CancellationSignal?, java.util.concurrent.Executor, androidx.core.util.Consumer<android.location.Location!>);
+ method public static String? getGnssHardwareModelName(android.location.LocationManager);
+ method public static int getGnssYearOfHardware(android.location.LocationManager);
+ method public static boolean hasProvider(android.location.LocationManager, String);
+ method public static boolean isLocationEnabled(android.location.LocationManager);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssMeasurementsCallback(android.location.LocationManager, android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssMeasurementsCallback(android.location.LocationManager, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback, android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, java.util.concurrent.Executor, androidx.core.location.GnssStatusCompat.Callback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void removeUpdates(android.location.LocationManager, androidx.core.location.LocationListenerCompat);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, androidx.core.location.LocationListenerCompat, android.os.Looper);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, java.util.concurrent.Executor, androidx.core.location.LocationListenerCompat);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) public static void unregisterGnssMeasurementsCallback(android.location.LocationManager, android.location.GnssMeasurementsEvent.Callback);
+ method public static void unregisterGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback);
+ }
+
+ public final class LocationRequestCompat {
+ method @IntRange(from=1) public long getDurationMillis();
+ method @IntRange(from=0) public long getIntervalMillis();
+ method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+ method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
+ method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
+ method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
+ method @RequiresApi(31) public android.location.LocationRequest toLocationRequest();
+ method @RequiresApi(19) public android.location.LocationRequest? toLocationRequest(String);
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
+ }
+
+ public static final class LocationRequestCompat.Builder {
+ ctor public LocationRequestCompat.Builder(androidx.core.location.LocationRequestCompat);
+ ctor public LocationRequestCompat.Builder(long);
+ method public androidx.core.location.LocationRequestCompat build();
+ method public androidx.core.location.LocationRequestCompat.Builder clearMinUpdateIntervalMillis();
+ method public androidx.core.location.LocationRequestCompat.Builder setDurationMillis(@IntRange(from=1) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setIntervalMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+ method public androidx.core.location.LocationRequestCompat.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
+ method public androidx.core.location.LocationRequestCompat.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setQuality(int);
+ }
+
+}
+
+package androidx.core.math {
+
+ public class MathUtils {
+ method public static int addExact(int, int);
+ method public static long addExact(long, long);
+ method public static double clamp(double, double, double);
+ method public static float clamp(float, float, float);
+ method public static int clamp(int, int, int);
+ method public static long clamp(long, long, long);
+ method public static int decrementExact(int);
+ method public static long decrementExact(long);
+ method public static int incrementExact(int);
+ method public static long incrementExact(long);
+ method public static int multiplyExact(int, int);
+ method public static long multiplyExact(long, long);
+ method public static int negateExact(int);
+ method public static long negateExact(long);
+ method public static int subtractExact(int, int);
+ method public static long subtractExact(long, long);
+ method public static int toIntExact(long);
+ }
+
+}
+
+package androidx.core.net {
+
+ public final class ConnectivityManagerCompat {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static android.net.NetworkInfo? getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+ method public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+ field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+ field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+ field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+ }
+
+ public final class MailTo {
+ method public String? getBcc();
+ method public String? getBody();
+ method public String? getCc();
+ method public java.util.Map<java.lang.String!,java.lang.String!>? getHeaders();
+ method public String? getSubject();
+ method public String? getTo();
+ method public static boolean isMailTo(android.net.Uri?);
+ method public static boolean isMailTo(String?);
+ method public static androidx.core.net.MailTo parse(android.net.Uri) throws androidx.core.net.ParseException;
+ method public static androidx.core.net.MailTo parse(String) throws androidx.core.net.ParseException;
+ field public static final String MAILTO_SCHEME = "mailto:";
+ }
+
+ public class ParseException extends java.lang.RuntimeException {
+ field public final String response;
+ }
+
+ public final class TrafficStatsCompat {
+ method @Deprecated public static void clearThreadStatsTag();
+ method @Deprecated public static int getThreadStatsTag();
+ method @Deprecated public static void incrementOperationCount(int);
+ method @Deprecated public static void incrementOperationCount(int, int);
+ method @Deprecated public static void setThreadStatsTag(int);
+ method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method @Deprecated public static void tagSocket(java.net.Socket!) throws java.net.SocketException;
+ method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method @Deprecated public static void untagSocket(java.net.Socket!) throws java.net.SocketException;
+ }
+
+ public final class UriCompat {
+ method public static String toSafeString(android.net.Uri);
+ }
+
+}
+
+package androidx.core.os {
+
+ public class BuildCompat {
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O_MR1) public static boolean isAtLeastOMR1();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.P) public static boolean isAtLeastP();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.Q) public static boolean isAtLeastQ();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.R) public static boolean isAtLeastR();
+ method @Deprecated @ChecksSdkIntAtLeast(api=31, codename="S") public static boolean isAtLeastS();
+ method @Deprecated @ChecksSdkIntAtLeast(api=32, codename="Sv2") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastSv2();
+ method @Deprecated @ChecksSdkIntAtLeast(api=33, codename="Tiramisu") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastT();
+ method @ChecksSdkIntAtLeast(api=34, codename="UpsideDownCake") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastU();
+ method @ChecksSdkIntAtLeast(codename="VanillaIceCream") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastV();
+ field @ChecksSdkIntAtLeast(extension=android.os.ext.SdkExtensions.AD_SERVICES) public static final int AD_SERVICES_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.R) public static final int R_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.S) public static final int S_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.TIRAMISU) public static final int T_EXTENSION_INT;
+ }
+
+ @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface BuildCompat.PrereleaseSdkCheck {
+ }
+
+ public final class BundleCompat {
+ method public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+ method public static <T> T? getParcelable(android.os.Bundle, String?, Class<T!>);
+ method public static android.os.Parcelable![]? getParcelableArray(android.os.Bundle, String?, Class<? extends android.os.Parcelable>);
+ method public static <T> java.util.ArrayList<T!>? getParcelableArrayList(android.os.Bundle, String?, Class<? extends T>);
+ method public static <T> android.util.SparseArray<T!>? getSparseParcelableArray(android.os.Bundle, String?, Class<? extends T>);
+ method public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+ }
+
+ public final class CancellationSignal {
+ ctor public CancellationSignal();
+ method public void cancel();
+ method public Object? getCancellationSignalObject();
+ method public boolean isCanceled();
+ method public void setOnCancelListener(androidx.core.os.CancellationSignal.OnCancelListener?);
+ method public void throwIfCanceled();
+ }
+
+ public static interface CancellationSignal.OnCancelListener {
+ method public void onCancel();
+ }
+
+ public final class ConfigurationCompat {
+ method public static androidx.core.os.LocaleListCompat getLocales(android.content.res.Configuration);
+ method public static void setLocales(android.content.res.Configuration, androidx.core.os.LocaleListCompat);
+ }
+
+ public final class EnvironmentCompat {
+ method public static String getStorageState(java.io.File);
+ field public static final String MEDIA_UNKNOWN = "unknown";
+ }
+
+ public final class ExecutorCompat {
+ method public static java.util.concurrent.Executor create(android.os.Handler);
+ }
+
+ public final class HandlerCompat {
+ method public static android.os.Handler createAsync(android.os.Looper);
+ method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
+ method @RequiresApi(16) public static boolean hasCallbacks(android.os.Handler, Runnable);
+ method public static boolean postDelayed(android.os.Handler, Runnable, Object?, long);
+ }
+
+ public final class LocaleListCompat {
+ method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...);
+ method public static androidx.core.os.LocaleListCompat forLanguageTags(String?);
+ method public java.util.Locale? get(int);
+ method @Size(min=1) public static androidx.core.os.LocaleListCompat getAdjustedDefault();
+ method @Size(min=1) public static androidx.core.os.LocaleListCompat getDefault();
+ method public static androidx.core.os.LocaleListCompat getEmptyLocaleList();
+ method public java.util.Locale? getFirstMatch(String![]);
+ method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale?);
+ method public boolean isEmpty();
+ method @RequiresApi(21) public static boolean matchesLanguageAndScript(java.util.Locale, java.util.Locale);
+ method @IntRange(from=0) public int size();
+ method public String toLanguageTags();
+ method public Object? unwrap();
+ method @RequiresApi(24) public static androidx.core.os.LocaleListCompat wrap(android.os.LocaleList);
+ method @Deprecated @RequiresApi(24) public static androidx.core.os.LocaleListCompat! wrap(Object!);
+ }
+
+ public final class MessageCompat {
+ method public static boolean isAsynchronous(android.os.Message);
+ method public static void setAsynchronous(android.os.Message, boolean);
+ }
+
+ public class OperationCanceledException extends java.lang.RuntimeException {
+ ctor public OperationCanceledException();
+ ctor public OperationCanceledException(String?);
+ }
+
+ public final class ParcelCompat {
+ method public static <T> Object![]? readArray(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> java.util.ArrayList<T!>? readArrayList(android.os.Parcel, ClassLoader?, Class<? extends T>);
+ method public static boolean readBoolean(android.os.Parcel);
+ method public static <K, V> java.util.HashMap<K!,V!>? readHashMap(android.os.Parcel, ClassLoader?, Class<? extends K>, Class<? extends V>);
+ method public static <T> void readList(android.os.Parcel, java.util.List<? super T>, ClassLoader?, Class<T!>);
+ method public static <K, V> void readMap(android.os.Parcel, java.util.Map<? super K,? super V>, ClassLoader?, Class<K!>, Class<V!>);
+ method public static <T extends android.os.Parcelable> T? readParcelable(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @Deprecated public static <T> T![]? readParcelableArray(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> android.os.Parcelable![]? readParcelableArrayTyped(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @RequiresApi(30) public static <T> android.os.Parcelable.Creator<T!>? readParcelableCreator(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @RequiresApi(api=android.os.Build.VERSION_CODES.Q) public static <T> java.util.List<T!> readParcelableList(android.os.Parcel, java.util.List<T!>, ClassLoader?, Class<T!>);
+ method public static <T extends java.io.Serializable> T? readSerializable(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> android.util.SparseArray<T!>? readSparseArray(android.os.Parcel, ClassLoader?, Class<? extends T>);
+ method public static void writeBoolean(android.os.Parcel, boolean);
+ }
+
+ @Deprecated public final class ParcelableCompat {
+ method @Deprecated public static <T> android.os.Parcelable.Creator<T!>! newCreator(androidx.core.os.ParcelableCompatCreatorCallbacks<T!>!);
+ }
+
+ @Deprecated public interface ParcelableCompatCreatorCallbacks<T> {
+ method @Deprecated public T! createFromParcel(android.os.Parcel!, ClassLoader!);
+ method @Deprecated public T![]! newArray(int);
+ }
+
+ public final class ProcessCompat {
+ method public static boolean isApplicationUid(int);
+ }
+
+ @Deprecated public final class TraceCompat {
+ method @Deprecated public static void beginAsyncSection(String, int);
+ method @Deprecated public static void beginSection(String);
+ method @Deprecated public static void endAsyncSection(String, int);
+ method @Deprecated public static void endSection();
+ method @Deprecated public static boolean isEnabled();
+ method @Deprecated public static void setCounter(String, int);
+ }
+
+ @RequiresApi(17) public class UserHandleCompat {
+ method public static android.os.UserHandle getUserHandleForUid(int);
+ }
+
+ public class UserManagerCompat {
+ method public static boolean isUserUnlocked(android.content.Context);
+ }
+
+}
+
+package androidx.core.provider {
+
+ public final class DocumentsContractCompat {
+ method public static android.net.Uri? buildChildDocumentsUri(String, String?);
+ method public static android.net.Uri? buildChildDocumentsUriUsingTree(android.net.Uri, String);
+ method public static android.net.Uri? buildDocumentUri(String, String);
+ method public static android.net.Uri? buildDocumentUriUsingTree(android.net.Uri, String);
+ method public static android.net.Uri? buildTreeDocumentUri(String, String);
+ method public static android.net.Uri? createDocument(android.content.ContentResolver, android.net.Uri, String, String) throws java.io.FileNotFoundException;
+ method public static String? getDocumentId(android.net.Uri);
+ method public static String? getTreeDocumentId(android.net.Uri);
+ method public static boolean isDocumentUri(android.content.Context, android.net.Uri?);
+ method public static boolean isTreeUri(android.net.Uri);
+ method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.net.Uri? renameDocument(android.content.ContentResolver, android.net.Uri, String) throws java.io.FileNotFoundException;
+ }
+
+ public static final class DocumentsContractCompat.DocumentCompat {
+ field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
+ }
+
+ public final class FontRequest {
+ ctor public FontRequest(String, String, String, @ArrayRes int);
+ ctor public FontRequest(String, String, String, java.util.List<java.util.List<byte[]!>!>);
+ method public java.util.List<java.util.List<byte[]!>!>? getCertificates();
+ method @ArrayRes public int getCertificatesArrayResId();
+ method public String getProviderAuthority();
+ method public String getProviderPackage();
+ method public String getQuery();
+ }
+
+ public class FontsContractCompat {
+ method public static android.graphics.Typeface? buildTypeface(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![]);
+ method public static androidx.core.provider.FontsContractCompat.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static void requestFont(android.content.Context, androidx.core.provider.FontRequest, androidx.core.provider.FontsContractCompat.FontRequestCallback, android.os.Handler);
+ }
+
+ public static final class FontsContractCompat.Columns implements android.provider.BaseColumns {
+ ctor public FontsContractCompat.Columns();
+ field public static final String FILE_ID = "file_id";
+ field public static final String ITALIC = "font_italic";
+ field public static final String RESULT_CODE = "result_code";
+ field public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
+ field public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
+ field public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
+ field public static final int RESULT_CODE_OK = 0; // 0x0
+ field public static final String TTC_INDEX = "font_ttc_index";
+ field public static final String VARIATION_SETTINGS = "font_variation_settings";
+ field public static final String WEIGHT = "font_weight";
+ }
+
+ public static class FontsContractCompat.FontFamilyResult {
+ method public androidx.core.provider.FontsContractCompat.FontInfo![]! getFonts();
+ method public int getStatusCode();
+ field public static final int STATUS_OK = 0; // 0x0
+ field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
+ field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
+ }
+
+ public static class FontsContractCompat.FontInfo {
+ method public int getResultCode();
+ method @IntRange(from=0) public int getTtcIndex();
+ method public android.net.Uri getUri();
+ method @IntRange(from=1, to=1000) public int getWeight();
+ method public boolean isItalic();
+ }
+
+ public static class FontsContractCompat.FontRequestCallback {
+ ctor public FontsContractCompat.FontRequestCallback();
+ method public void onTypefaceRequestFailed(int);
+ method public void onTypefaceRetrieved(android.graphics.Typeface!);
+ field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
+ field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
+ field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
+ field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
+ field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
+ field public static final int FAIL_REASON_SECURITY_VIOLATION = -4; // 0xfffffffc
+ field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
+ }
+
+}
+
+package androidx.core.telephony {
+
+ @RequiresApi(22) public class SubscriptionManagerCompat {
+ method public static int getSlotIndex(int);
+ }
+
+ public class TelephonyManagerCompat {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static String? getImei(android.telephony.TelephonyManager);
+ method public static int getSubscriptionId(android.telephony.TelephonyManager);
+ }
+
+}
+
+package androidx.core.telephony.mbms {
+
+ public final class MbmsHelper {
+ method public static CharSequence? getBestNameForService(android.content.Context, android.telephony.mbms.ServiceInfo);
+ }
+
+}
+
+package androidx.core.text {
+
+ public final class BidiFormatter {
+ method public static androidx.core.text.BidiFormatter! getInstance();
+ method public static androidx.core.text.BidiFormatter! getInstance(boolean);
+ method public static androidx.core.text.BidiFormatter! getInstance(java.util.Locale!);
+ method public boolean getStereoReset();
+ method public boolean isRtl(CharSequence!);
+ method public boolean isRtl(String!);
+ method public boolean isRtlContext();
+ method public CharSequence! unicodeWrap(CharSequence!);
+ method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!);
+ method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+ method public CharSequence! unicodeWrap(CharSequence!, boolean);
+ method public String! unicodeWrap(String!);
+ method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!);
+ method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+ method public String! unicodeWrap(String!, boolean);
+ }
+
+ public static final class BidiFormatter.Builder {
+ ctor public BidiFormatter.Builder();
+ ctor public BidiFormatter.Builder(boolean);
+ ctor public BidiFormatter.Builder(java.util.Locale!);
+ method public androidx.core.text.BidiFormatter! build();
+ method public androidx.core.text.BidiFormatter.Builder! setTextDirectionHeuristic(androidx.core.text.TextDirectionHeuristicCompat!);
+ method public androidx.core.text.BidiFormatter.Builder! stereoReset(boolean);
+ }
+
+ public final class HtmlCompat {
+ method public static android.text.Spanned fromHtml(String, int);
+ method public static android.text.Spanned fromHtml(String, int, android.text.Html.ImageGetter?, android.text.Html.TagHandler?);
+ method public static String toHtml(android.text.Spanned, int);
+ field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
+ field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
+ field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32; // 0x20
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16; // 0x10
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2; // 0x2
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8; // 0x8
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4; // 0x4
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1; // 0x1
+ field public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0; // 0x0
+ field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
+ }
+
+ public final class ICUCompat {
+ method public static String? maximizeAndGetScript(java.util.Locale);
+ }
+
+ public class PrecomputedTextCompat implements android.text.Spannable {
+ method public char charAt(int);
+ method public static androidx.core.text.PrecomputedTextCompat! create(CharSequence, androidx.core.text.PrecomputedTextCompat.Params);
+ method @IntRange(from=0) public int getParagraphCount();
+ method @IntRange(from=0) public int getParagraphEnd(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getParagraphStart(@IntRange(from=0) int);
+ method public androidx.core.text.PrecomputedTextCompat.Params getParams();
+ method public int getSpanEnd(Object!);
+ method public int getSpanFlags(Object!);
+ method public int getSpanStart(Object!);
+ method public <T> T![]! getSpans(int, int, Class<T!>!);
+ method @UiThread public static java.util.concurrent.Future<androidx.core.text.PrecomputedTextCompat!>! getTextFuture(CharSequence, androidx.core.text.PrecomputedTextCompat.Params, java.util.concurrent.Executor?);
+ method public int length();
+ method public int nextSpanTransition(int, int, Class!);
+ method public void removeSpan(Object!);
+ method public void setSpan(Object!, int, int, int);
+ method public CharSequence! subSequence(int, int);
+ }
+
+ public static final class PrecomputedTextCompat.Params {
+ ctor @RequiresApi(28) public PrecomputedTextCompat.Params(android.text.PrecomputedText.Params);
+ method @RequiresApi(23) public int getBreakStrategy();
+ method @RequiresApi(23) public int getHyphenationFrequency();
+ method @RequiresApi(18) public android.text.TextDirectionHeuristic? getTextDirection();
+ method public android.text.TextPaint getTextPaint();
+ }
+
+ public static class PrecomputedTextCompat.Params.Builder {
+ ctor public PrecomputedTextCompat.Params.Builder(android.text.TextPaint);
+ method public androidx.core.text.PrecomputedTextCompat.Params build();
+ method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setBreakStrategy(int);
+ method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setHyphenationFrequency(int);
+ method @RequiresApi(18) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setTextDirection(android.text.TextDirectionHeuristic);
+ }
+
+ public interface TextDirectionHeuristicCompat {
+ method public boolean isRtl(char[]!, int, int);
+ method public boolean isRtl(CharSequence!, int, int);
+ }
+
+ public final class TextDirectionHeuristicsCompat {
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! ANYRTL_LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_RTL;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! LOCALE;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! RTL;
+ }
+
+ public final class TextUtilsCompat {
+ method public static int getLayoutDirectionFromLocale(java.util.Locale?);
+ method public static String htmlEncode(String);
+ }
+
+}
+
+package androidx.core.text.method {
+
+ public class LinkMovementMethodCompat extends android.text.method.LinkMovementMethod {
+ method public static androidx.core.text.method.LinkMovementMethodCompat getInstance();
+ }
+
+}
+
+package androidx.core.text.util {
+
+ public final class LinkifyCompat {
+ method public static boolean addLinks(android.text.Spannable, int);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static boolean addLinks(android.widget.TextView, int);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ }
+
+}
+
+package androidx.core.util {
+
+ public class AtomicFile {
+ ctor public AtomicFile(java.io.File);
+ method public void delete();
+ method public void failWrite(java.io.FileOutputStream?);
+ method public void finishWrite(java.io.FileOutputStream?);
+ method public java.io.File getBaseFile();
+ method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+ method public byte[] readFully() throws java.io.IOException;
+ method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+ }
+
+ public interface Consumer<T> {
+ method public void accept(T!);
+ }
+
+ public class ObjectsCompat {
+ method public static boolean equals(Object?, Object?);
+ method public static int hash(java.lang.Object!...);
+ method public static int hashCode(Object?);
+ method public static <T> T requireNonNull(T?);
+ method public static <T> T requireNonNull(T?, String);
+ method public static String? toString(Object?, String?);
+ }
+
+ public class Pair<F, S> {
+ ctor public Pair(F!, S!);
+ method public static <A, B> androidx.core.util.Pair<A!,B!> create(A!, B!);
+ field public final F! first;
+ field public final S! second;
+ }
+
+ public final class PatternsCompat {
+ field public static final java.util.regex.Pattern DOMAIN_NAME;
+ field public static final java.util.regex.Pattern EMAIL_ADDRESS;
+ field public static final java.util.regex.Pattern IP_ADDRESS;
+ field public static final java.util.regex.Pattern WEB_URL;
+ }
+
+ public final class Pools {
+ }
+
+ public static interface Pools.Pool<T> {
+ method public T? acquire();
+ method public boolean release(T);
+ }
+
+ public static class Pools.SimplePool<T> implements androidx.core.util.Pools.Pool<T> {
+ ctor public Pools.SimplePool(int);
+ method public T! acquire();
+ method public boolean release(T);
+ }
+
+ public static class Pools.SynchronizedPool<T> extends androidx.core.util.Pools.SimplePool<T> {
+ ctor public Pools.SynchronizedPool(int);
+ }
+
+ public interface Predicate<T> {
+ method public default androidx.core.util.Predicate<T!>! and(androidx.core.util.Predicate<? super T>!);
+ method public static <T> androidx.core.util.Predicate<T!>! isEqual(Object!);
+ method public default androidx.core.util.Predicate<T!>! negate();
+ method public static <T> androidx.core.util.Predicate<T!>! not(androidx.core.util.Predicate<? super T>!);
+ method public default androidx.core.util.Predicate<T!>! or(androidx.core.util.Predicate<? super T>!);
+ method public boolean test(T!);
+ }
+
+ public final class SizeFCompat {
+ ctor public SizeFCompat(float, float);
+ method public float getHeight();
+ method public float getWidth();
+ method @RequiresApi(21) public android.util.SizeF toSizeF();
+ method @RequiresApi(21) public static androidx.core.util.SizeFCompat toSizeFCompat(android.util.SizeF);
+ }
+
+ public interface Supplier<T> {
+ method public T! get();
+ }
+
+}
+
+package androidx.core.view {
+
+ public class AccessibilityDelegateCompat {
+ ctor public AccessibilityDelegateCompat();
+ method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
+ method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+ method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+ method public void sendAccessibilityEvent(android.view.View, int);
+ method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+ }
+
+ public abstract class ActionProvider {
+ ctor public ActionProvider(android.content.Context);
+ method public android.content.Context getContext();
+ method public boolean hasSubMenu();
+ method public boolean isVisible();
+ method public abstract android.view.View onCreateActionView();
+ method public android.view.View onCreateActionView(android.view.MenuItem);
+ method public boolean onPerformDefaultAction();
+ method public void onPrepareSubMenu(android.view.SubMenu);
+ method public boolean overridesItemVisibility();
+ method public void refreshVisibility();
+ method public void setVisibilityListener(androidx.core.view.ActionProvider.VisibilityListener?);
+ }
+
+ public static interface ActionProvider.VisibilityListener {
+ method public void onActionProviderVisibilityChanged(boolean);
+ }
+
+ public final class ContentInfoCompat {
+ method public android.content.ClipData getClip();
+ method public android.os.Bundle? getExtras();
+ method public int getFlags();
+ method public android.net.Uri? getLinkUri();
+ method public int getSource();
+ method @RequiresApi(31) public static android.util.Pair<android.view.ContentInfo!,android.view.ContentInfo!> partition(android.view.ContentInfo, java.util.function.Predicate<android.content.ClipData.Item!>);
+ method public android.util.Pair<androidx.core.view.ContentInfoCompat!,androidx.core.view.ContentInfoCompat!> partition(androidx.core.util.Predicate<android.content.ClipData.Item!>);
+ method @RequiresApi(31) public android.view.ContentInfo toContentInfo();
+ method @RequiresApi(31) public static androidx.core.view.ContentInfoCompat toContentInfoCompat(android.view.ContentInfo);
+ field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
+ field public static final int SOURCE_APP = 0; // 0x0
+ field public static final int SOURCE_AUTOFILL = 4; // 0x4
+ field public static final int SOURCE_CLIPBOARD = 1; // 0x1
+ field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
+ field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+ field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
+ }
+
+ public static final class ContentInfoCompat.Builder {
+ ctor public ContentInfoCompat.Builder(android.content.ClipData, int);
+ ctor public ContentInfoCompat.Builder(androidx.core.view.ContentInfoCompat);
+ method public androidx.core.view.ContentInfoCompat build();
+ method public androidx.core.view.ContentInfoCompat.Builder setClip(android.content.ClipData);
+ method public androidx.core.view.ContentInfoCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.view.ContentInfoCompat.Builder setFlags(int);
+ method public androidx.core.view.ContentInfoCompat.Builder setLinkUri(android.net.Uri?);
+ method public androidx.core.view.ContentInfoCompat.Builder setSource(int);
+ }
+
+ public final class DisplayCompat {
+ method public static androidx.core.view.DisplayCompat.ModeCompat getMode(android.content.Context, android.view.Display);
+ method public static androidx.core.view.DisplayCompat.ModeCompat![] getSupportedModes(android.content.Context, android.view.Display);
+ }
+
+ public static final class DisplayCompat.ModeCompat {
+ method public int getPhysicalHeight();
+ method public int getPhysicalWidth();
+ method @Deprecated public boolean isNative();
+ method @RequiresApi(android.os.Build.VERSION_CODES.M) public android.view.Display.Mode? toMode();
+ }
+
+ public final class DisplayCutoutCompat {
+ ctor public DisplayCutoutCompat(android.graphics.Rect?, java.util.List<android.graphics.Rect!>?);
+ ctor public DisplayCutoutCompat(androidx.core.graphics.Insets, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, androidx.core.graphics.Insets);
+ method public java.util.List<android.graphics.Rect!> getBoundingRects();
+ method public int getSafeInsetBottom();
+ method public int getSafeInsetLeft();
+ method public int getSafeInsetRight();
+ method public int getSafeInsetTop();
+ method public androidx.core.graphics.Insets getWaterfallInsets();
+ }
+
+ public final class DragAndDropPermissionsCompat {
+ method public void release();
+ }
+
+ public class DragStartHelper {
+ ctor public DragStartHelper(android.view.View, androidx.core.view.DragStartHelper.OnDragStartListener);
+ method public void attach();
+ method public void detach();
+ method public void getTouchPosition(android.graphics.Point);
+ method public boolean onLongClick(android.view.View);
+ method public boolean onTouch(android.view.View, android.view.MotionEvent);
+ }
+
+ public static interface DragStartHelper.OnDragStartListener {
+ method public boolean onDragStart(android.view.View, androidx.core.view.DragStartHelper);
+ }
+
+ public final class GestureDetectorCompat {
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener);
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler?);
+ method public boolean isLongpressEnabled();
+ method public boolean onTouchEvent(android.view.MotionEvent);
+ method public void setIsLongpressEnabled(boolean);
+ method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener?);
+ }
+
+ public final class GravityCompat {
+ method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect, int);
+ method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static int getAbsoluteGravity(int, int);
+ field public static final int END = 8388613; // 0x800005
+ field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+ field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+ field public static final int START = 8388611; // 0x800003
+ }
+
+ public final class HapticFeedbackConstantsCompat {
+ field public static final int CLOCK_TICK = 4; // 0x4
+ field public static final int CONFIRM = 16; // 0x10
+ field public static final int CONTEXT_CLICK = 6; // 0x6
+ field public static final int DRAG_START = 25; // 0x19
+ field public static final int FLAG_IGNORE_VIEW_SETTING = 1; // 0x1
+ field public static final int GESTURE_END = 13; // 0xd
+ field public static final int GESTURE_START = 12; // 0xc
+ field public static final int GESTURE_THRESHOLD_ACTIVATE = 23; // 0x17
+ field public static final int GESTURE_THRESHOLD_DEACTIVATE = 24; // 0x18
+ field public static final int KEYBOARD_PRESS = 3; // 0x3
+ field public static final int KEYBOARD_RELEASE = 7; // 0x7
+ field public static final int KEYBOARD_TAP = 3; // 0x3
+ field public static final int LONG_PRESS = 0; // 0x0
+ field public static final int NO_HAPTICS = -1; // 0xffffffff
+ field public static final int REJECT = 17; // 0x11
+ field public static final int SEGMENT_FREQUENT_TICK = 27; // 0x1b
+ field public static final int SEGMENT_TICK = 26; // 0x1a
+ field public static final int TEXT_HANDLE_MOVE = 9; // 0x9
+ field public static final int TOGGLE_OFF = 22; // 0x16
+ field public static final int TOGGLE_ON = 21; // 0x15
+ field public static final int VIRTUAL_KEY = 1; // 0x1
+ field public static final int VIRTUAL_KEY_RELEASE = 8; // 0x8
+ }
+
+ public final class InputDeviceCompat {
+ field public static final int SOURCE_ANY = -256; // 0xffffff00
+ field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+ field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+ field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+ field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+ field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+ field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+ field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+ field public static final int SOURCE_DPAD = 513; // 0x201
+ field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+ field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+ field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+ field public static final int SOURCE_KEYBOARD = 257; // 0x101
+ field public static final int SOURCE_MOUSE = 8194; // 0x2002
+ field public static final int SOURCE_ROTARY_ENCODER = 4194304; // 0x400000
+ field public static final int SOURCE_STYLUS = 16386; // 0x4002
+ field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+ field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+ field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+ field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+ field public static final int SOURCE_UNKNOWN = 0; // 0x0
+ }
+
+ public final class LayoutInflaterCompat {
+ method @Deprecated public static androidx.core.view.LayoutInflaterFactory! getFactory(android.view.LayoutInflater!);
+ method @Deprecated public static void setFactory(android.view.LayoutInflater, androidx.core.view.LayoutInflaterFactory);
+ method public static void setFactory2(android.view.LayoutInflater, android.view.LayoutInflater.Factory2);
+ }
+
+ @Deprecated public interface LayoutInflaterFactory {
+ method @Deprecated public android.view.View! onCreateView(android.view.View!, String!, android.content.Context!, android.util.AttributeSet!);
+ }
+
+ public final class MarginLayoutParamsCompat {
+ method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
+ method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
+ method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
+ }
+
+ public final class MenuCompat {
+ method public static void setGroupDividerEnabled(android.view.Menu, boolean);
+ method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+ }
+
+ public interface MenuHost {
+ method public void addMenuProvider(androidx.core.view.MenuProvider);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State);
+ method public void invalidateMenu();
+ method public void removeMenuProvider(androidx.core.view.MenuProvider);
+ }
+
+ public class MenuHostHelper {
+ ctor public MenuHostHelper(Runnable);
+ method public void addMenuProvider(androidx.core.view.MenuProvider);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State);
+ method public void onCreateMenu(android.view.Menu, android.view.MenuInflater);
+ method public void onMenuClosed(android.view.Menu);
+ method public boolean onMenuItemSelected(android.view.MenuItem);
+ method public void onPrepareMenu(android.view.Menu);
+ method public void removeMenuProvider(androidx.core.view.MenuProvider);
+ }
+
+ public final class MenuItemCompat {
+ method @Deprecated public static boolean collapseActionView(android.view.MenuItem!);
+ method @Deprecated public static boolean expandActionView(android.view.MenuItem!);
+ method public static androidx.core.view.ActionProvider? getActionProvider(android.view.MenuItem);
+ method @Deprecated public static android.view.View! getActionView(android.view.MenuItem!);
+ method public static int getAlphabeticModifiers(android.view.MenuItem);
+ method public static CharSequence? getContentDescription(android.view.MenuItem);
+ method public static android.content.res.ColorStateList? getIconTintList(android.view.MenuItem);
+ method public static android.graphics.PorterDuff.Mode? getIconTintMode(android.view.MenuItem);
+ method public static int getNumericModifiers(android.view.MenuItem);
+ method public static CharSequence? getTooltipText(android.view.MenuItem);
+ method @Deprecated public static boolean isActionViewExpanded(android.view.MenuItem!);
+ method public static android.view.MenuItem? setActionProvider(android.view.MenuItem, androidx.core.view.ActionProvider?);
+ method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
+ method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
+ method public static void setAlphabeticShortcut(android.view.MenuItem, char, int);
+ method public static void setContentDescription(android.view.MenuItem, CharSequence?);
+ method public static void setIconTintList(android.view.MenuItem, android.content.res.ColorStateList?);
+ method public static void setIconTintMode(android.view.MenuItem, android.graphics.PorterDuff.Mode?);
+ method public static void setNumericShortcut(android.view.MenuItem, char, int);
+ method @Deprecated public static android.view.MenuItem! setOnActionExpandListener(android.view.MenuItem!, androidx.core.view.MenuItemCompat.OnActionExpandListener!);
+ method public static void setShortcut(android.view.MenuItem, char, char, int, int);
+ method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+ method public static void setTooltipText(android.view.MenuItem, CharSequence?);
+ field @Deprecated public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+ field @Deprecated public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+ field @Deprecated public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+ field @Deprecated public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+ field @Deprecated public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+ }
+
+ @Deprecated public static interface MenuItemCompat.OnActionExpandListener {
+ method @Deprecated public boolean onMenuItemActionCollapse(android.view.MenuItem!);
+ method @Deprecated public boolean onMenuItemActionExpand(android.view.MenuItem!);
+ }
+
+ public interface MenuProvider {
+ method public void onCreateMenu(android.view.Menu, android.view.MenuInflater);
+ method public default void onMenuClosed(android.view.Menu);
+ method public boolean onMenuItemSelected(android.view.MenuItem);
+ method public default void onPrepareMenu(android.view.Menu);
+ }
+
+ public final class MotionEventCompat {
+ method @Deprecated public static int findPointerIndex(android.view.MotionEvent!, int);
+ method @Deprecated public static int getActionIndex(android.view.MotionEvent!);
+ method @Deprecated public static int getActionMasked(android.view.MotionEvent!);
+ method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int);
+ method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int, int);
+ method @Deprecated public static int getButtonState(android.view.MotionEvent!);
+ method @Deprecated public static int getPointerCount(android.view.MotionEvent!);
+ method @Deprecated public static int getPointerId(android.view.MotionEvent!, int);
+ method @Deprecated public static int getSource(android.view.MotionEvent!);
+ method @Deprecated public static float getX(android.view.MotionEvent!, int);
+ method @Deprecated public static float getY(android.view.MotionEvent!, int);
+ method public static boolean isFromSource(android.view.MotionEvent, int);
+ field @Deprecated public static final int ACTION_HOVER_ENTER = 9; // 0x9
+ field @Deprecated public static final int ACTION_HOVER_EXIT = 10; // 0xa
+ field @Deprecated public static final int ACTION_HOVER_MOVE = 7; // 0x7
+ field @Deprecated public static final int ACTION_MASK = 255; // 0xff
+ field @Deprecated public static final int ACTION_POINTER_DOWN = 5; // 0x5
+ field @Deprecated public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+ field @Deprecated public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+ field @Deprecated public static final int ACTION_POINTER_UP = 6; // 0x6
+ field @Deprecated public static final int ACTION_SCROLL = 8; // 0x8
+ field @Deprecated public static final int AXIS_BRAKE = 23; // 0x17
+ field @Deprecated public static final int AXIS_DISTANCE = 24; // 0x18
+ field @Deprecated public static final int AXIS_GAS = 22; // 0x16
+ field @Deprecated public static final int AXIS_GENERIC_1 = 32; // 0x20
+ field @Deprecated public static final int AXIS_GENERIC_10 = 41; // 0x29
+ field @Deprecated public static final int AXIS_GENERIC_11 = 42; // 0x2a
+ field @Deprecated public static final int AXIS_GENERIC_12 = 43; // 0x2b
+ field @Deprecated public static final int AXIS_GENERIC_13 = 44; // 0x2c
+ field @Deprecated public static final int AXIS_GENERIC_14 = 45; // 0x2d
+ field @Deprecated public static final int AXIS_GENERIC_15 = 46; // 0x2e
+ field @Deprecated public static final int AXIS_GENERIC_16 = 47; // 0x2f
+ field @Deprecated public static final int AXIS_GENERIC_2 = 33; // 0x21
+ field @Deprecated public static final int AXIS_GENERIC_3 = 34; // 0x22
+ field @Deprecated public static final int AXIS_GENERIC_4 = 35; // 0x23
+ field @Deprecated public static final int AXIS_GENERIC_5 = 36; // 0x24
+ field @Deprecated public static final int AXIS_GENERIC_6 = 37; // 0x25
+ field @Deprecated public static final int AXIS_GENERIC_7 = 38; // 0x26
+ field @Deprecated public static final int AXIS_GENERIC_8 = 39; // 0x27
+ field @Deprecated public static final int AXIS_GENERIC_9 = 40; // 0x28
+ field @Deprecated public static final int AXIS_HAT_X = 15; // 0xf
+ field @Deprecated public static final int AXIS_HAT_Y = 16; // 0x10
+ field @Deprecated public static final int AXIS_HSCROLL = 10; // 0xa
+ field @Deprecated public static final int AXIS_LTRIGGER = 17; // 0x11
+ field @Deprecated public static final int AXIS_ORIENTATION = 8; // 0x8
+ field @Deprecated public static final int AXIS_PRESSURE = 2; // 0x2
+ field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+ field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
+ field @Deprecated public static final int AXIS_RTRIGGER = 18; // 0x12
+ field @Deprecated public static final int AXIS_RUDDER = 20; // 0x14
+ field @Deprecated public static final int AXIS_RX = 12; // 0xc
+ field @Deprecated public static final int AXIS_RY = 13; // 0xd
+ field @Deprecated public static final int AXIS_RZ = 14; // 0xe
+ field public static final int AXIS_SCROLL = 26; // 0x1a
+ field @Deprecated public static final int AXIS_SIZE = 3; // 0x3
+ field @Deprecated public static final int AXIS_THROTTLE = 19; // 0x13
+ field @Deprecated public static final int AXIS_TILT = 25; // 0x19
+ field @Deprecated public static final int AXIS_TOOL_MAJOR = 6; // 0x6
+ field @Deprecated public static final int AXIS_TOOL_MINOR = 7; // 0x7
+ field @Deprecated public static final int AXIS_TOUCH_MAJOR = 4; // 0x4
+ field @Deprecated public static final int AXIS_TOUCH_MINOR = 5; // 0x5
+ field @Deprecated public static final int AXIS_VSCROLL = 9; // 0x9
+ field @Deprecated public static final int AXIS_WHEEL = 21; // 0x15
+ field @Deprecated public static final int AXIS_X = 0; // 0x0
+ field @Deprecated public static final int AXIS_Y = 1; // 0x1
+ field @Deprecated public static final int AXIS_Z = 11; // 0xb
+ field @Deprecated public static final int BUTTON_PRIMARY = 1; // 0x1
+ }
+
+ public interface NestedScrollingChild {
+ method public boolean dispatchNestedFling(float, float, boolean);
+ method public boolean dispatchNestedPreFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+ method public boolean hasNestedScrollingParent();
+ method public boolean isNestedScrollingEnabled();
+ method public void setNestedScrollingEnabled(boolean);
+ method public boolean startNestedScroll(int);
+ method public void stopNestedScroll();
+ }
+
+ public interface NestedScrollingChild2 extends androidx.core.view.NestedScrollingChild {
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+ method public boolean hasNestedScrollingParent(int);
+ method public boolean startNestedScroll(int, int);
+ method public void stopNestedScroll(int);
+ }
+
+ public interface NestedScrollingChild3 extends androidx.core.view.NestedScrollingChild2 {
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+ }
+
+ public class NestedScrollingChildHelper {
+ ctor public NestedScrollingChildHelper(android.view.View);
+ method public boolean dispatchNestedFling(float, float, boolean);
+ method public boolean dispatchNestedPreFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]?);
+ method public boolean hasNestedScrollingParent();
+ method public boolean hasNestedScrollingParent(int);
+ method public boolean isNestedScrollingEnabled();
+ method public void onDetachedFromWindow();
+ method public void onStopNestedScroll(android.view.View);
+ method public void setNestedScrollingEnabled(boolean);
+ method public boolean startNestedScroll(int);
+ method public boolean startNestedScroll(int, int);
+ method public void stopNestedScroll();
+ method public void stopNestedScroll(int);
+ }
+
+ public interface NestedScrollingParent {
+ method public int getNestedScrollAxes();
+ method public boolean onNestedFling(android.view.View, float, float, boolean);
+ method public boolean onNestedPreFling(android.view.View, float, float);
+ method public void onNestedPreScroll(android.view.View, int, int, int[]);
+ method public void onNestedScroll(android.view.View, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int);
+ method public void onStopNestedScroll(android.view.View);
+ }
+
+ public interface NestedScrollingParent2 extends androidx.core.view.NestedScrollingParent {
+ method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View, int);
+ }
+
+ public interface NestedScrollingParent3 extends androidx.core.view.NestedScrollingParent2 {
+ method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+ }
+
+ public class NestedScrollingParentHelper {
+ ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+ method public int getNestedScrollAxes();
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View);
+ method public void onStopNestedScroll(android.view.View, int);
+ }
+
+ public interface OnApplyWindowInsetsListener {
+ method public androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ }
+
+ public interface OnReceiveContentListener {
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ }
+
+ public interface OnReceiveContentViewBehavior {
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(androidx.core.view.ContentInfoCompat);
+ }
+
+ public final class OneShotPreDrawListener implements android.view.View.OnAttachStateChangeListener android.view.ViewTreeObserver.OnPreDrawListener {
+ method public static androidx.core.view.OneShotPreDrawListener add(android.view.View, Runnable);
+ method public boolean onPreDraw();
+ method public void onViewAttachedToWindow(android.view.View);
+ method public void onViewDetachedFromWindow(android.view.View);
+ method public void removeListener();
+ }
+
+ public final class PointerIconCompat {
+ method public static androidx.core.view.PointerIconCompat create(android.graphics.Bitmap, float, float);
+ method public static androidx.core.view.PointerIconCompat getSystemIcon(android.content.Context, int);
+ method public static androidx.core.view.PointerIconCompat load(android.content.res.Resources, int);
+ field public static final int TYPE_ALIAS = 1010; // 0x3f2
+ field public static final int TYPE_ALL_SCROLL = 1013; // 0x3f5
+ field public static final int TYPE_ARROW = 1000; // 0x3e8
+ field public static final int TYPE_CELL = 1006; // 0x3ee
+ field public static final int TYPE_CONTEXT_MENU = 1001; // 0x3e9
+ field public static final int TYPE_COPY = 1011; // 0x3f3
+ field public static final int TYPE_CROSSHAIR = 1007; // 0x3ef
+ field public static final int TYPE_DEFAULT = 1000; // 0x3e8
+ field public static final int TYPE_GRAB = 1020; // 0x3fc
+ field public static final int TYPE_GRABBING = 1021; // 0x3fd
+ field public static final int TYPE_HAND = 1002; // 0x3ea
+ field public static final int TYPE_HELP = 1003; // 0x3eb
+ field public static final int TYPE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+ field public static final int TYPE_NO_DROP = 1012; // 0x3f4
+ field public static final int TYPE_NULL = 0; // 0x0
+ field public static final int TYPE_TEXT = 1008; // 0x3f0
+ field public static final int TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+ field public static final int TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+ field public static final int TYPE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+ field public static final int TYPE_VERTICAL_TEXT = 1009; // 0x3f1
+ field public static final int TYPE_WAIT = 1004; // 0x3ec
+ field public static final int TYPE_ZOOM_IN = 1018; // 0x3fa
+ field public static final int TYPE_ZOOM_OUT = 1019; // 0x3fb
+ }
+
+ public final class ScaleGestureDetectorCompat {
+ method public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector);
+ method @Deprecated public static boolean isQuickScaleEnabled(Object!);
+ method public static void setQuickScaleEnabled(android.view.ScaleGestureDetector, boolean);
+ method @Deprecated public static void setQuickScaleEnabled(Object!, boolean);
+ }
+
+ public interface ScrollingView {
+ method public int computeHorizontalScrollExtent();
+ method public int computeHorizontalScrollOffset();
+ method public int computeHorizontalScrollRange();
+ method public int computeVerticalScrollExtent();
+ method public int computeVerticalScrollOffset();
+ method public int computeVerticalScrollRange();
+ }
+
+ public final class SoftwareKeyboardControllerCompat {
+ ctor public SoftwareKeyboardControllerCompat(android.view.View);
+ method public void hide();
+ method public void show();
+ }
+
+ public interface TintableBackgroundView {
+ method public android.content.res.ColorStateList? getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportBackgroundTintMode();
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList?);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ @Deprecated public final class VelocityTrackerCompat {
+ method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
+ method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+ }
+
+ public class ViewCompat {
+ ctor @Deprecated protected ViewCompat();
+ method public static int addAccessibilityAction(android.view.View, CharSequence, androidx.core.view.accessibility.AccessibilityViewCommand);
+ method public static void addKeyboardNavigationClusters(android.view.View, java.util.Collection<android.view.View!>, int);
+ method public static void addOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+ method public static androidx.core.view.ViewPropertyAnimatorCompat animate(android.view.View);
+ method @Deprecated public static boolean canScrollHorizontally(android.view.View!, int);
+ method @Deprecated public static boolean canScrollVertically(android.view.View!, int);
+ method public static void cancelDragAndDrop(android.view.View);
+ method @Deprecated public static int combineMeasuredStates(int, int);
+ method public static androidx.core.view.WindowInsetsCompat computeSystemWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat, android.graphics.Rect);
+ method public static androidx.core.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ method public static void dispatchFinishTemporaryDetach(android.view.View);
+ method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+ method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+ method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?);
+ method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?, int);
+ method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?);
+ method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, int);
+ method public static void dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, int, int[]);
+ method public static void dispatchStartTemporaryDetach(android.view.View);
+ method public static void enableAccessibleClickableSpanSupport(android.view.View);
+ method public static int generateViewId();
+ method public static androidx.core.view.AccessibilityDelegateCompat? getAccessibilityDelegate(android.view.View);
+ method public static int getAccessibilityLiveRegion(android.view.View);
+ method public static androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
+ method @UiThread public static CharSequence? getAccessibilityPaneTitle(android.view.View);
+ method @Deprecated public static float getAlpha(android.view.View!);
+ method public static androidx.core.view.autofill.AutofillIdCompat? getAutofillId(android.view.View);
+ method public static android.content.res.ColorStateList? getBackgroundTintList(android.view.View);
+ method public static android.graphics.PorterDuff.Mode? getBackgroundTintMode(android.view.View);
+ method public static android.graphics.Rect? getClipBounds(android.view.View);
+ method public static androidx.core.view.contentcapture.ContentCaptureSessionCompat? getContentCaptureSession(android.view.View);
+ method public static android.view.Display? getDisplay(android.view.View);
+ method public static float getElevation(android.view.View);
+ method public static boolean getFitsSystemWindows(android.view.View);
+ method public static int getImportantForAccessibility(android.view.View);
+ method public static int getImportantForAutofill(android.view.View);
+ method public static int getImportantForContentCapture(android.view.View);
+ method public static int getLabelFor(android.view.View);
+ method @Deprecated public static int getLayerType(android.view.View!);
+ method public static int getLayoutDirection(android.view.View);
+ method @Deprecated public static android.graphics.Matrix? getMatrix(android.view.View!);
+ method @Deprecated public static int getMeasuredHeightAndState(android.view.View!);
+ method @Deprecated public static int getMeasuredState(android.view.View!);
+ method @Deprecated public static int getMeasuredWidthAndState(android.view.View!);
+ method public static int getMinimumHeight(android.view.View);
+ method public static int getMinimumWidth(android.view.View);
+ method public static int getNextClusterForwardId(android.view.View);
+ method public static String![]? getOnReceiveContentMimeTypes(android.view.View);
+ method @Deprecated public static int getOverScrollMode(android.view.View!);
+ method @Px public static int getPaddingEnd(android.view.View);
+ method @Px public static int getPaddingStart(android.view.View);
+ method public static android.view.ViewParent? getParentForAccessibility(android.view.View);
+ method @Deprecated public static float getPivotX(android.view.View!);
+ method @Deprecated public static float getPivotY(android.view.View!);
+ method public static androidx.core.view.WindowInsetsCompat? getRootWindowInsets(android.view.View);
+ method @Deprecated public static float getRotation(android.view.View!);
+ method @Deprecated public static float getRotationX(android.view.View!);
+ method @Deprecated public static float getRotationY(android.view.View!);
+ method @Deprecated public static float getScaleX(android.view.View!);
+ method @Deprecated public static float getScaleY(android.view.View!);
+ method public static int getScrollIndicators(android.view.View);
+ method @UiThread public static CharSequence? getStateDescription(android.view.View);
+ method public static java.util.List<android.graphics.Rect!> getSystemGestureExclusionRects(android.view.View);
+ method public static String? getTransitionName(android.view.View);
+ method @Deprecated public static float getTranslationX(android.view.View!);
+ method @Deprecated public static float getTranslationY(android.view.View!);
+ method public static float getTranslationZ(android.view.View);
+ method @Deprecated public static androidx.core.view.WindowInsetsControllerCompat? getWindowInsetsController(android.view.View);
+ method @Deprecated public static int getWindowSystemUiVisibility(android.view.View);
+ method @Deprecated public static float getX(android.view.View!);
+ method @Deprecated public static float getY(android.view.View!);
+ method public static float getZ(android.view.View);
+ method public static boolean hasAccessibilityDelegate(android.view.View);
+ method public static boolean hasExplicitFocusable(android.view.View);
+ method public static boolean hasNestedScrollingParent(android.view.View);
+ method public static boolean hasNestedScrollingParent(android.view.View, int);
+ method public static boolean hasOnClickListeners(android.view.View);
+ method public static boolean hasOverlappingRendering(android.view.View);
+ method public static boolean hasTransientState(android.view.View);
+ method @UiThread public static boolean isAccessibilityHeading(android.view.View);
+ method public static boolean isAttachedToWindow(android.view.View);
+ method public static boolean isFocusedByDefault(android.view.View);
+ method public static boolean isImportantForAccessibility(android.view.View);
+ method public static boolean isImportantForAutofill(android.view.View);
+ method public static boolean isImportantForContentCapture(android.view.View);
+ method public static boolean isInLayout(android.view.View);
+ method public static boolean isKeyboardNavigationCluster(android.view.View);
+ method public static boolean isLaidOut(android.view.View);
+ method public static boolean isLayoutDirectionResolved(android.view.View);
+ method public static boolean isNestedScrollingEnabled(android.view.View);
+ method @Deprecated public static boolean isOpaque(android.view.View!);
+ method public static boolean isPaddingRelative(android.view.View);
+ method @UiThread public static boolean isScreenReaderFocusable(android.view.View);
+ method @Deprecated public static void jumpDrawablesToCurrentState(android.view.View!);
+ method public static android.view.View? keyboardNavigationClusterSearch(android.view.View, android.view.View?, int);
+ method public static void offsetLeftAndRight(android.view.View, int);
+ method public static void offsetTopAndBottom(android.view.View, int);
+ method public static androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ method @Deprecated public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+ method @Deprecated public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+ method public static boolean performHapticFeedback(android.view.View, int);
+ method public static boolean performHapticFeedback(android.view.View, int, int);
+ method public static androidx.core.view.ContentInfoCompat? performReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ method public static void postInvalidateOnAnimation(android.view.View);
+ method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+ method public static void postOnAnimation(android.view.View, Runnable);
+ method public static void postOnAnimationDelayed(android.view.View, Runnable, long);
+ method public static void removeAccessibilityAction(android.view.View, int);
+ method public static void removeOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+ method public static void replaceAccessibilityAction(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat, CharSequence?, androidx.core.view.accessibility.AccessibilityViewCommand?);
+ method public static void requestApplyInsets(android.view.View);
+ method public static <T extends android.view.View> T requireViewById(android.view.View, @IdRes int);
+ method @Deprecated public static int resolveSizeAndState(int, int, int);
+ method public static boolean restoreDefaultFocus(android.view.View);
+ method public static void saveAttributeDataForStyleable(android.view.View, android.content.Context, int[], android.util.AttributeSet?, android.content.res.TypedArray, int, int);
+ method public static void setAccessibilityDelegate(android.view.View, androidx.core.view.AccessibilityDelegateCompat?);
+ method @UiThread public static void setAccessibilityHeading(android.view.View, boolean);
+ method public static void setAccessibilityLiveRegion(android.view.View, int);
+ method @UiThread public static void setAccessibilityPaneTitle(android.view.View, CharSequence?);
+ method @Deprecated public static void setActivated(android.view.View!, boolean);
+ method @Deprecated public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
+ method public static void setAutofillHints(android.view.View, java.lang.String!...);
+ method public static void setAutofillId(android.view.View, androidx.core.view.autofill.AutofillIdCompat?);
+ method public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
+ method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList?);
+ method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode?);
+ method @Deprecated public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup!, boolean);
+ method public static void setClipBounds(android.view.View, android.graphics.Rect?);
+ method public static void setContentCaptureSession(android.view.View, androidx.core.view.contentcapture.ContentCaptureSessionCompat?);
+ method public static void setElevation(android.view.View, float);
+ method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
+ method public static void setFocusedByDefault(android.view.View, boolean);
+ method public static void setHasTransientState(android.view.View, boolean);
+ method @UiThread public static void setImportantForAccessibility(android.view.View, int);
+ method public static void setImportantForAutofill(android.view.View, int);
+ method public static void setImportantForContentCapture(android.view.View, int);
+ method public static void setKeyboardNavigationCluster(android.view.View, boolean);
+ method public static void setLabelFor(android.view.View, @IdRes int);
+ method public static void setLayerPaint(android.view.View, android.graphics.Paint?);
+ method @Deprecated public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
+ method public static void setLayoutDirection(android.view.View, int);
+ method public static void setNestedScrollingEnabled(android.view.View, boolean);
+ method public static void setNextClusterForwardId(android.view.View, int);
+ method public static void setOnApplyWindowInsetsListener(android.view.View, androidx.core.view.OnApplyWindowInsetsListener?);
+ method public static void setOnReceiveContentListener(android.view.View, String![]?, androidx.core.view.OnReceiveContentListener?);
+ method @Deprecated public static void setOverScrollMode(android.view.View!, int);
+ method public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
+ method @Deprecated public static void setPivotX(android.view.View!, float);
+ method @Deprecated public static void setPivotY(android.view.View!, float);
+ method public static void setPointerIcon(android.view.View, androidx.core.view.PointerIconCompat?);
+ method @Deprecated public static void setRotation(android.view.View!, float);
+ method @Deprecated public static void setRotationX(android.view.View!, float);
+ method @Deprecated public static void setRotationY(android.view.View!, float);
+ method @Deprecated public static void setSaveFromParentEnabled(android.view.View!, boolean);
+ method @Deprecated public static void setScaleX(android.view.View!, float);
+ method @Deprecated public static void setScaleY(android.view.View!, float);
+ method @UiThread public static void setScreenReaderFocusable(android.view.View, boolean);
+ method public static void setScrollIndicators(android.view.View, int);
+ method public static void setScrollIndicators(android.view.View, int, int);
+ method @UiThread public static void setStateDescription(android.view.View, CharSequence?);
+ method public static void setSystemGestureExclusionRects(android.view.View, java.util.List<android.graphics.Rect!>);
+ method public static void setTooltipText(android.view.View, CharSequence?);
+ method public static void setTransitionName(android.view.View, String?);
+ method @Deprecated public static void setTranslationX(android.view.View!, float);
+ method @Deprecated public static void setTranslationY(android.view.View!, float);
+ method public static void setTranslationZ(android.view.View, float);
+ method public static void setWindowInsetsAnimationCallback(android.view.View, androidx.core.view.WindowInsetsAnimationCompat.Callback?);
+ method @Deprecated public static void setX(android.view.View!, float);
+ method @Deprecated public static void setY(android.view.View!, float);
+ method public static void setZ(android.view.View, float);
+ method public static boolean startDragAndDrop(android.view.View, android.content.ClipData?, android.view.View.DragShadowBuilder, Object?, int);
+ method public static boolean startNestedScroll(android.view.View, int);
+ method public static boolean startNestedScroll(android.view.View, int, int);
+ method public static void stopNestedScroll(android.view.View);
+ method public static void stopNestedScroll(android.view.View, int);
+ method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder);
+ field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+ field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+ field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+ field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0; // 0x0
+ field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 2; // 0x2
+ field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 8; // 0x8
+ field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 1; // 0x1
+ field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 4; // 0x4
+ field @Deprecated public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+ field @Deprecated public static final int LAYER_TYPE_NONE = 0; // 0x0
+ field @Deprecated public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+ field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+ field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+ field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+ field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+ field @Deprecated public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+ field @Deprecated public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+ field @Deprecated public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
+ field @Deprecated public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+ field @Deprecated public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
+ field @Deprecated public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+ field @Deprecated public static final int OVER_SCROLL_NEVER = 2; // 0x2
+ field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+ field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+ field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+ field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+ field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+ field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+ field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+ field public static final int TYPE_NON_TOUCH = 1; // 0x1
+ field public static final int TYPE_TOUCH = 0; // 0x0
+ }
+
+ public static interface ViewCompat.OnUnhandledKeyEventListenerCompat {
+ method public boolean onUnhandledKeyEvent(android.view.View, android.view.KeyEvent);
+ }
+
+ public final class ViewConfigurationCompat {
+ method public static float getScaledHorizontalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+ method public static int getScaledHoverSlop(android.view.ViewConfiguration);
+ method @Deprecated public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
+ method public static float getScaledVerticalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+ method @Deprecated public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
+ method public static boolean shouldShowMenuShortcutsWhenKeyboardPresent(android.view.ViewConfiguration, android.content.Context);
+ }
+
+ public final class ViewGroupCompat {
+ method public static int getLayoutMode(android.view.ViewGroup);
+ method public static int getNestedScrollAxes(android.view.ViewGroup);
+ method public static boolean isTransitionGroup(android.view.ViewGroup);
+ method @Deprecated public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static void setLayoutMode(android.view.ViewGroup, int);
+ method @Deprecated public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
+ method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+ field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+ field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+ }
+
+ public final class ViewParentCompat {
+ method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onNestedFling(android.view.ViewParent, android.view.View, float, float, boolean);
+ method public static boolean onNestedPreFling(android.view.ViewParent, android.view.View, float, float);
+ method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[]);
+ method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[], int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int, int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int, int, int[]);
+ method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int, int);
+ method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int, int);
+ method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
+ method public static void onStopNestedScroll(android.view.ViewParent, android.view.View, int);
+ method @Deprecated public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ }
+
+ public final class ViewPropertyAnimatorCompat {
+ method public androidx.core.view.ViewPropertyAnimatorCompat alpha(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat alphaBy(float);
+ method public void cancel();
+ method public long getDuration();
+ method public android.view.animation.Interpolator? getInterpolator();
+ method public long getStartDelay();
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotation(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setDuration(long);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setInterpolator(android.view.animation.Interpolator?);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setListener(androidx.core.view.ViewPropertyAnimatorListener?);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setStartDelay(long);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setUpdateListener(androidx.core.view.ViewPropertyAnimatorUpdateListener?);
+ method public void start();
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationZ(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationZBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat withEndAction(Runnable);
+ method public androidx.core.view.ViewPropertyAnimatorCompat withLayer();
+ method public androidx.core.view.ViewPropertyAnimatorCompat withStartAction(Runnable);
+ method public androidx.core.view.ViewPropertyAnimatorCompat x(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat xBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat y(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat yBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat z(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat zBy(float);
+ }
+
+ public interface ViewPropertyAnimatorListener {
+ method public void onAnimationCancel(android.view.View);
+ method public void onAnimationEnd(android.view.View);
+ method public void onAnimationStart(android.view.View);
+ }
+
+ public class ViewPropertyAnimatorListenerAdapter implements androidx.core.view.ViewPropertyAnimatorListener {
+ ctor public ViewPropertyAnimatorListenerAdapter();
+ method public void onAnimationCancel(android.view.View);
+ method public void onAnimationEnd(android.view.View);
+ method public void onAnimationStart(android.view.View);
+ }
+
+ public interface ViewPropertyAnimatorUpdateListener {
+ method public void onAnimationUpdate(android.view.View);
+ }
+
+ public class ViewStructureCompat {
+ method public void setClassName(String);
+ method public void setContentDescription(CharSequence);
+ method public void setDimens(int, int, int, int, int, int);
+ method public void setText(CharSequence);
+ method @RequiresApi(23) public android.view.ViewStructure toViewStructure();
+ method @RequiresApi(23) public static androidx.core.view.ViewStructureCompat toViewStructureCompat(android.view.ViewStructure);
+ }
+
+ public final class WindowCompat {
+ method public static androidx.core.view.WindowInsetsControllerCompat getInsetsController(android.view.Window, android.view.View);
+ method public static <T extends android.view.View> T requireViewById(android.view.Window, @IdRes int);
+ method public static void setDecorFitsSystemWindows(android.view.Window, boolean);
+ field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+ field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+ field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+ }
+
+ public final class WindowInsetsAnimationCompat {
+ ctor public WindowInsetsAnimationCompat(int, android.view.animation.Interpolator?, long);
+ method @FloatRange(from=0.0f, to=1.0f) public float getAlpha();
+ method public long getDurationMillis();
+ method @FloatRange(from=0.0f, to=1.0f) public float getFraction();
+ method public float getInterpolatedFraction();
+ method public android.view.animation.Interpolator? getInterpolator();
+ method public int getTypeMask();
+ method public void setAlpha(@FloatRange(from=0.0f, to=1.0f) float);
+ method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float);
+ }
+
+ public static final class WindowInsetsAnimationCompat.BoundsCompat {
+ ctor public WindowInsetsAnimationCompat.BoundsCompat(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public androidx.core.graphics.Insets getLowerBound();
+ method public androidx.core.graphics.Insets getUpperBound();
+ method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat inset(androidx.core.graphics.Insets);
+ method @RequiresApi(30) public android.view.WindowInsetsAnimation.Bounds toBounds();
+ method @RequiresApi(30) public static androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat toBoundsCompat(android.view.WindowInsetsAnimation.Bounds);
+ }
+
+ public abstract static class WindowInsetsAnimationCompat.Callback {
+ ctor public WindowInsetsAnimationCompat.Callback(int);
+ method public final int getDispatchMode();
+ method public void onEnd(androidx.core.view.WindowInsetsAnimationCompat);
+ method public void onPrepare(androidx.core.view.WindowInsetsAnimationCompat);
+ method public abstract androidx.core.view.WindowInsetsCompat onProgress(androidx.core.view.WindowInsetsCompat, java.util.List<androidx.core.view.WindowInsetsAnimationCompat!>);
+ method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat onStart(androidx.core.view.WindowInsetsAnimationCompat, androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat);
+ field public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; // 0x1
+ field public static final int DISPATCH_MODE_STOP = 0; // 0x0
+ }
+
+ public interface WindowInsetsAnimationControlListenerCompat {
+ method public void onCancelled(androidx.core.view.WindowInsetsAnimationControllerCompat?);
+ method public void onFinished(androidx.core.view.WindowInsetsAnimationControllerCompat);
+ method public void onReady(androidx.core.view.WindowInsetsAnimationControllerCompat, int);
+ }
+
+ public final class WindowInsetsAnimationControllerCompat {
+ method public void finish(boolean);
+ method public float getCurrentAlpha();
+ method @FloatRange(from=0.0f, to=1.0f) public float getCurrentFraction();
+ method public androidx.core.graphics.Insets getCurrentInsets();
+ method public androidx.core.graphics.Insets getHiddenStateInsets();
+ method public androidx.core.graphics.Insets getShownStateInsets();
+ method public int getTypes();
+ method public boolean isCancelled();
+ method public boolean isFinished();
+ method public boolean isReady();
+ method public void setInsetsAndAlpha(androidx.core.graphics.Insets?, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+ }
+
+ public class WindowInsetsCompat {
+ ctor public WindowInsetsCompat(androidx.core.view.WindowInsetsCompat?);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeDisplayCutout();
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeStableInsets();
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeSystemWindowInsets();
+ method public androidx.core.view.DisplayCutoutCompat? getDisplayCutout();
+ method public androidx.core.graphics.Insets getInsets(int);
+ method public androidx.core.graphics.Insets getInsetsIgnoringVisibility(int);
+ method @Deprecated public androidx.core.graphics.Insets getMandatorySystemGestureInsets();
+ method @Deprecated public int getStableInsetBottom();
+ method @Deprecated public int getStableInsetLeft();
+ method @Deprecated public int getStableInsetRight();
+ method @Deprecated public int getStableInsetTop();
+ method @Deprecated public androidx.core.graphics.Insets getStableInsets();
+ method @Deprecated public androidx.core.graphics.Insets getSystemGestureInsets();
+ method @Deprecated public int getSystemWindowInsetBottom();
+ method @Deprecated public int getSystemWindowInsetLeft();
+ method @Deprecated public int getSystemWindowInsetRight();
+ method @Deprecated public int getSystemWindowInsetTop();
+ method @Deprecated public androidx.core.graphics.Insets getSystemWindowInsets();
+ method @Deprecated public androidx.core.graphics.Insets getTappableElementInsets();
+ method public boolean hasInsets();
+ method @Deprecated public boolean hasStableInsets();
+ method @Deprecated public boolean hasSystemWindowInsets();
+ method public androidx.core.view.WindowInsetsCompat inset(androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+ method public boolean isConsumed();
+ method public boolean isRound();
+ method public boolean isVisible(int);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+ method @RequiresApi(20) public android.view.WindowInsets? toWindowInsets();
+ method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets);
+ method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets, android.view.View?);
+ field public static final androidx.core.view.WindowInsetsCompat CONSUMED;
+ }
+
+ public static final class WindowInsetsCompat.Builder {
+ ctor public WindowInsetsCompat.Builder();
+ ctor public WindowInsetsCompat.Builder(androidx.core.view.WindowInsetsCompat);
+ method public androidx.core.view.WindowInsetsCompat build();
+ method public androidx.core.view.WindowInsetsCompat.Builder setDisplayCutout(androidx.core.view.DisplayCutoutCompat?);
+ method public androidx.core.view.WindowInsetsCompat.Builder setInsets(int, androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat.Builder setInsetsIgnoringVisibility(int, androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setMandatorySystemGestureInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setStableInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemGestureInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemWindowInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setTappableElementInsets(androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat.Builder setVisible(int, boolean);
+ }
+
+ public static final class WindowInsetsCompat.Type {
+ method public static int captionBar();
+ method public static int displayCutout();
+ method public static int ime();
+ method public static int mandatorySystemGestures();
+ method public static int navigationBars();
+ method public static int statusBars();
+ method public static int systemBars();
+ method public static int systemGestures();
+ method public static int tappableElement();
+ }
+
+ public final class WindowInsetsControllerCompat {
+ ctor public WindowInsetsControllerCompat(android.view.Window, android.view.View);
+ method public void addOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+ method public void controlWindowInsetsAnimation(int, long, android.view.animation.Interpolator?, android.os.CancellationSignal?, androidx.core.view.WindowInsetsAnimationControlListenerCompat);
+ method public int getSystemBarsBehavior();
+ method public void hide(int);
+ method public boolean isAppearanceLightNavigationBars();
+ method public boolean isAppearanceLightStatusBars();
+ method public void removeOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+ method public void setAppearanceLightNavigationBars(boolean);
+ method public void setAppearanceLightStatusBars(boolean);
+ method public void setSystemBarsBehavior(int);
+ method public void show(int);
+ method @Deprecated @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
+ field public static final int BEHAVIOR_DEFAULT = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
+ field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
+ }
+
+ public static interface WindowInsetsControllerCompat.OnControllableInsetsChangedListener {
+ method public void onControllableInsetsChanged(androidx.core.view.WindowInsetsControllerCompat, int);
+ }
+
+}
+
+package androidx.core.view.accessibility {
+
+ public final class AccessibilityClickableSpanCompat extends android.text.style.ClickableSpan {
+ method public void onClick(android.view.View);
+ }
+
+ public final class AccessibilityEventCompat {
+ method @Deprecated public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! asRecord(android.view.accessibility.AccessibilityEvent!);
+ method public static int getAction(android.view.accessibility.AccessibilityEvent);
+ method public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
+ method public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! getRecord(android.view.accessibility.AccessibilityEvent!, int);
+ method @Deprecated public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
+ method public static void setAction(android.view.accessibility.AccessibilityEvent, int);
+ method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, int);
+ method public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent, int);
+ field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 256; // 0x100
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 128; // 0x80
+ field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
+ field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
+ field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
+ field public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 64; // 0x40
+ field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+ field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+ field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+ field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+ field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
+ field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+ field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+ field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+ field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+ field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+ field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+ field public static final int TYPE_VIEW_CONTEXT_CLICKED = 8388608; // 0x800000
+ field @Deprecated public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+ field @Deprecated public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+ field @Deprecated public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+ field @Deprecated public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+ field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+ field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
+ field @Deprecated public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+ }
+
+ public final class AccessibilityManagerCompat {
+ method @Deprecated public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+ method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+ method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
+ method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
+ method @Deprecated public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
+ method @Deprecated public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+ method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+ }
+
+ @Deprecated public static interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
+ method @Deprecated public void onAccessibilityStateChanged(boolean);
+ }
+
+ @Deprecated public abstract static class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat implements androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener {
+ ctor @Deprecated public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+ }
+
+ public static interface AccessibilityManagerCompat.TouchExplorationStateChangeListener {
+ method public void onTouchExplorationStateChanged(boolean);
+ }
+
+ public class AccessibilityNodeInfoCompat {
+ ctor @Deprecated public AccessibilityNodeInfoCompat(Object!);
+ method public void addAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+ method public void addAction(int);
+ method public void addChild(android.view.View!);
+ method public void addChild(android.view.View!, int);
+ method public boolean canOpenPopup();
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByText(String!);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByViewId(String!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! findFocus(int);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! focusSearch(int);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!>! getActionList();
+ method @Deprecated public int getActions();
+ method public java.util.List<java.lang.String!> getAvailableExtraData();
+ method @Deprecated public void getBoundsInParent(android.graphics.Rect!);
+ method public void getBoundsInScreen(android.graphics.Rect!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getChild(int);
+ method public int getChildCount();
+ method public CharSequence! getClassName();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! getCollectionInfo();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! getCollectionItemInfo();
+ method public CharSequence! getContentDescription();
+ method public int getDrawingOrder();
+ method public CharSequence! getError();
+ method public android.view.accessibility.AccessibilityNodeInfo.ExtraRenderingInfo? getExtraRenderingInfo();
+ method public android.os.Bundle! getExtras();
+ method public CharSequence? getHintText();
+ method @Deprecated public Object! getInfo();
+ method public int getInputType();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabelFor();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabeledBy();
+ method public int getLiveRegion();
+ method public int getMaxTextLength();
+ method public long getMinDurationBetweenContentChangesMillis();
+ method public int getMovementGranularities();
+ method public CharSequence! getPackageName();
+ method public CharSequence? getPaneTitle();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getParent();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! getRangeInfo();
+ method public CharSequence? getRoleDescription();
+ method public CharSequence? getStateDescription();
+ method public CharSequence! getText();
+ method public int getTextSelectionEnd();
+ method public int getTextSelectionStart();
+ method public CharSequence? getTooltipText();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat? getTouchDelegateInfo();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalAfter();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalBefore();
+ method public String? getUniqueId();
+ method public String! getViewIdResourceName();
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getWindow();
+ method public int getWindowId();
+ method public boolean hasRequestInitialAccessibilityFocus();
+ method public boolean isAccessibilityFocused();
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isContentInvalid();
+ method public boolean isContextClickable();
+ method public boolean isDismissable();
+ method public boolean isEditable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isHeading();
+ method public boolean isImportantForAccessibility();
+ method public boolean isLongClickable();
+ method public boolean isMultiLine();
+ method public boolean isPassword();
+ method public boolean isScreenReaderFocusable();
+ method public boolean isScrollable();
+ method public boolean isSelected();
+ method public boolean isShowingHintText();
+ method public boolean isTextEntryKey();
+ method public boolean isTextSelectable();
+ method public boolean isVisibleToUser();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!, int);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+ method public boolean performAction(int);
+ method public boolean performAction(int, android.os.Bundle!);
+ method @Deprecated public void recycle();
+ method public boolean refresh();
+ method public boolean removeAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+ method public boolean removeChild(android.view.View!);
+ method public boolean removeChild(android.view.View!, int);
+ method public void setAccessibilityFocused(boolean);
+ method public void setAvailableExtraData(java.util.List<java.lang.String!>);
+ method @Deprecated public void setBoundsInParent(android.graphics.Rect!);
+ method public void setBoundsInScreen(android.graphics.Rect!);
+ method public void setCanOpenPopup(boolean);
+ method public void setCheckable(boolean);
+ method public void setChecked(boolean);
+ method public void setClassName(CharSequence!);
+ method public void setClickable(boolean);
+ method public void setCollectionInfo(Object!);
+ method public void setCollectionItemInfo(Object!);
+ method public void setContentDescription(CharSequence!);
+ method public void setContentInvalid(boolean);
+ method public void setContextClickable(boolean);
+ method public void setDismissable(boolean);
+ method public void setDrawingOrder(int);
+ method public void setEditable(boolean);
+ method public void setEnabled(boolean);
+ method public void setError(CharSequence!);
+ method public void setFocusable(boolean);
+ method public void setFocused(boolean);
+ method public void setHeading(boolean);
+ method public void setHintText(CharSequence?);
+ method public void setImportantForAccessibility(boolean);
+ method public void setInputType(int);
+ method public void setLabelFor(android.view.View!);
+ method public void setLabelFor(android.view.View!, int);
+ method public void setLabeledBy(android.view.View!);
+ method public void setLabeledBy(android.view.View!, int);
+ method public void setLiveRegion(int);
+ method public void setLongClickable(boolean);
+ method public void setMaxTextLength(int);
+ method public void setMinDurationBetweenContentChangesMillis(long);
+ method public void setMovementGranularities(int);
+ method public void setMultiLine(boolean);
+ method public void setPackageName(CharSequence!);
+ method public void setPaneTitle(CharSequence?);
+ method public void setParent(android.view.View!);
+ method public void setParent(android.view.View!, int);
+ method public void setPassword(boolean);
+ method public void setRangeInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat!);
+ method public void setRequestInitialAccessibilityFocus(boolean);
+ method public void setRoleDescription(CharSequence?);
+ method public void setScreenReaderFocusable(boolean);
+ method public void setScrollable(boolean);
+ method public void setSelected(boolean);
+ method public void setShowingHintText(boolean);
+ method public void setSource(android.view.View!);
+ method public void setSource(android.view.View!, int);
+ method public void setStateDescription(CharSequence?);
+ method public void setText(CharSequence!);
+ method public void setTextEntryKey(boolean);
+ method public void setTextSelectable(boolean);
+ method public void setTextSelection(int, int);
+ method public void setTooltipText(CharSequence?);
+ method public void setTouchDelegateInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat);
+ method public void setTraversalAfter(android.view.View!);
+ method public void setTraversalAfter(android.view.View!, int);
+ method public void setTraversalBefore(android.view.View!);
+ method public void setTraversalBefore(android.view.View!, int);
+ method public void setUniqueId(String?);
+ method public void setViewIdResourceName(String!);
+ method public void setVisibleToUser(boolean);
+ method public android.view.accessibility.AccessibilityNodeInfo! unwrap();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! wrap(android.view.accessibility.AccessibilityNodeInfo);
+ field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+ field public static final String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+ field public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+ field public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+ field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+ field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
+ field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+ field public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
+ field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
+ field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
+ field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+ field public static final String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+ field public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+ field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+ field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+ field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+ field public static final int ACTION_CLICK = 16; // 0x10
+ field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+ field public static final int ACTION_COPY = 16384; // 0x4000
+ field public static final int ACTION_CUT = 65536; // 0x10000
+ field public static final int ACTION_DISMISS = 1048576; // 0x100000
+ field public static final int ACTION_EXPAND = 262144; // 0x40000
+ field public static final int ACTION_FOCUS = 1; // 0x1
+ field public static final int ACTION_LONG_CLICK = 32; // 0x20
+ field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+ field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+ field public static final int ACTION_PASTE = 32768; // 0x8000
+ field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+ field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+ field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+ field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+ field public static final int ACTION_SELECT = 4; // 0x4
+ field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+ field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+ field public static final int EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH = 20000; // 0x4e20
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
+ field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+ field public static final int FOCUS_INPUT = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+ field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+ field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+ field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+ }
+
+ public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+ ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, CharSequence!);
+ method public int getId();
+ method public CharSequence! getLabel();
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_ACCESSIBILITY_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_SELECTION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COLLAPSE;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CONTEXT_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COPY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CUT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_DISMISS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_CANCEL;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_DROP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_START;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_EXPAND;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_HIDE_TOOLTIP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_IME_ENTER;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_LONG_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_MOVE_WINDOW;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_HTML_ELEMENT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_DOWN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_LEFT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_RIGHT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_UP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PASTE;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PRESS_AND_HOLD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_HTML_ELEMENT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_BACKWARD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_DOWN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_FORWARD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_LEFT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_RIGHT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_TO_POSITION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_UP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SELECT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_PROGRESS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_SELECTION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_TEXT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_ON_SCREEN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SHOW_TEXT_SUGGESTIONS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_TOOLTIP;
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+ method public int getColumnCount();
+ method public int getRowCount();
+ method public int getSelectionMode();
+ method public boolean isHierarchical();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean, int);
+ field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+ field public static final int SELECTION_MODE_NONE = 0; // 0x0
+ field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+ method public int getColumnIndex();
+ method public int getColumnSpan();
+ method public int getRowIndex();
+ method public int getRowSpan();
+ method @Deprecated public boolean isHeading();
+ method public boolean isSelected();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean, boolean);
+ }
+
+ public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+ method public float getCurrent();
+ method public float getMax();
+ method public float getMin();
+ method public int getType();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! obtain(int, float, float, float);
+ field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+ field public static final int RANGE_TYPE_INT = 0; // 0x0
+ field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+ }
+
+ public static final class AccessibilityNodeInfoCompat.TouchDelegateInfoCompat {
+ ctor public AccessibilityNodeInfoCompat.TouchDelegateInfoCompat(java.util.Map<android.graphics.Region!,android.view.View!>);
+ method public android.graphics.Region? getRegionAt(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getRegionCount();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getTargetForRegion(android.graphics.Region);
+ }
+
+ public class AccessibilityNodeProviderCompat {
+ ctor public AccessibilityNodeProviderCompat();
+ ctor public AccessibilityNodeProviderCompat(Object?);
+ method public void addExtraDataToAccessibilityNodeInfo(int, androidx.core.view.accessibility.AccessibilityNodeInfoCompat, String, android.os.Bundle?);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? createAccessibilityNodeInfo(int);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>? findAccessibilityNodeInfosByText(String, int);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? findFocus(int);
+ method public Object? getProvider();
+ method public boolean performAction(int, int, android.os.Bundle?);
+ field public static final int HOST_VIEW_ID = -1; // 0xffffffff
+ }
+
+ public class AccessibilityRecordCompat {
+ ctor @Deprecated public AccessibilityRecordCompat(Object!);
+ method @Deprecated public boolean equals(Object?);
+ method @Deprecated public int getAddedCount();
+ method @Deprecated public CharSequence! getBeforeText();
+ method @Deprecated public CharSequence! getClassName();
+ method @Deprecated public CharSequence! getContentDescription();
+ method @Deprecated public int getCurrentItemIndex();
+ method @Deprecated public int getFromIndex();
+ method @Deprecated public Object! getImpl();
+ method @Deprecated public int getItemCount();
+ method @Deprecated public int getMaxScrollX();
+ method public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord);
+ method @Deprecated public int getMaxScrollY();
+ method public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord);
+ method @Deprecated public android.os.Parcelable! getParcelableData();
+ method @Deprecated public int getRemovedCount();
+ method @Deprecated public int getScrollX();
+ method @Deprecated public int getScrollY();
+ method @Deprecated public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getSource();
+ method @Deprecated public java.util.List<java.lang.CharSequence!>! getText();
+ method @Deprecated public int getToIndex();
+ method @Deprecated public int getWindowId();
+ method @Deprecated public int hashCode();
+ method @Deprecated public boolean isChecked();
+ method @Deprecated public boolean isEnabled();
+ method @Deprecated public boolean isFullScreen();
+ method @Deprecated public boolean isPassword();
+ method @Deprecated public boolean isScrollable();
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain();
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain(androidx.core.view.accessibility.AccessibilityRecordCompat!);
+ method @Deprecated public void recycle();
+ method @Deprecated public void setAddedCount(int);
+ method @Deprecated public void setBeforeText(CharSequence!);
+ method @Deprecated public void setChecked(boolean);
+ method @Deprecated public void setClassName(CharSequence!);
+ method @Deprecated public void setContentDescription(CharSequence!);
+ method @Deprecated public void setCurrentItemIndex(int);
+ method @Deprecated public void setEnabled(boolean);
+ method @Deprecated public void setFromIndex(int);
+ method @Deprecated public void setFullScreen(boolean);
+ method @Deprecated public void setItemCount(int);
+ method public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord, int);
+ method @Deprecated public void setMaxScrollX(int);
+ method public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord, int);
+ method @Deprecated public void setMaxScrollY(int);
+ method @Deprecated public void setParcelableData(android.os.Parcelable!);
+ method @Deprecated public void setPassword(boolean);
+ method @Deprecated public void setRemovedCount(int);
+ method @Deprecated public void setScrollX(int);
+ method @Deprecated public void setScrollY(int);
+ method @Deprecated public void setScrollable(boolean);
+ method public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View?, int);
+ method @Deprecated public void setSource(android.view.View!);
+ method @Deprecated public void setSource(android.view.View!, int);
+ method @Deprecated public void setToIndex(int);
+ }
+
+ public interface AccessibilityViewCommand {
+ method public boolean perform(android.view.View, androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments?);
+ }
+
+ public abstract static class AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.CommandArguments();
+ }
+
+ public static final class AccessibilityViewCommand.MoveAtGranularityArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveAtGranularityArguments();
+ method public boolean getExtendSelection();
+ method public int getGranularity();
+ }
+
+ public static final class AccessibilityViewCommand.MoveHtmlArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveHtmlArguments();
+ method public String? getHTMLElement();
+ }
+
+ public static final class AccessibilityViewCommand.MoveWindowArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveWindowArguments();
+ method public int getX();
+ method public int getY();
+ }
+
+ public static final class AccessibilityViewCommand.ScrollToPositionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.ScrollToPositionArguments();
+ method public int getColumn();
+ method public int getRow();
+ }
+
+ public static final class AccessibilityViewCommand.SetProgressArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetProgressArguments();
+ method public float getProgress();
+ }
+
+ public static final class AccessibilityViewCommand.SetSelectionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetSelectionArguments();
+ method public int getEnd();
+ method public int getStart();
+ }
+
+ public static final class AccessibilityViewCommand.SetTextArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetTextArguments();
+ method public CharSequence? getText();
+ }
+
+ public class AccessibilityWindowInfoCompat {
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getAnchor();
+ method public void getBoundsInScreen(android.graphics.Rect);
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getChild(int);
+ method public int getChildCount();
+ method public int getDisplayId();
+ method public int getId();
+ method public int getLayer();
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getParent();
+ method public void getRegionInScreen(android.graphics.Region);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getRoot();
+ method public CharSequence? getTitle();
+ method public int getType();
+ method public boolean isAccessibilityFocused();
+ method public boolean isActive();
+ method public boolean isFocused();
+ method public boolean isInPictureInPictureMode();
+ method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat? obtain();
+ method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat? obtain(androidx.core.view.accessibility.AccessibilityWindowInfoCompat?);
+ method @Deprecated public void recycle();
+ method public android.view.accessibility.AccessibilityWindowInfo? unwrap();
+ field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+ field public static final int TYPE_APPLICATION = 1; // 0x1
+ field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
+ field public static final int TYPE_SYSTEM = 3; // 0x3
+ }
+
+}
+
+package androidx.core.view.animation {
+
+ public final class PathInterpolatorCompat {
+ method public static android.view.animation.Interpolator create(android.graphics.Path);
+ method public static android.view.animation.Interpolator create(float, float);
+ method public static android.view.animation.Interpolator create(float, float, float, float);
+ }
+
+}
+
+package androidx.core.view.autofill {
+
+ public class AutofillIdCompat {
+ method @RequiresApi(26) public android.view.autofill.AutofillId toAutofillId();
+ method @RequiresApi(26) public static androidx.core.view.autofill.AutofillIdCompat toAutofillIdCompat(android.view.autofill.AutofillId);
+ }
+
+}
+
+package androidx.core.view.contentcapture {
+
+ public class ContentCaptureSessionCompat {
+ method public android.view.autofill.AutofillId? newAutofillId(long);
+ method public androidx.core.view.ViewStructureCompat? newVirtualViewStructure(android.view.autofill.AutofillId, long);
+ method public void notifyViewTextChanged(android.view.autofill.AutofillId, CharSequence?);
+ method public void notifyViewsAppeared(java.util.List<android.view.ViewStructure!>);
+ method public void notifyViewsDisappeared(long[]);
+ method @RequiresApi(29) public android.view.contentcapture.ContentCaptureSession toContentCaptureSession();
+ method @RequiresApi(29) public static androidx.core.view.contentcapture.ContentCaptureSessionCompat toContentCaptureSessionCompat(android.view.contentcapture.ContentCaptureSession, android.view.View);
+ }
+
+}
+
+package androidx.core.view.inputmethod {
+
+ public final class EditorInfoCompat {
+ ctor @Deprecated public EditorInfoCompat();
+ method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo);
+ method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
+ method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, String![]?);
+ method public static void setInitialSurroundingSubText(android.view.inputmethod.EditorInfo, CharSequence, int);
+ method public static void setInitialSurroundingText(android.view.inputmethod.EditorInfo, CharSequence);
+ field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
+ field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
+ }
+
+ public final class InputConnectionCompat {
+ ctor @Deprecated public InputConnectionCompat();
+ method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+ method @Deprecated public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
+ method public static android.view.inputmethod.InputConnection createWrapper(android.view.View, android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
+ field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
+ }
+
+ public static interface InputConnectionCompat.OnCommitContentListener {
+ method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+ }
+
+ public final class InputContentInfoCompat {
+ ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri?);
+ method public android.net.Uri getContentUri();
+ method public android.content.ClipDescription getDescription();
+ method public android.net.Uri? getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
+ method public Object? unwrap();
+ method public static androidx.core.view.inputmethod.InputContentInfoCompat? wrap(Object?);
+ }
+
+}
+
+package androidx.core.widget {
+
+ public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+ ctor public AutoScrollHelper(android.view.View);
+ method public abstract boolean canTargetScrollHorizontally(int);
+ method public abstract boolean canTargetScrollVertically(int);
+ method public boolean isEnabled();
+ method public boolean isExclusive();
+ method public boolean onTouch(android.view.View!, android.view.MotionEvent!);
+ method public abstract void scrollTargetBy(int, int);
+ method public androidx.core.widget.AutoScrollHelper setActivationDelay(int);
+ method public androidx.core.widget.AutoScrollHelper setEdgeType(int);
+ method public androidx.core.widget.AutoScrollHelper! setEnabled(boolean);
+ method public androidx.core.widget.AutoScrollHelper! setExclusive(boolean);
+ method public androidx.core.widget.AutoScrollHelper setMaximumEdges(float, float);
+ method public androidx.core.widget.AutoScrollHelper setMaximumVelocity(float, float);
+ method public androidx.core.widget.AutoScrollHelper setMinimumVelocity(float, float);
+ method public androidx.core.widget.AutoScrollHelper setRampDownDuration(int);
+ method public androidx.core.widget.AutoScrollHelper setRampUpDuration(int);
+ method public androidx.core.widget.AutoScrollHelper setRelativeEdges(float, float);
+ method public androidx.core.widget.AutoScrollHelper setRelativeVelocity(float, float);
+ field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+ field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+ field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+ field public static final float NO_MAX = 3.4028235E38f;
+ field public static final float NO_MIN = 0.0f;
+ field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+ }
+
+ public final class CheckedTextViewCompat {
+ method public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
+ method public static android.content.res.ColorStateList? getCheckMarkTintList(android.widget.CheckedTextView);
+ method public static android.graphics.PorterDuff.Mode? getCheckMarkTintMode(android.widget.CheckedTextView);
+ method public static void setCheckMarkTintList(android.widget.CheckedTextView, android.content.res.ColorStateList?);
+ method public static void setCheckMarkTintMode(android.widget.CheckedTextView, android.graphics.PorterDuff.Mode?);
+ }
+
+ public final class CompoundButtonCompat {
+ method public static android.graphics.drawable.Drawable? getButtonDrawable(android.widget.CompoundButton);
+ method public static android.content.res.ColorStateList? getButtonTintList(android.widget.CompoundButton);
+ method public static android.graphics.PorterDuff.Mode? getButtonTintMode(android.widget.CompoundButton);
+ method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList?);
+ method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode?);
+ }
+
+ public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+ ctor public ContentLoadingProgressBar(android.content.Context);
+ ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet?);
+ method public void hide();
+ method public void onAttachedToWindow();
+ method public void onDetachedFromWindow();
+ method public void show();
+ }
+
+ public final class EdgeEffectCompat {
+ ctor @Deprecated public EdgeEffectCompat(android.content.Context!);
+ method public static android.widget.EdgeEffect create(android.content.Context, android.util.AttributeSet?);
+ method @Deprecated public boolean draw(android.graphics.Canvas!);
+ method @Deprecated public void finish();
+ method public static float getDistance(android.widget.EdgeEffect);
+ method @Deprecated public boolean isFinished();
+ method @Deprecated public boolean onAbsorb(int);
+ method public static void onPull(android.widget.EdgeEffect, float, float);
+ method @Deprecated public boolean onPull(float);
+ method @Deprecated public boolean onPull(float, float);
+ method public static float onPullDistance(android.widget.EdgeEffect, float, float);
+ method @Deprecated public boolean onRelease();
+ method @Deprecated public void setSize(int, int);
+ }
+
+ public class ImageViewCompat {
+ method public static android.content.res.ColorStateList? getImageTintList(android.widget.ImageView);
+ method public static android.graphics.PorterDuff.Mode? getImageTintMode(android.widget.ImageView);
+ method public static void setImageTintList(android.widget.ImageView, android.content.res.ColorStateList?);
+ method public static void setImageTintMode(android.widget.ImageView, android.graphics.PorterDuff.Mode?);
+ }
+
+ public final class ListPopupWindowCompat {
+ method public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
+ method @Deprecated public static android.view.View.OnTouchListener! createDragToOpenListener(Object!, android.view.View!);
+ }
+
+ public class ListViewAutoScrollHelper extends androidx.core.widget.AutoScrollHelper {
+ ctor public ListViewAutoScrollHelper(android.widget.ListView);
+ method public boolean canTargetScrollHorizontally(int);
+ method public boolean canTargetScrollVertically(int);
+ method public void scrollTargetBy(int, int);
+ }
+
+ public final class ListViewCompat {
+ method public static boolean canScrollList(android.widget.ListView, int);
+ method public static void scrollListBy(android.widget.ListView, int);
+ }
+
+ public class NestedScrollView extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingChild3 androidx.core.view.NestedScrollingParent3 androidx.core.view.ScrollingView {
+ ctor public NestedScrollView(android.content.Context);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?, int);
+ method public boolean arrowScroll(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollExtent();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollOffset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollRange();
+ method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollExtent();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollOffset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollRange();
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+ method public boolean executeKeyEvent(android.view.KeyEvent);
+ method public void fling(int);
+ method public boolean fullScroll(int);
+ method public int getMaxScrollAmount();
+ method public boolean hasNestedScrollingParent(int);
+ method public boolean isFillViewport();
+ method public boolean isSmoothScrollingEnabled();
+ method public void onAttachedToWindow();
+ method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View, int);
+ method public boolean pageScroll(int);
+ method public void setFillViewport(boolean);
+ method public void setOnScrollChangeListener(androidx.core.widget.NestedScrollView.OnScrollChangeListener?);
+ method public void setSmoothScrollingEnabled(boolean);
+ method public final void smoothScrollBy(int, int);
+ method public final void smoothScrollBy(int, int, int);
+ method public final void smoothScrollTo(int, int);
+ method public final void smoothScrollTo(int, int, int);
+ method public boolean startNestedScroll(int, int);
+ method public void stopNestedScroll(int);
+ }
+
+ public static interface NestedScrollView.OnScrollChangeListener {
+ method public void onScrollChange(androidx.core.widget.NestedScrollView, int, int, int, int);
+ }
+
+ public final class PopupMenuCompat {
+ method public static android.view.View.OnTouchListener? getDragToOpenListener(Object);
+ }
+
+ public final class PopupWindowCompat {
+ method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+ method public static int getWindowLayoutType(android.widget.PopupWindow);
+ method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+ method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+ method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+ }
+
+ @Deprecated public final class ScrollerCompat {
+ method @Deprecated public void abortAnimation();
+ method @Deprecated public boolean computeScrollOffset();
+ method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!);
+ method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!, android.view.animation.Interpolator!);
+ method @Deprecated public void fling(int, int, int, int, int, int, int, int);
+ method @Deprecated public void fling(int, int, int, int, int, int, int, int, int, int);
+ method @Deprecated public float getCurrVelocity();
+ method @Deprecated public int getCurrX();
+ method @Deprecated public int getCurrY();
+ method @Deprecated public int getFinalX();
+ method @Deprecated public int getFinalY();
+ method @Deprecated public boolean isFinished();
+ method @Deprecated public boolean isOverScrolled();
+ method @Deprecated public void notifyHorizontalEdgeReached(int, int, int);
+ method @Deprecated public void notifyVerticalEdgeReached(int, int, int);
+ method @Deprecated public boolean springBack(int, int, int, int, int, int);
+ method @Deprecated public void startScroll(int, int, int, int);
+ method @Deprecated public void startScroll(int, int, int, int, int);
+ }
+
+ public final class TextViewCompat {
+ method public static int getAutoSizeMaxTextSize(android.widget.TextView);
+ method public static int getAutoSizeMinTextSize(android.widget.TextView);
+ method public static int getAutoSizeStepGranularity(android.widget.TextView);
+ method public static int[] getAutoSizeTextAvailableSizes(android.widget.TextView);
+ method public static int getAutoSizeTextType(android.widget.TextView);
+ method public static android.content.res.ColorStateList? getCompoundDrawableTintList(android.widget.TextView);
+ method public static android.graphics.PorterDuff.Mode? getCompoundDrawableTintMode(android.widget.TextView);
+ method public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
+ method public static int getFirstBaselineToTopHeight(android.widget.TextView);
+ method public static int getLastBaselineToBottomHeight(android.widget.TextView);
+ method public static int getMaxLines(android.widget.TextView);
+ method public static int getMinLines(android.widget.TextView);
+ method public static androidx.core.text.PrecomputedTextCompat.Params getTextMetricsParams(android.widget.TextView);
+ method public static void setAutoSizeTextTypeUniformWithConfiguration(android.widget.TextView, int, int, int, int) throws java.lang.IllegalArgumentException;
+ method public static void setAutoSizeTextTypeUniformWithPresetSizes(android.widget.TextView, int[], int) throws java.lang.IllegalArgumentException;
+ method public static void setAutoSizeTextTypeWithDefaults(android.widget.TextView, int);
+ method public static void setCompoundDrawableTintList(android.widget.TextView, android.content.res.ColorStateList?);
+ method public static void setCompoundDrawableTintMode(android.widget.TextView, android.graphics.PorterDuff.Mode?);
+ method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+ method public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
+ method public static void setFirstBaselineToTopHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setLastBaselineToBottomHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setLineHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setPrecomputedText(android.widget.TextView, androidx.core.text.PrecomputedTextCompat);
+ method public static void setTextAppearance(android.widget.TextView, @StyleRes int);
+ method public static void setTextMetricsParams(android.widget.TextView, androidx.core.text.PrecomputedTextCompat.Params);
+ field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
+ field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
+ }
+
+ public interface TintableCompoundButton {
+ method public android.content.res.ColorStateList? getSupportButtonTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportButtonTintMode();
+ method public void setSupportButtonTintList(android.content.res.ColorStateList?);
+ method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ public interface TintableCompoundDrawablesView {
+ method public android.content.res.ColorStateList? getSupportCompoundDrawablesTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportCompoundDrawablesTintMode();
+ method public void setSupportCompoundDrawablesTintList(android.content.res.ColorStateList?);
+ method public void setSupportCompoundDrawablesTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+}
+
diff --git a/core/core/api/aidlRelease/current/android/support/v4/app/INotificationSideChannel.aidl b/core/core/api/aidlRelease/current/android/support/v4/app/INotificationSideChannel.aidl
index e9863e96..5d2ca13 100644
--- a/core/core/api/aidlRelease/current/android/support/v4/app/INotificationSideChannel.aidl
+++ b/core/core/api/aidlRelease/current/android/support/v4/app/INotificationSideChannel.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.support.v4.app;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface INotificationSideChannel {
oneway void notify(String packageName, int id, String tag, in android.app.Notification notification);
oneway void cancel(String packageName, int id, String tag);
diff --git a/core/core/api/aidlRelease/current/android/support/v4/os/IResultReceiver.aidl b/core/core/api/aidlRelease/current/android/support/v4/os/IResultReceiver.aidl
index cad8249..c9ab384 100644
--- a/core/core/api/aidlRelease/current/android/support/v4/os/IResultReceiver.aidl
+++ b/core/core/api/aidlRelease/current/android/support/v4/os/IResultReceiver.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.support.v4.os;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IResultReceiver {
oneway void send(int resultCode, in android.os.Bundle resultData);
}
diff --git a/core/core/api/aidlRelease/current/android/support/v4/os/IResultReceiver2.aidl b/core/core/api/aidlRelease/current/android/support/v4/os/IResultReceiver2.aidl
index 881607e..3559fc9 100644
--- a/core/core/api/aidlRelease/current/android/support/v4/os/IResultReceiver2.aidl
+++ b/core/core/api/aidlRelease/current/android/support/v4/os/IResultReceiver2.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.support.v4.os;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IResultReceiver2 {
oneway void send(int resultCode, in android.os.Bundle resultData);
}
diff --git a/core/core/api/aidlRelease/current/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportCallback.aidl b/core/core/api/aidlRelease/current/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportCallback.aidl
index 41570bd..d4ac576 100644
--- a/core/core/api/aidlRelease/current/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportCallback.aidl
+++ b/core/core/api/aidlRelease/current/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportCallback.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.core.app.unusedapprestrictions;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IUnusedAppRestrictionsBackportCallback {
oneway void onIsPermissionRevocationEnabledForAppResult(boolean success, boolean isEnabled);
}
diff --git a/core/core/api/aidlRelease/current/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportService.aidl b/core/core/api/aidlRelease/current/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportService.aidl
index 9aba17c..a6e2f44 100644
--- a/core/core/api/aidlRelease/current/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportService.aidl
+++ b/core/core/api/aidlRelease/current/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportService.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.core.app.unusedapprestrictions;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IUnusedAppRestrictionsBackportService {
oneway void isPermissionRevocationEnabledForApp(in androidx.core.app.unusedapprestrictions.IUnusedAppRestrictionsBackportCallback callback);
}
diff --git a/core/core/api/current.ignore b/core/core/api/current.ignore
deleted file mode 100644
index 3ff8fad..0000000
--- a/core/core/api/current.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-// Baseline format: 1.0
-InvalidNullConversion: androidx.core.app.PendingIntentCompat#getBroadcast(android.content.Context, int, android.content.Intent, int, boolean):
- Attempted to change method return from @NonNull to @Nullable: incompatible change for method androidx.core.app.PendingIntentCompat.getBroadcast(android.content.Context,int,android.content.Intent,int,boolean)
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index 0c385e3..128f0c4 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -1446,7 +1446,7 @@
method @ColorInt public static int HSLToColor(float[]);
method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
- method @ColorInt public static int M3HCTtoColor(float, float, float);
+ method @ColorInt public static int M3HCTToColor(@FloatRange(from=0.0, to=360, toInclusive=false) float, @FloatRange(from=0.0, to=java.lang.Double.POSITIVE_INFINITY, toInclusive=false) float, @FloatRange(from=0.0, to=100) float);
method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
@@ -1460,7 +1460,7 @@
method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
method public static void colorToHSL(@ColorInt int, float[]);
method public static void colorToLAB(@ColorInt int, double[]);
- method public static void colorToM3HCT(@ColorInt int, float[]);
+ method public static void colorToM3HCT(@ColorInt int, @Size(3) float[]);
method public static void colorToXYZ(@ColorInt int, double[]);
method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
method public static int compositeColors(@ColorInt int, @ColorInt int);
diff --git a/core/core/api/res-1.11.0-beta02.txt b/core/core/api/res-1.11.0-beta02.txt
new file mode 100644
index 0000000..dd913d3
--- /dev/null
+++ b/core/core/api/res-1.11.0-beta02.txt
@@ -0,0 +1,21 @@
+attr alpha
+attr font
+attr fontProviderAuthority
+attr fontProviderCerts
+attr fontProviderFetchStrategy
+attr fontProviderFetchTimeout
+attr fontProviderPackage
+attr fontProviderQuery
+attr fontProviderSystemFontFamily
+attr fontStyle
+attr fontVariationSettings
+attr fontWeight
+attr lStar
+attr queryPatterns
+attr shortcutMatchRequired
+attr ttcIndex
+style TextAppearance_Compat_Notification
+style TextAppearance_Compat_Notification_Info
+style TextAppearance_Compat_Notification_Line2
+style TextAppearance_Compat_Notification_Time
+style TextAppearance_Compat_Notification_Title
diff --git a/core/core/api/restricted_1.11.0-beta01.txt b/core/core/api/restricted_1.11.0-beta01.txt
index 29edb7b..f02ce1a 100644
--- a/core/core/api/restricted_1.11.0-beta01.txt
+++ b/core/core/api/restricted_1.11.0-beta01.txt
@@ -1506,7 +1506,7 @@
package androidx.core.content.res {
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class CamColor {
- method public static void getM3HCTfromColor(@ColorInt int, float[]);
+ method public static void getM3HCTfromColor(@ColorInt int, @Size(3) float[]);
method public static int toColor(@FloatRange(from=0.0, to=360.0) float, @FloatRange(from=0.0, to=java.lang.Double.POSITIVE_INFINITY, toInclusive=false) float, @FloatRange(from=0.0, to=100.0) float);
}
@@ -1687,7 +1687,7 @@
method @ColorInt public static int HSLToColor(float[]);
method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
- method @ColorInt public static int M3HCTtoColor(float, float, float);
+ method @ColorInt public static int M3HCTToColor(@FloatRange(from=0.0, to=360, toInclusive=false) float, @FloatRange(from=0.0, to=java.lang.Double.POSITIVE_INFINITY, toInclusive=false) float, @FloatRange(from=0.0, to=100) float);
method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
@@ -1701,7 +1701,7 @@
method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
method public static void colorToHSL(@ColorInt int, float[]);
method public static void colorToLAB(@ColorInt int, double[]);
- method public static void colorToM3HCT(@ColorInt int, float[]);
+ method public static void colorToM3HCT(@ColorInt int, @Size(3) float[]);
method public static void colorToXYZ(@ColorInt int, double[]);
method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
method public static int compositeColors(@ColorInt int, @ColorInt int);
diff --git a/core/core/api/restricted_1.11.0-beta02.txt b/core/core/api/restricted_1.11.0-beta02.txt
new file mode 100644
index 0000000..f02ce1a
--- /dev/null
+++ b/core/core/api/restricted_1.11.0-beta02.txt
@@ -0,0 +1,4583 @@
+// Signature format: 4.0
+package android.support.v4.os {
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ResultReceiver implements android.os.Parcelable {
+ ctor public ResultReceiver(android.os.Handler!);
+ method public int describeContents();
+ method protected void onReceiveResult(int, android.os.Bundle!);
+ method public void send(int, android.os.Bundle!);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.os.ResultReceiver!>! CREATOR;
+ }
+
+}
+
+package androidx.core.accessibilityservice {
+
+ public final class AccessibilityServiceInfoCompat {
+ method public static String capabilityToString(int);
+ method public static String feedbackTypeToString(int);
+ method public static String? flagToString(int);
+ method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+ method public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+ field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+ field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+ field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+ field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+ field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+ field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+ field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+ field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+ field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+ field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+ field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+ }
+
+}
+
+package androidx.core.app {
+
+ public class ActivityCompat extends androidx.core.content.ContextCompat {
+ ctor protected ActivityCompat();
+ method public static void finishAffinity(android.app.Activity);
+ method public static void finishAfterTransition(android.app.Activity);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.ActivityCompat.PermissionCompatDelegate? getPermissionCompatDelegate();
+ method public static android.net.Uri? getReferrer(android.app.Activity);
+ method @Deprecated public static boolean invalidateOptionsMenu(android.app.Activity!);
+ method public static boolean isLaunchedFromBubble(android.app.Activity);
+ method public static void postponeEnterTransition(android.app.Activity);
+ method public static void recreate(android.app.Activity);
+ method public static androidx.core.view.DragAndDropPermissionsCompat? requestDragAndDropPermissions(android.app.Activity, android.view.DragEvent);
+ method public static void requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+ method public static <T extends android.view.View> T requireViewById(android.app.Activity, @IdRes int);
+ method public static void setEnterSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+ method public static void setExitSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+ method public static void setLocusContext(android.app.Activity, androidx.core.content.LocusIdCompat?, android.os.Bundle?);
+ method public static void setPermissionCompatDelegate(androidx.core.app.ActivityCompat.PermissionCompatDelegate?);
+ method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, String);
+ method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle?);
+ method public static void startIntentSenderForResult(android.app.Activity, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public static void startPostponedEnterTransition(android.app.Activity);
+ }
+
+ public static interface ActivityCompat.OnRequestPermissionsResultCallback {
+ method public void onRequestPermissionsResult(int, String![], int[]);
+ }
+
+ public static interface ActivityCompat.PermissionCompatDelegate {
+ method public boolean onActivityResult(android.app.Activity, @IntRange(from=0) int, int, android.content.Intent?);
+ method public boolean requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface ActivityCompat.RequestPermissionsRequestCodeValidator {
+ method public void validateRequestPermissionsRequestCode(int);
+ }
+
+ public final class ActivityManagerCompat {
+ method public static boolean isLowRamDevice(android.app.ActivityManager);
+ }
+
+ public class ActivityOptionsCompat {
+ ctor protected ActivityOptionsCompat();
+ method public android.graphics.Rect? getLaunchBounds();
+ method public static androidx.core.app.ActivityOptionsCompat makeBasic();
+ method public static androidx.core.app.ActivityOptionsCompat makeClipRevealAnimation(android.view.View, int, int, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, String);
+ method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, androidx.core.util.Pair<android.view.View!,java.lang.String!>!...);
+ method public static androidx.core.app.ActivityOptionsCompat makeTaskLaunchBehind();
+ method public static androidx.core.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+ method public void requestUsageTimeReport(android.app.PendingIntent);
+ method public androidx.core.app.ActivityOptionsCompat setLaunchBounds(android.graphics.Rect?);
+ method public android.os.Bundle? toBundle();
+ method public void update(androidx.core.app.ActivityOptionsCompat);
+ field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
+ field public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+ }
+
+ public final class AlarmManagerCompat {
+ method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
+ method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ }
+
+ @RequiresApi(28) public class AppComponentFactory extends android.app.AppComponentFactory {
+ ctor public AppComponentFactory();
+ method public final android.app.Activity instantiateActivity(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Activity instantiateActivityCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.app.Application instantiateApplication(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Application instantiateApplicationCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.content.ContentProvider instantiateProvider(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.ContentProvider instantiateProviderCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.content.BroadcastReceiver instantiateReceiver(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.BroadcastReceiver instantiateReceiverCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.app.Service instantiateService(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Service instantiateServiceCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ }
+
+ public class AppLaunchChecker {
+ ctor @Deprecated public AppLaunchChecker();
+ method public static boolean hasStartedFromLauncher(android.content.Context);
+ method public static void onActivityCreate(android.app.Activity);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class AppLocalesStorageHelper {
+ method public static void persistLocales(android.content.Context, String);
+ method public static String readLocales(android.content.Context);
+ }
+
+ public final class AppOpsManagerCompat {
+ method public static int checkOrNoteProxyOp(android.content.Context, int, String, String);
+ method public static int noteOp(android.content.Context, String, int, String);
+ method public static int noteOpNoThrow(android.content.Context, String, int, String);
+ method public static int noteProxyOp(android.content.Context, String, String);
+ method public static int noteProxyOpNoThrow(android.content.Context, String, String);
+ method public static String? permissionToOp(String);
+ field public static final int MODE_ALLOWED = 0; // 0x0
+ field public static final int MODE_DEFAULT = 3; // 0x3
+ field public static final int MODE_ERRORED = 2; // 0x2
+ field public static final int MODE_IGNORED = 1; // 0x1
+ }
+
+ @Deprecated public final class BundleCompat {
+ method @Deprecated public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+ method @Deprecated public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ComponentActivity extends android.app.Activity implements androidx.core.view.KeyEventDispatcher.Component androidx.lifecycle.LifecycleOwner {
+ ctor public ComponentActivity();
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public <T extends androidx.core.app.ComponentActivity.ExtraData> T! getExtraData(Class<T!>!);
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void putExtraData(androidx.core.app.ComponentActivity.ExtraData!);
+ method protected final boolean shouldDumpInternalState(String![]?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean superDispatchKeyEvent(android.view.KeyEvent);
+ }
+
+ @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static class ComponentActivity.ExtraData {
+ ctor @Deprecated public ComponentActivity.ExtraData();
+ }
+
+ @RequiresApi(api=28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class CoreComponentFactory extends android.app.AppComponentFactory {
+ ctor public CoreComponentFactory();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface CoreComponentFactory.CompatWrapped {
+ method public Object! getWrapper();
+ }
+
+ public class DialogCompat {
+ method public static android.view.View requireViewById(android.app.Dialog, int);
+ }
+
+ public class FrameMetricsAggregator {
+ ctor public FrameMetricsAggregator();
+ ctor public FrameMetricsAggregator(@androidx.core.app.FrameMetricsAggregator.MetricType int);
+ method public void add(android.app.Activity);
+ method public android.util.SparseIntArray![]? getMetrics();
+ method public android.util.SparseIntArray![]? remove(android.app.Activity);
+ method public android.util.SparseIntArray![]? reset();
+ method public android.util.SparseIntArray![]? stop();
+ field public static final int ANIMATION_DURATION = 256; // 0x100
+ field public static final int ANIMATION_INDEX = 8; // 0x8
+ field public static final int COMMAND_DURATION = 32; // 0x20
+ field public static final int COMMAND_INDEX = 5; // 0x5
+ field public static final int DELAY_DURATION = 128; // 0x80
+ field public static final int DELAY_INDEX = 7; // 0x7
+ field public static final int DRAW_DURATION = 8; // 0x8
+ field public static final int DRAW_INDEX = 3; // 0x3
+ field public static final int EVERY_DURATION = 511; // 0x1ff
+ field public static final int INPUT_DURATION = 2; // 0x2
+ field public static final int INPUT_INDEX = 1; // 0x1
+ field public static final int LAYOUT_MEASURE_DURATION = 4; // 0x4
+ field public static final int LAYOUT_MEASURE_INDEX = 2; // 0x2
+ field public static final int SWAP_DURATION = 64; // 0x40
+ field public static final int SWAP_INDEX = 6; // 0x6
+ field public static final int SYNC_DURATION = 16; // 0x10
+ field public static final int SYNC_INDEX = 4; // 0x4
+ field public static final int TOTAL_DURATION = 1; // 0x1
+ field public static final int TOTAL_INDEX = 0; // 0x0
+ }
+
+ @IntDef(flag=true, value={androidx.core.app.FrameMetricsAggregator.TOTAL_DURATION, androidx.core.app.FrameMetricsAggregator.INPUT_DURATION, androidx.core.app.FrameMetricsAggregator.LAYOUT_MEASURE_DURATION, androidx.core.app.FrameMetricsAggregator.DRAW_DURATION, androidx.core.app.FrameMetricsAggregator.SYNC_DURATION, androidx.core.app.FrameMetricsAggregator.COMMAND_DURATION, androidx.core.app.FrameMetricsAggregator.SWAP_DURATION, androidx.core.app.FrameMetricsAggregator.DELAY_DURATION, androidx.core.app.FrameMetricsAggregator.ANIMATION_DURATION, androidx.core.app.FrameMetricsAggregator.EVERY_DURATION}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface FrameMetricsAggregator.MetricType {
+ }
+
+ @Deprecated public abstract class JobIntentService extends android.app.Service {
+ ctor @Deprecated public JobIntentService();
+ method @Deprecated public static void enqueueWork(android.content.Context, android.content.ComponentName, int, android.content.Intent);
+ method @Deprecated public static void enqueueWork(android.content.Context, Class<?>, int, android.content.Intent);
+ method @Deprecated public boolean isStopped();
+ method @Deprecated public android.os.IBinder! onBind(android.content.Intent);
+ method @Deprecated protected abstract void onHandleWork(android.content.Intent);
+ method @Deprecated public boolean onStopCurrentWork();
+ method @Deprecated public void setInterruptIfStopped(boolean);
+ }
+
+ public final class LocaleManagerCompat {
+ method @AnyThread public static androidx.core.os.LocaleListCompat getApplicationLocales(android.content.Context);
+ method @AnyThread public static androidx.core.os.LocaleListCompat getSystemLocales(android.content.Context);
+ }
+
+ public final class MultiWindowModeChangedInfo {
+ ctor public MultiWindowModeChangedInfo(boolean);
+ ctor @RequiresApi(26) public MultiWindowModeChangedInfo(boolean, android.content.res.Configuration);
+ method @RequiresApi(26) public android.content.res.Configuration getNewConfig();
+ method public boolean isInMultiWindowMode();
+ }
+
+ public final class NavUtils {
+ method public static android.content.Intent? getParentActivityIntent(android.app.Activity);
+ method public static android.content.Intent? getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static android.content.Intent? getParentActivityIntent(android.content.Context, Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static String? getParentActivityName(android.app.Activity);
+ method public static String? getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static void navigateUpFromSameTask(android.app.Activity);
+ method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+ method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+ field public static final String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface NotificationBuilderWithBuilderAccessor {
+ method public android.app.Notification.Builder! getBuilder();
+ }
+
+ public class NotificationChannelCompat {
+ method public boolean canBubble();
+ method public boolean canBypassDnd();
+ method public boolean canShowBadge();
+ method public android.media.AudioAttributes? getAudioAttributes();
+ method public String? getConversationId();
+ method public String? getDescription();
+ method public String? getGroup();
+ method public String getId();
+ method public int getImportance();
+ method public int getLightColor();
+ method @androidx.core.app.NotificationCompat.NotificationVisibility public int getLockscreenVisibility();
+ method public CharSequence? getName();
+ method public String? getParentChannelId();
+ method public android.net.Uri? getSound();
+ method public long[]? getVibrationPattern();
+ method public boolean isImportantConversation();
+ method public boolean shouldShowLights();
+ method public boolean shouldVibrate();
+ method public androidx.core.app.NotificationChannelCompat.Builder toBuilder();
+ field public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
+ }
+
+ public static class NotificationChannelCompat.Builder {
+ ctor public NotificationChannelCompat.Builder(String, int);
+ method public androidx.core.app.NotificationChannelCompat build();
+ method public androidx.core.app.NotificationChannelCompat.Builder setConversationId(String, String);
+ method public androidx.core.app.NotificationChannelCompat.Builder setDescription(String?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setGroup(String?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setImportance(int);
+ method public androidx.core.app.NotificationChannelCompat.Builder setLightColor(int);
+ method public androidx.core.app.NotificationChannelCompat.Builder setLightsEnabled(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setName(CharSequence?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setShowBadge(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setSound(android.net.Uri?, android.media.AudioAttributes?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setVibrationEnabled(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setVibrationPattern(long[]?);
+ }
+
+ public class NotificationChannelGroupCompat {
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getChannels();
+ method public String? getDescription();
+ method public String getId();
+ method public CharSequence? getName();
+ method public boolean isBlocked();
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder toBuilder();
+ }
+
+ public static class NotificationChannelGroupCompat.Builder {
+ ctor public NotificationChannelGroupCompat.Builder(String);
+ method public androidx.core.app.NotificationChannelGroupCompat build();
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder setDescription(String?);
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder setName(CharSequence?);
+ }
+
+ public class NotificationCompat {
+ ctor @Deprecated public NotificationCompat();
+ method public static androidx.core.app.NotificationCompat.Action? getAction(android.app.Notification, int);
+ method public static int getActionCount(android.app.Notification);
+ method public static boolean getAllowSystemGeneratedContextualActions(android.app.Notification);
+ method public static boolean getAutoCancel(android.app.Notification);
+ method public static int getBadgeIconType(android.app.Notification);
+ method public static androidx.core.app.NotificationCompat.BubbleMetadata? getBubbleMetadata(android.app.Notification);
+ method public static String? getCategory(android.app.Notification);
+ method public static String? getChannelId(android.app.Notification);
+ method public static int getColor(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentInfo(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentText(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentTitle(android.app.Notification);
+ method public static android.os.Bundle? getExtras(android.app.Notification);
+ method public static String? getGroup(android.app.Notification);
+ method @androidx.core.app.NotificationCompat.GroupAlertBehavior public static int getGroupAlertBehavior(android.app.Notification);
+ method @RequiresApi(21) public static java.util.List<androidx.core.app.NotificationCompat.Action!> getInvisibleActions(android.app.Notification);
+ method public static boolean getLocalOnly(android.app.Notification);
+ method public static androidx.core.content.LocusIdCompat? getLocusId(android.app.Notification);
+ method public static boolean getOngoing(android.app.Notification);
+ method public static boolean getOnlyAlertOnce(android.app.Notification);
+ method public static java.util.List<androidx.core.app.Person!> getPeople(android.app.Notification);
+ method public static android.app.Notification? getPublicVersion(android.app.Notification);
+ method public static CharSequence? getSettingsText(android.app.Notification);
+ method public static String? getShortcutId(android.app.Notification);
+ method @RequiresApi(19) public static boolean getShowWhen(android.app.Notification);
+ method public static String? getSortKey(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getSubText(android.app.Notification);
+ method public static long getTimeoutAfter(android.app.Notification);
+ method @RequiresApi(19) public static boolean getUsesChronometer(android.app.Notification);
+ method @androidx.core.app.NotificationCompat.NotificationVisibility public static int getVisibility(android.app.Notification);
+ method public static boolean isGroupSummary(android.app.Notification);
+ method public static android.graphics.Bitmap? reduceLargeIconSize(android.content.Context, android.graphics.Bitmap?);
+ field public static final int BADGE_ICON_LARGE = 2; // 0x2
+ field public static final int BADGE_ICON_NONE = 0; // 0x0
+ field public static final int BADGE_ICON_SMALL = 1; // 0x1
+ field public static final String CATEGORY_ALARM = "alarm";
+ field public static final String CATEGORY_CALL = "call";
+ field public static final String CATEGORY_EMAIL = "email";
+ field public static final String CATEGORY_ERROR = "err";
+ field public static final String CATEGORY_EVENT = "event";
+ field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
+ field public static final String CATEGORY_MESSAGE = "msg";
+ field public static final String CATEGORY_MISSED_CALL = "missed_call";
+ field public static final String CATEGORY_NAVIGATION = "navigation";
+ field public static final String CATEGORY_PROGRESS = "progress";
+ field public static final String CATEGORY_PROMO = "promo";
+ field public static final String CATEGORY_RECOMMENDATION = "recommendation";
+ field public static final String CATEGORY_REMINDER = "reminder";
+ field public static final String CATEGORY_SERVICE = "service";
+ field public static final String CATEGORY_SOCIAL = "social";
+ field public static final String CATEGORY_STATUS = "status";
+ field public static final String CATEGORY_STOPWATCH = "stopwatch";
+ field public static final String CATEGORY_SYSTEM = "sys";
+ field public static final String CATEGORY_TRANSPORT = "transport";
+ field public static final String CATEGORY_WORKOUT = "workout";
+ field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
+ field public static final int DEFAULT_ALL = -1; // 0xffffffff
+ field public static final int DEFAULT_LIGHTS = 4; // 0x4
+ field public static final int DEFAULT_SOUND = 1; // 0x1
+ field public static final int DEFAULT_VIBRATE = 2; // 0x2
+ field public static final String EXTRA_ANSWER_COLOR = "android.answerColor";
+ field public static final String EXTRA_ANSWER_INTENT = "android.answerIntent";
+ field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+ field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+ field public static final String EXTRA_BIG_TEXT = "android.bigText";
+ field public static final String EXTRA_CALL_IS_VIDEO = "android.callIsVideo";
+ field public static final String EXTRA_CALL_PERSON = "android.callPerson";
+ field public static final String EXTRA_CALL_PERSON_COMPAT = "android.callPersonCompat";
+ field public static final String EXTRA_CALL_TYPE = "android.callType";
+ field public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
+ field public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
+ field public static final String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+ field public static final String EXTRA_COLORIZED = "android.colorized";
+ field public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+ field public static final String EXTRA_COMPAT_TEMPLATE = "androidx.core.app.extra.COMPAT_TEMPLATE";
+ field public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+ field public static final String EXTRA_DECLINE_COLOR = "android.declineColor";
+ field public static final String EXTRA_DECLINE_INTENT = "android.declineIntent";
+ field public static final String EXTRA_HANG_UP_INTENT = "android.hangUpIntent";
+ field public static final String EXTRA_HIDDEN_CONVERSATION_TITLE = "android.hiddenConversationTitle";
+ field public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
+ field public static final String EXTRA_INFO_TEXT = "android.infoText";
+ field public static final String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
+ field public static final String EXTRA_LARGE_ICON = "android.largeIcon";
+ field public static final String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+ field public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
+ field public static final String EXTRA_MESSAGES = "android.messages";
+ field public static final String EXTRA_MESSAGING_STYLE_USER = "android.messagingStyleUser";
+ field public static final String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
+ field public static final String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
+ field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
+ field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
+ field public static final String EXTRA_PICTURE = "android.picture";
+ field public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION = "android.pictureContentDescription";
+ field public static final String EXTRA_PICTURE_ICON = "android.pictureIcon";
+ field public static final String EXTRA_PROGRESS = "android.progress";
+ field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+ field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+ field public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+ field public static final String EXTRA_SHOW_BIG_PICTURE_WHEN_COLLAPSED = "android.showBigPictureWhenCollapsed";
+ field public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+ field public static final String EXTRA_SHOW_WHEN = "android.showWhen";
+ field public static final String EXTRA_SMALL_ICON = "android.icon";
+ field public static final String EXTRA_SUB_TEXT = "android.subText";
+ field public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
+ field public static final String EXTRA_TEMPLATE = "android.template";
+ field public static final String EXTRA_TEXT = "android.text";
+ field public static final String EXTRA_TEXT_LINES = "android.textLines";
+ field public static final String EXTRA_TITLE = "android.title";
+ field public static final String EXTRA_TITLE_BIG = "android.title.big";
+ field public static final String EXTRA_VERIFICATION_ICON = "android.verificationIcon";
+ field public static final String EXTRA_VERIFICATION_ICON_COMPAT = "android.verificationIconCompat";
+ field public static final String EXTRA_VERIFICATION_TEXT = "android.verificationText";
+ field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+ field public static final int FLAG_BUBBLE = 4096; // 0x1000
+ field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+ field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+ field @Deprecated public static final int FLAG_HIGH_PRIORITY = 128; // 0x80
+ field public static final int FLAG_INSISTENT = 4; // 0x4
+ field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+ field public static final int FLAG_NO_CLEAR = 32; // 0x20
+ field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+ field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+ field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int FOREGROUND_SERVICE_DEFAULT = 0; // 0x0
+ field public static final int FOREGROUND_SERVICE_DEFERRED = 2; // 0x2
+ field public static final int FOREGROUND_SERVICE_IMMEDIATE = 1; // 0x1
+ field public static final int GROUP_ALERT_ALL = 0; // 0x0
+ field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
+ field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+ field public static final String GROUP_KEY_SILENT = "silent";
+ field public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int MAX_ACTION_BUTTONS = 3; // 0x3
+ field public static final int PRIORITY_DEFAULT = 0; // 0x0
+ field public static final int PRIORITY_HIGH = 1; // 0x1
+ field public static final int PRIORITY_LOW = -1; // 0xffffffff
+ field public static final int PRIORITY_MAX = 2; // 0x2
+ field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+ field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+ field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+ field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+ field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+ }
+
+ public static class NotificationCompat.Action {
+ ctor public NotificationCompat.Action(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action(int, CharSequence?, android.app.PendingIntent?);
+ method public android.app.PendingIntent? getActionIntent();
+ method public boolean getAllowGeneratedReplies();
+ method public androidx.core.app.RemoteInput![]? getDataOnlyRemoteInputs();
+ method public android.os.Bundle getExtras();
+ method @Deprecated public int getIcon();
+ method public androidx.core.graphics.drawable.IconCompat? getIconCompat();
+ method public androidx.core.app.RemoteInput![]? getRemoteInputs();
+ method @androidx.core.app.NotificationCompat.Action.SemanticAction public int getSemanticAction();
+ method public boolean getShowsUserInterface();
+ method public CharSequence? getTitle();
+ method public boolean isAuthenticationRequired();
+ method public boolean isContextual();
+ field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5
+ field public static final int SEMANTIC_ACTION_CALL = 10; // 0xa
+ field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4
+ field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2
+ field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3
+ field public static final int SEMANTIC_ACTION_MUTE = 6; // 0x6
+ field public static final int SEMANTIC_ACTION_NONE = 0; // 0x0
+ field public static final int SEMANTIC_ACTION_REPLY = 1; // 0x1
+ field public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; // 0x9
+ field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8
+ field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7
+ field public android.app.PendingIntent? actionIntent;
+ field @Deprecated public int icon;
+ field public CharSequence! title;
+ }
+
+ public static final class NotificationCompat.Action.Builder {
+ ctor public NotificationCompat.Action.Builder(androidx.core.app.NotificationCompat.Action);
+ ctor public NotificationCompat.Action.Builder(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action.Builder(int, CharSequence?, android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Action.Builder addRemoteInput(androidx.core.app.RemoteInput?);
+ method public androidx.core.app.NotificationCompat.Action build();
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Extender);
+ method @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.NotificationCompat.Action.Builder fromAndroidAction(android.app.Notification.Action);
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.NotificationCompat.Action.Builder setAllowGeneratedReplies(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setAuthenticationRequired(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setContextual(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setSemanticAction(@androidx.core.app.NotificationCompat.Action.SemanticAction int);
+ method public androidx.core.app.NotificationCompat.Action.Builder setShowsUserInterface(boolean);
+ }
+
+ public static interface NotificationCompat.Action.Extender {
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_NONE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_REPLY, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_UNREAD, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_DELETE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_ARCHIVE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_UNMUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_UP, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_DOWN, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_CALL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.Action.SemanticAction {
+ }
+
+ public static final class NotificationCompat.Action.WearableExtender implements androidx.core.app.NotificationCompat.Action.Extender {
+ ctor public NotificationCompat.Action.WearableExtender();
+ ctor public NotificationCompat.Action.WearableExtender(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender clone();
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+ method @Deprecated public CharSequence? getCancelLabel();
+ method @Deprecated public CharSequence? getConfirmLabel();
+ method public boolean getHintDisplayActionInline();
+ method public boolean getHintLaunchesActivity();
+ method @Deprecated public CharSequence? getInProgressLabel();
+ method public boolean isAvailableOffline();
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setCancelLabel(CharSequence?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setConfirmLabel(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintDisplayActionInline(boolean);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintLaunchesActivity(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setInProgressLabel(CharSequence?);
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.BADGE_ICON_NONE, androidx.core.app.NotificationCompat.BADGE_ICON_SMALL, androidx.core.app.NotificationCompat.BADGE_ICON_LARGE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.BadgeIconType {
+ }
+
+ public static class NotificationCompat.BigPictureStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigPictureStyle();
+ ctor public NotificationCompat.BigPictureStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap?);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.drawable.Icon?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.drawable.IconCompat? getPictureIcon(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle setBigContentTitle(CharSequence?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle setContentDescription(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle setSummaryText(CharSequence?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle showBigPictureWhenCollapsed(boolean);
+ }
+
+ public static class NotificationCompat.BigTextStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigTextStyle();
+ ctor public NotificationCompat.BigTextStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle bigText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle setBigContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle setSummaryText(CharSequence?);
+ }
+
+ public static final class NotificationCompat.BubbleMetadata {
+ method public static androidx.core.app.NotificationCompat.BubbleMetadata? fromPlatform(android.app.Notification.BubbleMetadata?);
+ method public boolean getAutoExpandBubble();
+ method public android.app.PendingIntent? getDeleteIntent();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public int getDesiredHeight();
+ method @DimenRes public int getDesiredHeightResId();
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public android.app.PendingIntent? getIntent();
+ method public String? getShortcutId();
+ method public boolean isNotificationSuppressed();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setFlags(int);
+ method public static android.app.Notification.BubbleMetadata? toPlatform(androidx.core.app.NotificationCompat.BubbleMetadata?);
+ }
+
+ public static final class NotificationCompat.BubbleMetadata.Builder {
+ ctor @Deprecated public NotificationCompat.BubbleMetadata.Builder();
+ ctor public NotificationCompat.BubbleMetadata.Builder(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat);
+ ctor @RequiresApi(30) public NotificationCompat.BubbleMetadata.Builder(String);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata build();
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setAutoExpandBubble(boolean);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeight(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIcon(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setSuppressNotification(boolean);
+ }
+
+ public static class NotificationCompat.Builder {
+ ctor @Deprecated public NotificationCompat.Builder(android.content.Context);
+ ctor @RequiresApi(19) public NotificationCompat.Builder(android.content.Context, android.app.Notification);
+ ctor public NotificationCompat.Builder(android.content.Context, String);
+ method public androidx.core.app.NotificationCompat.Builder addAction(androidx.core.app.NotificationCompat.Action?);
+ method public androidx.core.app.NotificationCompat.Builder addAction(int, CharSequence?, android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder addExtras(android.os.Bundle?);
+ method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(androidx.core.app.NotificationCompat.Action?);
+ method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(int, CharSequence?, android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder addPerson(androidx.core.app.Person?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder addPerson(String?);
+ method public android.app.Notification build();
+ method public androidx.core.app.NotificationCompat.Builder clearActions();
+ method public androidx.core.app.NotificationCompat.Builder clearInvisibleActions();
+ method public androidx.core.app.NotificationCompat.Builder clearPeople();
+ method public android.widget.RemoteViews? createBigContentView();
+ method public android.widget.RemoteViews? createContentView();
+ method public android.widget.RemoteViews? createHeadsUpContentView();
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Extender);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! getBigContentView();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.core.app.NotificationCompat.BubbleMetadata? getBubbleMetadata();
+ method @ColorInt @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getColor();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! getContentView();
+ method public android.os.Bundle getExtras();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getForegroundServiceBehavior();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! getHeadsUpContentView();
+ method @Deprecated public android.app.Notification getNotification();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getPriority();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public long getWhenIfShowing();
+ method protected static CharSequence? limitCharSequenceLength(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setAllowSystemGeneratedContextualActions(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setAutoCancel(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setBadgeIconType(@androidx.core.app.NotificationCompat.BadgeIconType int);
+ method public androidx.core.app.NotificationCompat.Builder setBubbleMetadata(androidx.core.app.NotificationCompat.BubbleMetadata?);
+ method public androidx.core.app.NotificationCompat.Builder setCategory(String?);
+ method public androidx.core.app.NotificationCompat.Builder setChannelId(String);
+ method @RequiresApi(24) public androidx.core.app.NotificationCompat.Builder setChronometerCountDown(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setColor(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.Builder setColorized(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setContent(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setContentInfo(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder setContentText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomBigContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomHeadsUpContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setDefaults(int);
+ method public androidx.core.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Builder setForegroundServiceBehavior(@androidx.core.app.NotificationCompat.ServiceNotificationBehavior int);
+ method public androidx.core.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent?, boolean);
+ method public androidx.core.app.NotificationCompat.Builder setGroup(String?);
+ method public androidx.core.app.NotificationCompat.Builder setGroupAlertBehavior(@androidx.core.app.NotificationCompat.GroupAlertBehavior int);
+ method public androidx.core.app.NotificationCompat.Builder setGroupSummary(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap?);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.Builder setLargeIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.Builder setLights(@ColorInt int, int, int);
+ method public androidx.core.app.NotificationCompat.Builder setLocalOnly(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
+ method public androidx.core.app.NotificationCompat.Builder setNumber(int);
+ method public androidx.core.app.NotificationCompat.Builder setOngoing(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setPriority(int);
+ method public androidx.core.app.NotificationCompat.Builder setProgress(int, int, boolean);
+ method public androidx.core.app.NotificationCompat.Builder setPublicVersion(android.app.Notification?);
+ method public androidx.core.app.NotificationCompat.Builder setRemoteInputHistory(CharSequence![]?);
+ method public androidx.core.app.NotificationCompat.Builder setSettingsText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setShortcutId(String?);
+ method public androidx.core.app.NotificationCompat.Builder setShortcutInfo(androidx.core.content.pm.ShortcutInfoCompat?);
+ method public androidx.core.app.NotificationCompat.Builder setShowWhen(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setSilent(boolean);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.Builder setSmallIcon(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int);
+ method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int, int);
+ method public androidx.core.app.NotificationCompat.Builder setSortKey(String?);
+ method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?);
+ method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?, @androidx.core.app.NotificationCompat.StreamType int);
+ method public androidx.core.app.NotificationCompat.Builder setStyle(androidx.core.app.NotificationCompat.Style?);
+ method public androidx.core.app.NotificationCompat.Builder setSubText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?, android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setTimeoutAfter(long);
+ method public androidx.core.app.NotificationCompat.Builder setUsesChronometer(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setVibrate(long[]?);
+ method public androidx.core.app.NotificationCompat.Builder setVisibility(@androidx.core.app.NotificationCompat.NotificationVisibility int);
+ method public androidx.core.app.NotificationCompat.Builder setWhen(long);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public java.util.ArrayList<androidx.core.app.NotificationCompat.Action!>! mActions;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.Context! mContext;
+ field @Deprecated public java.util.ArrayList<java.lang.String!>! mPeople;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public java.util.ArrayList<androidx.core.app.Person!> mPersonList;
+ }
+
+ public static class NotificationCompat.CallStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.CallStyle();
+ ctor public NotificationCompat.CallStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public static androidx.core.app.NotificationCompat.CallStyle forIncomingCall(androidx.core.app.Person, android.app.PendingIntent, android.app.PendingIntent);
+ method public static androidx.core.app.NotificationCompat.CallStyle forOngoingCall(androidx.core.app.Person, android.app.PendingIntent);
+ method public static androidx.core.app.NotificationCompat.CallStyle forScreeningCall(androidx.core.app.Person, android.app.PendingIntent, android.app.PendingIntent);
+ method @RequiresApi(20) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public java.util.ArrayList<androidx.core.app.NotificationCompat.Action!> getActionsListWithSystemActions();
+ method public androidx.core.app.NotificationCompat.CallStyle setAnswerButtonColorHint(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CallStyle setDeclineButtonColorHint(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CallStyle setIsVideo(boolean);
+ method public androidx.core.app.NotificationCompat.CallStyle setVerificationIcon(android.graphics.Bitmap?);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.CallStyle setVerificationIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.CallStyle setVerificationText(CharSequence?);
+ field public static final int CALL_TYPE_INCOMING = 1; // 0x1
+ field public static final int CALL_TYPE_ONGOING = 2; // 0x2
+ field public static final int CALL_TYPE_SCREENING = 3; // 0x3
+ field public static final int CALL_TYPE_UNKNOWN = 0; // 0x0
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.CallStyle.CALL_TYPE_UNKNOWN, androidx.core.app.NotificationCompat.CallStyle.CALL_TYPE_INCOMING, androidx.core.app.NotificationCompat.CallStyle.CALL_TYPE_ONGOING, androidx.core.app.NotificationCompat.CallStyle.CALL_TYPE_SCREENING}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.CallStyle.CallType {
+ }
+
+ public static final class NotificationCompat.CarExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.CarExtender();
+ ctor public NotificationCompat.CarExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method @ColorInt public int getColor();
+ method public android.graphics.Bitmap? getLargeIcon();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation? getUnreadConversation();
+ method public androidx.core.app.NotificationCompat.CarExtender setColor(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation?);
+ }
+
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+ method @Deprecated public long getLatestTimestamp();
+ method @Deprecated public String![]? getMessages();
+ method @Deprecated public String? getParticipant();
+ method @Deprecated public String![]? getParticipants();
+ method @Deprecated public android.app.PendingIntent? getReadPendingIntent();
+ method @Deprecated public androidx.core.app.RemoteInput? getRemoteInput();
+ method @Deprecated public android.app.PendingIntent? getReplyPendingIntent();
+ }
+
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(String?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation build();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent?, androidx.core.app.RemoteInput?);
+ }
+
+ public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.DecoratedCustomViewStyle();
+ }
+
+ public static interface NotificationCompat.Extender {
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.GROUP_ALERT_ALL, androidx.core.app.NotificationCompat.GROUP_ALERT_SUMMARY, androidx.core.app.NotificationCompat.GROUP_ALERT_CHILDREN}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.GroupAlertBehavior {
+ }
+
+ public static class NotificationCompat.InboxStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.InboxStyle();
+ ctor public NotificationCompat.InboxStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.InboxStyle addLine(CharSequence?);
+ method public androidx.core.app.NotificationCompat.InboxStyle setBigContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.InboxStyle setSummaryText(CharSequence?);
+ }
+
+ public static class NotificationCompat.MessagingStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.MessagingStyle(androidx.core.app.Person);
+ ctor @Deprecated public NotificationCompat.MessagingStyle(CharSequence);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addHistoricMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, androidx.core.app.Person?);
+ method @Deprecated public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, CharSequence?);
+ method public static androidx.core.app.NotificationCompat.MessagingStyle? extractMessagingStyleFromNotification(android.app.Notification);
+ method public CharSequence? getConversationTitle();
+ method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getHistoricMessages();
+ method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getMessages();
+ method public androidx.core.app.Person getUser();
+ method @Deprecated public CharSequence? getUserDisplayName();
+ method public boolean isGroupConversation();
+ method public androidx.core.app.NotificationCompat.MessagingStyle setConversationTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle setGroupConversation(boolean);
+ field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
+ }
+
+ public static final class NotificationCompat.MessagingStyle.Message {
+ ctor public NotificationCompat.MessagingStyle.Message(CharSequence?, long, androidx.core.app.Person?);
+ ctor @Deprecated public NotificationCompat.MessagingStyle.Message(CharSequence?, long, CharSequence?);
+ method public String? getDataMimeType();
+ method public android.net.Uri? getDataUri();
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.Person? getPerson();
+ method @Deprecated public CharSequence? getSender();
+ method public CharSequence? getText();
+ method public long getTimestamp();
+ method public androidx.core.app.NotificationCompat.MessagingStyle.Message setData(String?, android.net.Uri?);
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC, androidx.core.app.NotificationCompat.VISIBILITY_PRIVATE, androidx.core.app.NotificationCompat.VISIBILITY_SECRET}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.NotificationVisibility {
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_DEFAULT, androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE, androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_DEFERRED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.ServiceNotificationBehavior {
+ }
+
+ @IntDef({android.media.AudioManager.STREAM_VOICE_CALL, android.media.AudioManager.STREAM_SYSTEM, android.media.AudioManager.STREAM_RING, android.media.AudioManager.STREAM_MUSIC, android.media.AudioManager.STREAM_ALARM, android.media.AudioManager.STREAM_NOTIFICATION, android.media.AudioManager.STREAM_DTMF, android.media.AudioManager.STREAM_ACCESSIBILITY}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.StreamType {
+ }
+
+ public abstract static class NotificationCompat.Style {
+ ctor public NotificationCompat.Style();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void addCompatExtras(android.os.Bundle);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void apply(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews applyStandardTemplate(boolean, int, boolean);
+ method public android.app.Notification? build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void buildIntoRemoteViews(android.widget.RemoteViews!, android.widget.RemoteViews!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected void clearCompatExtraKeys(android.os.Bundle);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.graphics.Bitmap! createColoredBitmap(int, int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean displayCustomViewInline();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.NotificationCompat.Style? extractStyleFromNotification(android.app.Notification);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected String? getClassName();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! makeBigContentView(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! makeContentView(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! makeHeadsUpContentView(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected void restoreFromCompatExtras(android.os.Bundle);
+ method public void setBuilder(androidx.core.app.NotificationCompat.Builder?);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected androidx.core.app.NotificationCompat.Builder! mBuilder;
+ }
+
+ public static final class NotificationCompat.TvExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.TvExtender();
+ ctor public NotificationCompat.TvExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method public String? getChannelId();
+ method public android.app.PendingIntent? getContentIntent();
+ method public android.app.PendingIntent? getDeleteIntent();
+ method public boolean isAvailableOnTv();
+ method public boolean isSuppressShowOverApps();
+ method public androidx.core.app.NotificationCompat.TvExtender setChannelId(String?);
+ method public androidx.core.app.NotificationCompat.TvExtender setContentIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.TvExtender setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.TvExtender setSuppressShowOverApps(boolean);
+ }
+
+ public static final class NotificationCompat.WearableExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.WearableExtender();
+ ctor public NotificationCompat.WearableExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.WearableExtender addAction(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.WearableExtender addActions(java.util.List<androidx.core.app.NotificationCompat.Action!>);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification!>);
+ method public androidx.core.app.NotificationCompat.WearableExtender clearActions();
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender clearPages();
+ method public androidx.core.app.NotificationCompat.WearableExtender clone();
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method public java.util.List<androidx.core.app.NotificationCompat.Action!> getActions();
+ method @Deprecated public android.graphics.Bitmap? getBackground();
+ method public String? getBridgeTag();
+ method public int getContentAction();
+ method @Deprecated public int getContentIcon();
+ method @Deprecated public int getContentIconGravity();
+ method public boolean getContentIntentAvailableOffline();
+ method @Deprecated public int getCustomContentHeight();
+ method @Deprecated public int getCustomSizePreset();
+ method public String? getDismissalId();
+ method @Deprecated public android.app.PendingIntent? getDisplayIntent();
+ method @Deprecated public int getGravity();
+ method @Deprecated public boolean getHintAmbientBigPicture();
+ method @Deprecated public boolean getHintAvoidBackgroundClipping();
+ method public boolean getHintContentIntentLaunchesActivity();
+ method @Deprecated public boolean getHintHideIcon();
+ method @Deprecated public int getHintScreenTimeout();
+ method @Deprecated public boolean getHintShowBackgroundOnly();
+ method @Deprecated public java.util.List<android.app.Notification!> getPages();
+ method public boolean getStartScrollBottom();
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap?);
+ method public androidx.core.app.NotificationCompat.WearableExtender setBridgeTag(String?);
+ method public androidx.core.app.NotificationCompat.WearableExtender setContentAction(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIcon(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+ method public androidx.core.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+ method public androidx.core.app.NotificationCompat.WearableExtender setDismissalId(String?);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent?);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setGravity(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAmbientBigPicture(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+ method public androidx.core.app.NotificationCompat.WearableExtender setHintContentIntentLaunchesActivity(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+ method public androidx.core.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+ field @Deprecated public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+ field @Deprecated public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+ field @Deprecated public static final int SIZE_DEFAULT = 0; // 0x0
+ field @Deprecated public static final int SIZE_FULL_SCREEN = 5; // 0x5
+ field @Deprecated public static final int SIZE_LARGE = 4; // 0x4
+ field @Deprecated public static final int SIZE_MEDIUM = 3; // 0x3
+ field @Deprecated public static final int SIZE_SMALL = 2; // 0x2
+ field @Deprecated public static final int SIZE_XSMALL = 1; // 0x1
+ field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+ }
+
+ public final class NotificationCompatExtras {
+ field public static final String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+ field public static final String EXTRA_GROUP_KEY = "android.support.groupKey";
+ field public static final String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+ field public static final String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+ field public static final String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+ field public static final String EXTRA_SORT_KEY = "android.support.sortKey";
+ }
+
+ public abstract class NotificationCompatSideChannelService extends android.app.Service {
+ ctor public NotificationCompatSideChannelService();
+ method public abstract void cancel(String!, int, String!);
+ method public abstract void cancelAll(String!);
+ method public abstract void notify(String!, int, String!, android.app.Notification!);
+ method public android.os.IBinder! onBind(android.content.Intent!);
+ }
+
+ public final class NotificationManagerCompat {
+ method public boolean areNotificationsEnabled();
+ method public void cancel(int);
+ method public void cancel(String?, int);
+ method public void cancelAll();
+ method public void createNotificationChannel(android.app.NotificationChannel);
+ method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+ method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
+ method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+ method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup!>);
+ method public void createNotificationChannelGroupsCompat(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+ method public void createNotificationChannels(java.util.List<android.app.NotificationChannel!>);
+ method public void createNotificationChannelsCompat(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.core.app.NotificationManagerCompat from(android.content.Context);
+ method public java.util.List<android.service.notification.StatusBarNotification!> getActiveNotifications();
+ method @androidx.core.app.NotificationManagerCompat.InterruptionFilter public int getCurrentInterruptionFilter();
+ method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+ method public int getImportance();
+ method public android.app.NotificationChannel? getNotificationChannel(String);
+ method public android.app.NotificationChannel? getNotificationChannel(String, String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String, String);
+ method public android.app.NotificationChannelGroup? getNotificationChannelGroup(String);
+ method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroupCompat(String);
+ method public java.util.List<android.app.NotificationChannelGroup!> getNotificationChannelGroups();
+ method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroupsCompat();
+ method public java.util.List<android.app.NotificationChannel!> getNotificationChannels();
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannelsCompat();
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(int, android.app.Notification);
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(String?, int, android.app.Notification);
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(java.util.List<androidx.core.app.NotificationManagerCompat.NotificationWithIdAndTag!>);
+ field public static final String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+ field public static final String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+ field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+ field public static final int IMPORTANCE_HIGH = 4; // 0x4
+ field public static final int IMPORTANCE_LOW = 2; // 0x2
+ field public static final int IMPORTANCE_MAX = 5; // 0x5
+ field public static final int IMPORTANCE_MIN = 1; // 0x1
+ field public static final int IMPORTANCE_NONE = 0; // 0x0
+ field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
+ field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
+ field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
+ field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
+ field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
+ field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
+ }
+
+ @IntDef({androidx.core.app.NotificationManagerCompat.INTERRUPTION_FILTER_UNKNOWN, androidx.core.app.NotificationManagerCompat.INTERRUPTION_FILTER_ALL, androidx.core.app.NotificationManagerCompat.INTERRUPTION_FILTER_PRIORITY, androidx.core.app.NotificationManagerCompat.INTERRUPTION_FILTER_NONE, androidx.core.app.NotificationManagerCompat.INTERRUPTION_FILTER_ALARMS}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationManagerCompat.InterruptionFilter {
+ }
+
+ public static class NotificationManagerCompat.NotificationWithIdAndTag {
+ ctor public NotificationManagerCompat.NotificationWithIdAndTag(int, android.app.Notification);
+ ctor public NotificationManagerCompat.NotificationWithIdAndTag(String?, int, android.app.Notification);
+ }
+
+ public interface OnMultiWindowModeChangedProvider {
+ method public void addOnMultiWindowModeChangedListener(androidx.core.util.Consumer<androidx.core.app.MultiWindowModeChangedInfo!>);
+ method public void removeOnMultiWindowModeChangedListener(androidx.core.util.Consumer<androidx.core.app.MultiWindowModeChangedInfo!>);
+ }
+
+ public interface OnNewIntentProvider {
+ method public void addOnNewIntentListener(androidx.core.util.Consumer<android.content.Intent!>);
+ method public void removeOnNewIntentListener(androidx.core.util.Consumer<android.content.Intent!>);
+ }
+
+ public interface OnPictureInPictureModeChangedProvider {
+ method public void addOnPictureInPictureModeChangedListener(androidx.core.util.Consumer<androidx.core.app.PictureInPictureModeChangedInfo!>);
+ method public void removeOnPictureInPictureModeChangedListener(androidx.core.util.Consumer<androidx.core.app.PictureInPictureModeChangedInfo!>);
+ }
+
+ public final class PendingIntentCompat {
+ method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent![], int, android.os.Bundle, boolean);
+ method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent![], int, boolean);
+ method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, android.os.Bundle, boolean);
+ method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, boolean);
+ method public static android.app.PendingIntent? getBroadcast(android.content.Context, int, android.content.Intent, int, boolean);
+ method @RequiresApi(26) public static android.app.PendingIntent getForegroundService(android.content.Context, int, android.content.Intent, int, boolean);
+ method public static android.app.PendingIntent getService(android.content.Context, int, android.content.Intent, int, boolean);
+ }
+
+ public class Person {
+ method @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.Person fromAndroidPerson(android.app.Person);
+ method public static androidx.core.app.Person fromBundle(android.os.Bundle);
+ method @RequiresApi(22) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.Person fromPersistableBundle(android.os.PersistableBundle);
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public String? getKey();
+ method public CharSequence? getName();
+ method public String? getUri();
+ method public boolean isBot();
+ method public boolean isImportant();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public String resolveToLegacyUri();
+ method @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.app.Person toAndroidPerson();
+ method public androidx.core.app.Person.Builder toBuilder();
+ method public android.os.Bundle toBundle();
+ method @RequiresApi(22) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.os.PersistableBundle toPersistableBundle();
+ }
+
+ public static class Person.Builder {
+ ctor public Person.Builder();
+ method public androidx.core.app.Person build();
+ method public androidx.core.app.Person.Builder setBot(boolean);
+ method public androidx.core.app.Person.Builder setIcon(androidx.core.graphics.drawable.IconCompat?);
+ method public androidx.core.app.Person.Builder setImportant(boolean);
+ method public androidx.core.app.Person.Builder setKey(String?);
+ method public androidx.core.app.Person.Builder setName(CharSequence?);
+ method public androidx.core.app.Person.Builder setUri(String?);
+ }
+
+ public final class PictureInPictureModeChangedInfo {
+ ctor public PictureInPictureModeChangedInfo(boolean);
+ ctor @RequiresApi(26) public PictureInPictureModeChangedInfo(boolean, android.content.res.Configuration);
+ method @RequiresApi(26) public android.content.res.Configuration getNewConfig();
+ method public boolean isInPictureInPictureMode();
+ }
+
+ @androidx.versionedparcelable.VersionedParcelize(jetifyAs="android.support.v4.app.RemoteActionCompat") public final class RemoteActionCompat implements androidx.versionedparcelable.VersionedParcelable {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public RemoteActionCompat();
+ ctor public RemoteActionCompat(androidx.core.app.RemoteActionCompat);
+ ctor public RemoteActionCompat(androidx.core.graphics.drawable.IconCompat, CharSequence, CharSequence, android.app.PendingIntent);
+ method @RequiresApi(26) public static androidx.core.app.RemoteActionCompat createFromRemoteAction(android.app.RemoteAction);
+ method public android.app.PendingIntent getActionIntent();
+ method public CharSequence getContentDescription();
+ method public androidx.core.graphics.drawable.IconCompat getIcon();
+ method public CharSequence getTitle();
+ method public boolean isEnabled();
+ method public void setEnabled(boolean);
+ method public void setShouldShowIcon(boolean);
+ method public boolean shouldShowIcon();
+ method @RequiresApi(26) public android.app.RemoteAction toRemoteAction();
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(4) public android.app.PendingIntent mActionIntent;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(3) public CharSequence mContentDescription;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(5) public boolean mEnabled;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(1) public androidx.core.graphics.drawable.IconCompat mIcon;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(6) public boolean mShouldShowIcon;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(2) public CharSequence mTitle;
+ }
+
+ public final class RemoteInput {
+ method public static void addDataResultToIntent(androidx.core.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String!,android.net.Uri!>);
+ method public static void addResultsToIntent(androidx.core.app.RemoteInput![], android.content.Intent, android.os.Bundle);
+ method public boolean getAllowFreeFormInput();
+ method public java.util.Set<java.lang.String!>? getAllowedDataTypes();
+ method public CharSequence![]? getChoices();
+ method public static java.util.Map<java.lang.String!,android.net.Uri!>? getDataResultsFromIntent(android.content.Intent, String);
+ method @androidx.core.app.RemoteInput.EditChoicesBeforeSending public int getEditChoicesBeforeSending();
+ method public android.os.Bundle getExtras();
+ method public CharSequence? getLabel();
+ method public String getResultKey();
+ method public static android.os.Bundle? getResultsFromIntent(android.content.Intent);
+ method @androidx.core.app.RemoteInput.Source public static int getResultsSource(android.content.Intent);
+ method public boolean isDataOnly();
+ method public static void setResultsSource(android.content.Intent, @androidx.core.app.RemoteInput.Source int);
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; // 0x0
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; // 0x1
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; // 0x2
+ field public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+ field public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+ field public static final int SOURCE_CHOICE = 1; // 0x1
+ field public static final int SOURCE_FREE_FORM_INPUT = 0; // 0x0
+ }
+
+ public static final class RemoteInput.Builder {
+ ctor public RemoteInput.Builder(String);
+ method public androidx.core.app.RemoteInput.Builder addExtras(android.os.Bundle);
+ method public androidx.core.app.RemoteInput build();
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.RemoteInput.Builder setAllowDataType(String, boolean);
+ method public androidx.core.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+ method public androidx.core.app.RemoteInput.Builder setChoices(CharSequence![]?);
+ method public androidx.core.app.RemoteInput.Builder setEditChoicesBeforeSending(@androidx.core.app.RemoteInput.EditChoicesBeforeSending int);
+ method public androidx.core.app.RemoteInput.Builder setLabel(CharSequence?);
+ }
+
+ @IntDef({androidx.core.app.RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO, androidx.core.app.RemoteInput.EDIT_CHOICES_BEFORE_SENDING_DISABLED, androidx.core.app.RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RemoteInput.EditChoicesBeforeSending {
+ }
+
+ @IntDef({androidx.core.app.RemoteInput.SOURCE_FREE_FORM_INPUT, androidx.core.app.RemoteInput.SOURCE_CHOICE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RemoteInput.Source {
+ }
+
+ public final class ServiceCompat {
+ method public static void stopForeground(android.app.Service, @androidx.core.app.ServiceCompat.StopForegroundFlags int);
+ field public static final int START_STICKY = 1; // 0x1
+ field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+ field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
+ }
+
+ @IntDef(flag=true, value={androidx.core.app.ServiceCompat.STOP_FOREGROUND_REMOVE, androidx.core.app.ServiceCompat.STOP_FOREGROUND_DETACH}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ServiceCompat.StopForegroundFlags {
+ }
+
+ public final class ShareCompat {
+ method @Deprecated public static void configureMenuItem(android.view.Menu, @IdRes int, androidx.core.app.ShareCompat.IntentBuilder);
+ method @Deprecated public static void configureMenuItem(android.view.MenuItem, androidx.core.app.ShareCompat.IntentBuilder);
+ method public static android.content.ComponentName? getCallingActivity(android.app.Activity);
+ method public static String? getCallingPackage(android.app.Activity);
+ field public static final String EXTRA_CALLING_ACTIVITY = "androidx.core.app.EXTRA_CALLING_ACTIVITY";
+ field public static final String EXTRA_CALLING_ACTIVITY_INTEROP = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+ field public static final String EXTRA_CALLING_PACKAGE = "androidx.core.app.EXTRA_CALLING_PACKAGE";
+ field public static final String EXTRA_CALLING_PACKAGE_INTEROP = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+ }
+
+ public static class ShareCompat.IntentBuilder {
+ ctor public ShareCompat.IntentBuilder(android.content.Context);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+ method public android.content.Intent createChooserIntent();
+ method @Deprecated public static androidx.core.app.ShareCompat.IntentBuilder from(android.app.Activity);
+ method public android.content.Intent getIntent();
+ method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(@StringRes int);
+ method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(CharSequence?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailBcc(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailCc(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailTo(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setHtmlText(String?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setStream(android.net.Uri?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setSubject(String?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setText(CharSequence?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setType(String?);
+ method public void startChooser();
+ }
+
+ public static class ShareCompat.IntentReader {
+ ctor public ShareCompat.IntentReader(android.app.Activity);
+ ctor public ShareCompat.IntentReader(android.content.Context, android.content.Intent);
+ method @Deprecated public static androidx.core.app.ShareCompat.IntentReader from(android.app.Activity);
+ method public android.content.ComponentName? getCallingActivity();
+ method public android.graphics.drawable.Drawable? getCallingActivityIcon();
+ method public android.graphics.drawable.Drawable? getCallingApplicationIcon();
+ method public CharSequence? getCallingApplicationLabel();
+ method public String? getCallingPackage();
+ method public String![]? getEmailBcc();
+ method public String![]? getEmailCc();
+ method public String![]? getEmailTo();
+ method public String? getHtmlText();
+ method public android.net.Uri? getStream();
+ method public android.net.Uri? getStream(int);
+ method public int getStreamCount();
+ method public String? getSubject();
+ method public CharSequence? getText();
+ method public String? getType();
+ method public boolean isMultipleShare();
+ method public boolean isShareIntent();
+ method public boolean isSingleShare();
+ }
+
+ public abstract class SharedElementCallback {
+ ctor public SharedElementCallback();
+ method public android.os.Parcelable! onCaptureSharedElementSnapshot(android.view.View!, android.graphics.Matrix!, android.graphics.RectF!);
+ method public android.view.View! onCreateSnapshotView(android.content.Context!, android.os.Parcelable!);
+ method public void onMapSharedElements(java.util.List<java.lang.String!>!, java.util.Map<java.lang.String!,android.view.View!>!);
+ method public void onRejectSharedElements(java.util.List<android.view.View!>!);
+ method public void onSharedElementEnd(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+ method public void onSharedElementStart(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+ method public void onSharedElementsArrived(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, androidx.core.app.SharedElementCallback.OnSharedElementsReadyListener!);
+ }
+
+ public static interface SharedElementCallback.OnSharedElementsReadyListener {
+ method public void onSharedElementsReady();
+ }
+
+ public final class TaskStackBuilder implements java.lang.Iterable<android.content.Intent> {
+ method public androidx.core.app.TaskStackBuilder addNextIntent(android.content.Intent);
+ method public androidx.core.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+ method public androidx.core.app.TaskStackBuilder addParentStack(android.app.Activity);
+ method public androidx.core.app.TaskStackBuilder addParentStack(android.content.ComponentName);
+ method public androidx.core.app.TaskStackBuilder addParentStack(Class<?>);
+ method public static androidx.core.app.TaskStackBuilder create(android.content.Context);
+ method public android.content.Intent? editIntentAt(int);
+ method @Deprecated public static androidx.core.app.TaskStackBuilder! from(android.content.Context!);
+ method @Deprecated public android.content.Intent! getIntent(int);
+ method public int getIntentCount();
+ method public android.content.Intent![] getIntents();
+ method public android.app.PendingIntent? getPendingIntent(int, int);
+ method public android.app.PendingIntent? getPendingIntent(int, int, android.os.Bundle?);
+ method @Deprecated public java.util.Iterator<android.content.Intent!> iterator();
+ method public void startActivities();
+ method public void startActivities(android.os.Bundle?);
+ }
+
+ public static interface TaskStackBuilder.SupportParentable {
+ method public android.content.Intent? getSupportParentActivityIntent();
+ }
+
+}
+
+package androidx.core.content {
+
+ public final class ContentProviderCompat {
+ method public static android.content.Context requireContext(android.content.ContentProvider);
+ }
+
+ public final class ContentResolverCompat {
+ method public static android.database.Cursor? query(android.content.ContentResolver, android.net.Uri, String![]?, String?, String![]?, String?, androidx.core.os.CancellationSignal?);
+ }
+
+ public class ContextCompat {
+ ctor protected ContextCompat();
+ method public static int checkSelfPermission(android.content.Context, String);
+ method public static android.content.Context? createDeviceProtectedStorageContext(android.content.Context);
+ method public static String? getAttributionTag(android.content.Context);
+ method public static java.io.File getCodeCacheDir(android.content.Context);
+ method @ColorInt public static int getColor(android.content.Context, @ColorRes int);
+ method public static android.content.res.ColorStateList? getColorStateList(android.content.Context, @ColorRes int);
+ method public static android.content.Context getContextForLanguage(android.content.Context);
+ method public static java.io.File? getDataDir(android.content.Context);
+ method public static android.view.Display getDisplayOrDefault(@DisplayContext android.content.Context);
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
+ method public static java.io.File![] getExternalCacheDirs(android.content.Context);
+ method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
+ method public static java.util.concurrent.Executor getMainExecutor(android.content.Context);
+ method public static java.io.File? getNoBackupFilesDir(android.content.Context);
+ method public static java.io.File![] getObbDirs(android.content.Context);
+ method public static String getString(android.content.Context, int);
+ method public static <T> T? getSystemService(android.content.Context, Class<T!>);
+ method public static String? getSystemServiceName(android.content.Context, Class<?>);
+ method public static boolean isDeviceProtectedStorage(android.content.Context);
+ method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, int);
+ method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, String?, android.os.Handler?, int);
+ method public static boolean startActivities(android.content.Context, android.content.Intent![]);
+ method public static boolean startActivities(android.content.Context, android.content.Intent![], android.os.Bundle?);
+ method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
+ method public static void startForegroundService(android.content.Context, android.content.Intent);
+ field public static final int RECEIVER_EXPORTED = 2; // 0x2
+ field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
+ field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
+ }
+
+ public class FileProvider extends android.content.ContentProvider {
+ ctor public FileProvider();
+ ctor protected FileProvider(@XmlRes int);
+ method public int delete(android.net.Uri, String?, String![]?);
+ method public String? getType(android.net.Uri);
+ method public String? getTypeAnonymous(android.net.Uri);
+ method public static android.net.Uri! getUriForFile(android.content.Context, String, java.io.File);
+ method public static android.net.Uri getUriForFile(android.content.Context, String, java.io.File, String);
+ method public android.net.Uri! insert(android.net.Uri, android.content.ContentValues);
+ method public boolean onCreate();
+ method public android.database.Cursor query(android.net.Uri, String![]?, String?, String![]?, String?);
+ method public int update(android.net.Uri, android.content.ContentValues, String?, String![]?);
+ }
+
+ public final class IntentCompat {
+ method public static android.content.Intent createManageUnusedAppRestrictionsIntent(android.content.Context, String);
+ method public static android.os.Parcelable![]? getParcelableArrayExtra(android.content.Intent, String?, Class<? extends android.os.Parcelable>);
+ method public static <T> java.util.ArrayList<T!>? getParcelableArrayListExtra(android.content.Intent, String?, Class<? extends T>);
+ method public static <T> T? getParcelableExtra(android.content.Intent, String?, Class<T!>);
+ method public static android.content.Intent makeMainSelectorActivity(String, String);
+ field public static final String ACTION_CREATE_REMINDER = "android.intent.action.CREATE_REMINDER";
+ field public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+ field public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+ field public static final String EXTRA_START_PLAYBACK = "android.intent.extra.START_PLAYBACK";
+ field public static final String EXTRA_TIME = "android.intent.extra.TIME";
+ }
+
+ public class IntentSanitizer {
+ method public android.content.Intent sanitize(android.content.Intent, androidx.core.util.Consumer<java.lang.String!>);
+ method public android.content.Intent sanitizeByFiltering(android.content.Intent);
+ method public android.content.Intent sanitizeByThrowing(android.content.Intent);
+ }
+
+ public static final class IntentSanitizer.Builder {
+ ctor public IntentSanitizer.Builder();
+ method public androidx.core.content.IntentSanitizer.Builder allowAction(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowAction(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowAnyComponent();
+ method public androidx.core.content.IntentSanitizer.Builder allowCategory(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowCategory(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipData(androidx.core.util.Predicate<android.content.ClipData!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataText();
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataUri(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataUriWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponent(android.content.ComponentName);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponent(androidx.core.util.Predicate<android.content.ComponentName!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponentWithPackage(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowData(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowDataWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtra(String, androidx.core.util.Predicate<java.lang.Object!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtra(String, Class<?>);
+ method public <T> androidx.core.content.IntentSanitizer.Builder allowExtra(String, Class<T!>, androidx.core.util.Predicate<T!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraOutput(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraOutput(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraStream(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraStreamUriWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowFlags(int);
+ method public androidx.core.content.IntentSanitizer.Builder allowHistoryStackFlags();
+ method public androidx.core.content.IntentSanitizer.Builder allowIdentifier();
+ method public androidx.core.content.IntentSanitizer.Builder allowPackage(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowPackage(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowReceiverFlags();
+ method public androidx.core.content.IntentSanitizer.Builder allowSelector();
+ method public androidx.core.content.IntentSanitizer.Builder allowSourceBounds();
+ method public androidx.core.content.IntentSanitizer.Builder allowType(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowType(String);
+ method public androidx.core.content.IntentSanitizer build();
+ }
+
+ public final class LocusIdCompat {
+ ctor public LocusIdCompat(String);
+ method public String getId();
+ method @RequiresApi(29) public android.content.LocusId toLocusId();
+ method @RequiresApi(29) public static androidx.core.content.LocusIdCompat toLocusIdCompat(android.content.LocusId);
+ }
+
+ public final class MimeTypeFilter {
+ method public static boolean matches(String?, String);
+ method public static String? matches(String?, String![]);
+ method public static String? matches(String![]?, String);
+ method public static String![] matchesMany(String![]?, String);
+ }
+
+ public interface OnConfigurationChangedProvider {
+ method public void addOnConfigurationChangedListener(androidx.core.util.Consumer<android.content.res.Configuration!>);
+ method public void removeOnConfigurationChangedListener(androidx.core.util.Consumer<android.content.res.Configuration!>);
+ }
+
+ public interface OnTrimMemoryProvider {
+ method public void addOnTrimMemoryListener(androidx.core.util.Consumer<java.lang.Integer!>);
+ method public void removeOnTrimMemoryListener(androidx.core.util.Consumer<java.lang.Integer!>);
+ }
+
+ public final class PackageManagerCompat {
+ method public static com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> getUnusedAppRestrictionsStatus(android.content.Context);
+ field public static final String ACTION_PERMISSION_REVOCATION_SETTINGS = "android.intent.action.AUTO_REVOKE_PERMISSIONS";
+ }
+
+ public final class PermissionChecker {
+ method @androidx.core.content.PermissionChecker.PermissionResult public static int checkCallingOrSelfPermission(android.content.Context, String);
+ method @androidx.core.content.PermissionChecker.PermissionResult public static int checkCallingPermission(android.content.Context, String, String?);
+ method @androidx.core.content.PermissionChecker.PermissionResult public static int checkPermission(android.content.Context, String, int, int, String?);
+ method @androidx.core.content.PermissionChecker.PermissionResult public static int checkSelfPermission(android.content.Context, String);
+ field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+ field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+ field public static final int PERMISSION_GRANTED = 0; // 0x0
+ }
+
+ @IntDef({androidx.core.content.PermissionChecker.PERMISSION_GRANTED, androidx.core.content.PermissionChecker.PERMISSION_DENIED, androidx.core.content.PermissionChecker.PERMISSION_DENIED_APP_OP}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PermissionChecker.PermissionResult {
+ }
+
+ @Deprecated public final class SharedPreferencesCompat {
+ }
+
+ @Deprecated public static final class SharedPreferencesCompat.EditorCompat {
+ method @Deprecated public void apply(android.content.SharedPreferences.Editor);
+ method @Deprecated public static androidx.core.content.SharedPreferencesCompat.EditorCompat! getInstance();
+ }
+
+ public class UnusedAppRestrictionsBackportCallback {
+ method public void onResult(boolean, boolean) throws android.os.RemoteException;
+ }
+
+ public abstract class UnusedAppRestrictionsBackportService extends android.app.Service {
+ ctor public UnusedAppRestrictionsBackportService();
+ method protected abstract void isPermissionRevocationEnabled(androidx.core.content.UnusedAppRestrictionsBackportCallback);
+ method public android.os.IBinder? onBind(android.content.Intent?);
+ field public static final String ACTION_UNUSED_APP_RESTRICTIONS_BACKPORT_CONNECTION = "android.support.unusedapprestrictions.action.CustomUnusedAppRestrictionsBackportService";
+ }
+
+ public final class UnusedAppRestrictionsConstants {
+ field public static final int API_30 = 4; // 0x4
+ field public static final int API_30_BACKPORT = 3; // 0x3
+ field public static final int API_31 = 5; // 0x5
+ field public static final int DISABLED = 2; // 0x2
+ field public static final int ERROR = 0; // 0x0
+ field public static final int FEATURE_NOT_AVAILABLE = 1; // 0x1
+ }
+
+ public class UriMatcherCompat {
+ method public static androidx.core.util.Predicate<android.net.Uri!> asPredicate(android.content.UriMatcher);
+ }
+
+}
+
+package androidx.core.content.pm {
+
+ @Deprecated public final class ActivityInfoCompat {
+ field @Deprecated public static final int CONFIG_UI_MODE = 512; // 0x200
+ }
+
+ public final class PackageInfoCompat {
+ method public static long getLongVersionCode(android.content.pm.PackageInfo);
+ method public static java.util.List<android.content.pm.Signature!> getSignatures(android.content.pm.PackageManager, String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static boolean hasSignatures(android.content.pm.PackageManager, String, @Size(min=1) java.util.Map<byte[]!,java.lang.Integer!>, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
+ }
+
+ public final class PermissionInfoCompat {
+ method public static int getProtection(android.content.pm.PermissionInfo);
+ method public static int getProtectionFlags(android.content.pm.PermissionInfo);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class ShortcutInfoChangeListener {
+ ctor public ShortcutInfoChangeListener();
+ method @AnyThread public void onAllShortcutsRemoved();
+ method @AnyThread public void onShortcutAdded(java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method @AnyThread public void onShortcutRemoved(java.util.List<java.lang.String!>);
+ method @AnyThread public void onShortcutUpdated(java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method @AnyThread public void onShortcutUsageReported(java.util.List<java.lang.String!>);
+ }
+
+ public class ShortcutInfoCompat {
+ method public android.content.ComponentName? getActivity();
+ method public java.util.Set<java.lang.String!>? getCategories();
+ method public CharSequence? getDisabledMessage();
+ method public int getDisabledReason();
+ method @androidx.core.content.pm.ShortcutInfoCompat.Surface public int getExcludedFromSurfaces();
+ method public android.os.PersistableBundle? getExtras();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.core.graphics.drawable.IconCompat! getIcon();
+ method public String getId();
+ method public android.content.Intent getIntent();
+ method public android.content.Intent![] getIntents();
+ method public long getLastChangedTimestamp();
+ method public androidx.core.content.LocusIdCompat? getLocusId();
+ method public CharSequence? getLongLabel();
+ method public String getPackage();
+ method public int getRank();
+ method public CharSequence getShortLabel();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.os.Bundle? getTransientExtras();
+ method public android.os.UserHandle? getUserHandle();
+ method public boolean hasKeyFieldsOnly();
+ method public boolean isCached();
+ method public boolean isDeclaredInManifest();
+ method public boolean isDynamic();
+ method public boolean isEnabled();
+ method public boolean isExcludedFromSurfaces(@androidx.core.content.pm.ShortcutInfoCompat.Surface int);
+ method public boolean isImmutable();
+ method public boolean isPinned();
+ method @RequiresApi(25) public android.content.pm.ShortcutInfo! toShortcutInfo();
+ field public static final int SURFACE_LAUNCHER = 1; // 0x1
+ }
+
+ public static class ShortcutInfoCompat.Builder {
+ ctor @RequiresApi(25) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public ShortcutInfoCompat.Builder(android.content.Context, android.content.pm.ShortcutInfo);
+ ctor public ShortcutInfoCompat.Builder(android.content.Context, String);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public ShortcutInfoCompat.Builder(androidx.core.content.pm.ShortcutInfoCompat);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder addCapabilityBinding(String);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder addCapabilityBinding(String, String, java.util.List<java.lang.String!>);
+ method public androidx.core.content.pm.ShortcutInfoCompat build();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setActivity(android.content.ComponentName);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setAlwaysBadged();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setCategories(java.util.Set<java.lang.String!>);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setDisabledMessage(CharSequence);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExcludedFromSurfaces(int);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExtras(android.os.PersistableBundle);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIcon(androidx.core.graphics.drawable.IconCompat!);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntent(android.content.Intent);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntents(android.content.Intent![]);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIsConversation();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLabel(CharSequence);
+ method @Deprecated public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived(boolean);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPerson(androidx.core.app.Person);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPersons(androidx.core.app.Person![]);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setRank(int);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setShortLabel(CharSequence);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setSliceUri(android.net.Uri);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.core.content.pm.ShortcutInfoCompat.Builder setTransientExtras(android.os.Bundle);
+ }
+
+ @IntDef(flag=true, value={androidx.core.content.pm.ShortcutInfoCompat.SURFACE_LAUNCHER}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ShortcutInfoCompat.Surface {
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class ShortcutInfoCompatSaver<T> {
+ ctor public ShortcutInfoCompatSaver();
+ method @AnyThread public abstract T! addShortcuts(java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>!);
+ method @WorkerThread public java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>! getShortcuts() throws java.lang.Exception;
+ method @AnyThread public abstract T! removeAllShortcuts();
+ method @AnyThread public abstract T! removeShortcuts(java.util.List<java.lang.String!>!);
+ }
+
+ public class ShortcutManagerCompat {
+ method public static boolean addDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static android.content.Intent createShortcutResultIntent(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+ method public static void disableShortcuts(android.content.Context, java.util.List<java.lang.String!>, CharSequence?);
+ method public static void enableShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getDynamicShortcuts(android.content.Context);
+ method public static int getIconMaxHeight(android.content.Context);
+ method public static int getIconMaxWidth(android.content.Context);
+ method public static int getMaxShortcutCountPerActivity(android.content.Context);
+ method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getShortcuts(android.content.Context, @androidx.core.content.pm.ShortcutManagerCompat.ShortcutMatchFlags int);
+ method public static boolean isRateLimitingActive(android.content.Context);
+ method public static boolean isRequestPinShortcutSupported(android.content.Context);
+ method public static boolean pushDynamicShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+ method public static void removeAllDynamicShortcuts(android.content.Context);
+ method public static void removeDynamicShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+ method public static void removeLongLivedShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+ method public static void reportShortcutUsed(android.content.Context, String);
+ method public static boolean requestPinShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat, android.content.IntentSender?);
+ method public static boolean setDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static boolean updateShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ field public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
+ field public static final int FLAG_MATCH_CACHED = 8; // 0x8
+ field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2
+ field public static final int FLAG_MATCH_MANIFEST = 1; // 0x1
+ field public static final int FLAG_MATCH_PINNED = 4; // 0x4
+ }
+
+ @IntDef(flag=true, value={androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_MANIFEST, androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_DYNAMIC, androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_PINNED, androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_CACHED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ShortcutManagerCompat.ShortcutMatchFlags {
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class ShortcutXmlParser {
+ method @WorkerThread public static java.util.List<java.lang.String!> getShortcutIds(android.content.Context);
+ method @VisibleForTesting public static java.util.List<java.lang.String!> parseShortcutIds(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
+package androidx.core.content.res {
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class CamColor {
+ method public static void getM3HCTfromColor(@ColorInt int, @Size(3) float[]);
+ method public static int toColor(@FloatRange(from=0.0, to=360.0) float, @FloatRange(from=0.0, to=java.lang.Double.POSITIVE_INFINITY, toInclusive=false) float, @FloatRange(from=0.0, to=100.0) float);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class ColorStateListInflaterCompat {
+ method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static android.content.res.ColorStateList createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static android.content.res.ColorStateList? inflate(android.content.res.Resources, @XmlRes int, android.content.res.Resources.Theme?);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class ComplexColorCompat {
+ method @ColorInt public int getColor();
+ method public android.graphics.Shader? getShader();
+ method public static androidx.core.content.res.ComplexColorCompat? inflate(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?);
+ method public boolean isGradient();
+ method public boolean isStateful();
+ method public boolean onStateChanged(int[]!);
+ method public void setColor(@ColorInt int);
+ method public boolean willDraw();
+ }
+
+ public final class ConfigurationHelper {
+ method public static int getDensityDpi(android.content.res.Resources);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class FontResourcesParserCompat {
+ method public static androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry? parse(org.xmlpull.v1.XmlPullParser, android.content.res.Resources) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static java.util.List<java.util.List<byte[]!>!> readCerts(android.content.res.Resources, @ArrayRes int);
+ field public static final int FETCH_STRATEGY_ASYNC = 1; // 0x1
+ field public static final int FETCH_STRATEGY_BLOCKING = 0; // 0x0
+ field public static final int INFINITE_TIMEOUT_VALUE = -1; // 0xffffffff
+ }
+
+ public static interface FontResourcesParserCompat.FamilyResourceEntry {
+ }
+
+ @IntDef({androidx.core.content.res.FontResourcesParserCompat.FETCH_STRATEGY_BLOCKING, androidx.core.content.res.FontResourcesParserCompat.FETCH_STRATEGY_ASYNC}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface FontResourcesParserCompat.FetchStrategy {
+ }
+
+ public static final class FontResourcesParserCompat.FontFamilyFilesResourceEntry implements androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry {
+ ctor public FontResourcesParserCompat.FontFamilyFilesResourceEntry(androidx.core.content.res.FontResourcesParserCompat.FontFileResourceEntry![]);
+ method public androidx.core.content.res.FontResourcesParserCompat.FontFileResourceEntry![] getEntries();
+ }
+
+ public static final class FontResourcesParserCompat.FontFileResourceEntry {
+ ctor public FontResourcesParserCompat.FontFileResourceEntry(String, int, boolean, String?, int, int);
+ method public String getFileName();
+ method public int getResourceId();
+ method public int getTtcIndex();
+ method public String? getVariationSettings();
+ method public int getWeight();
+ method public boolean isItalic();
+ }
+
+ public static final class FontResourcesParserCompat.ProviderResourceEntry implements androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry {
+ ctor public FontResourcesParserCompat.ProviderResourceEntry(androidx.core.provider.FontRequest, @androidx.core.content.res.FontResourcesParserCompat.FetchStrategy int, int);
+ method @androidx.core.content.res.FontResourcesParserCompat.FetchStrategy public int getFetchStrategy();
+ method public androidx.core.provider.FontRequest getRequest();
+ method public int getTimeout();
+ }
+
+ public final class ResourcesCompat {
+ method public static void clearCachesForTheme(android.content.res.Resources.Theme);
+ method public static android.graphics.Typeface? getCachedFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+ method @ColorInt public static int getColor(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.content.res.ColorStateList? getColorStateList(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable? getDrawableForDensity(android.content.res.Resources, @DrawableRes int, int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static float getFloat(android.content.res.Resources, @DimenRes int);
+ method public static android.graphics.Typeface? getFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? getFont(android.content.Context, @FontRes int, android.util.TypedValue, int, androidx.core.content.res.ResourcesCompat.FontCallback?) throws android.content.res.Resources.NotFoundException;
+ method public static void getFont(android.content.Context, @FontRes int, androidx.core.content.res.ResourcesCompat.FontCallback, android.os.Handler?) throws android.content.res.Resources.NotFoundException;
+ field @AnyRes public static final int ID_NULL = 0; // 0x0
+ }
+
+ public abstract static class ResourcesCompat.FontCallback {
+ ctor public ResourcesCompat.FontCallback();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final void callbackFailAsync(@androidx.core.provider.FontsContractCompat.FontRequestCallback.FontRequestFailReason int, android.os.Handler?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final void callbackSuccessAsync(android.graphics.Typeface, android.os.Handler?);
+ method public abstract void onFontRetrievalFailed(@androidx.core.provider.FontsContractCompat.FontRequestCallback.FontRequestFailReason int);
+ method public abstract void onFontRetrieved(android.graphics.Typeface);
+ }
+
+ public static final class ResourcesCompat.ThemeCompat {
+ method public static void rebase(android.content.res.Resources.Theme);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypedArrayUtils {
+ method public static int getAttr(android.content.Context, int, int);
+ method public static boolean getBoolean(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int, boolean);
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+ method public static int getInt(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int, int);
+ method public static boolean getNamedBoolean(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, boolean);
+ method @ColorInt public static int getNamedColor(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, @ColorInt int);
+ method public static android.content.res.ColorStateList? getNamedColorStateList(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme?, String, @StyleableRes int);
+ method public static androidx.core.content.res.ComplexColorCompat! getNamedComplexColor(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme?, String, @StyleableRes int, @ColorInt int);
+ method public static float getNamedFloat(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, float);
+ method public static int getNamedInt(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, int);
+ method @AnyRes public static int getNamedResourceId(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, @AnyRes int);
+ method public static String? getNamedString(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int);
+ method @AnyRes public static int getResourceId(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int, @AnyRes int);
+ method public static String? getString(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+ method public static CharSequence? getText(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+ method public static CharSequence![]? getTextArray(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+ method public static boolean hasAttribute(org.xmlpull.v1.XmlPullParser, String);
+ method public static android.content.res.TypedArray obtainAttributes(android.content.res.Resources, android.content.res.Resources.Theme?, android.util.AttributeSet, int[]);
+ method public static android.util.TypedValue? peekNamedValue(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, int);
+ }
+
+}
+
+package androidx.core.database {
+
+ public final class CursorWindowCompat {
+ method public static android.database.CursorWindow create(String?, long);
+ }
+
+ @Deprecated public final class DatabaseUtilsCompat {
+ method @Deprecated public static String![]! appendSelectionArgs(String![]!, String![]!);
+ method @Deprecated public static String! concatenateWhere(String!, String!);
+ }
+
+}
+
+package androidx.core.database.sqlite {
+
+ public final class SQLiteCursorCompat {
+ method public static void setFillWindowForwardOnly(android.database.sqlite.SQLiteCursor, boolean);
+ }
+
+}
+
+package androidx.core.graphics {
+
+ public final class BitmapCompat {
+ method public static android.graphics.Bitmap createScaledBitmap(android.graphics.Bitmap, int, int, android.graphics.Rect?, boolean);
+ method public static int getAllocationByteCount(android.graphics.Bitmap);
+ method public static boolean hasMipMap(android.graphics.Bitmap);
+ method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+ }
+
+ public class BlendModeColorFilterCompat {
+ method public static android.graphics.ColorFilter? createBlendModeColorFilterCompat(int, androidx.core.graphics.BlendModeCompat);
+ }
+
+ public enum BlendModeCompat {
+ enum_constant public static final androidx.core.graphics.BlendModeCompat CLEAR;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_BURN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_DODGE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DARKEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat DIFFERENCE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_ATOP;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_IN;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OUT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OVER;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat EXCLUSION;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HARD_LIGHT;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HUE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat LIGHTEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat LUMINOSITY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat MODULATE;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat MULTIPLY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat OVERLAY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat PLUS;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SATURATION;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SCREEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SOFT_LIGHT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_ATOP;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_IN;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OUT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OVER;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat XOR;
+ }
+
+ public final class ColorUtils {
+ method @ColorInt public static int HSLToColor(float[]);
+ method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
+ method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
+ method @ColorInt public static int M3HCTToColor(@FloatRange(from=0.0, to=360, toInclusive=false) float, @FloatRange(from=0.0, to=java.lang.Double.POSITIVE_INFINITY, toInclusive=false) float, @FloatRange(from=0.0, to=100) float);
+ method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
+ method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+ method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+ method @ColorInt public static int XYZToColor(@FloatRange(from=0.0f, to=95.047) double, @FloatRange(from=0.0f, to=0x64) double, @FloatRange(from=0.0f, to=108.883) double);
+ method public static void XYZToLAB(@FloatRange(from=0.0f, to=95.047) double, @FloatRange(from=0.0f, to=0x64) double, @FloatRange(from=0.0f, to=108.883) double, double[]);
+ method @ColorInt public static int blendARGB(@ColorInt int, @ColorInt int, @FloatRange(from=0.0, to=1.0) float);
+ method public static void blendHSL(float[], float[], @FloatRange(from=0.0, to=1.0) float, float[]);
+ method public static void blendLAB(double[], double[], @FloatRange(from=0.0, to=1.0) double, double[]);
+ method public static double calculateContrast(@ColorInt int, @ColorInt int);
+ method @FloatRange(from=0.0, to=1.0) public static double calculateLuminance(@ColorInt int);
+ method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
+ method public static void colorToHSL(@ColorInt int, float[]);
+ method public static void colorToLAB(@ColorInt int, double[]);
+ method public static void colorToM3HCT(@ColorInt int, @Size(3) float[]);
+ method public static void colorToXYZ(@ColorInt int, double[]);
+ method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
+ method public static int compositeColors(@ColorInt int, @ColorInt int);
+ method public static double distanceEuclidean(double[], double[]);
+ method @ColorInt public static int setAlphaComponent(@ColorInt int, @IntRange(from=0, to=255) int);
+ }
+
+ public final class Insets {
+ method public static androidx.core.graphics.Insets add(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets max(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets min(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets of(android.graphics.Rect);
+ method public static androidx.core.graphics.Insets of(int, int, int, int);
+ method public static androidx.core.graphics.Insets subtract(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method @RequiresApi(api=29) public static androidx.core.graphics.Insets toCompatInsets(android.graphics.Insets);
+ method @RequiresApi(29) public android.graphics.Insets toPlatformInsets();
+ method @Deprecated @RequiresApi(api=29) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.Insets wrap(android.graphics.Insets);
+ field public static final androidx.core.graphics.Insets NONE;
+ field public final int bottom;
+ field public final int left;
+ field public final int right;
+ field public final int top;
+ }
+
+ public final class PaintCompat {
+ method public static boolean hasGlyph(android.graphics.Paint, String);
+ method public static boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat?);
+ }
+
+ public final class PathSegment {
+ ctor public PathSegment(android.graphics.PointF, float, android.graphics.PointF, float);
+ method public android.graphics.PointF getEnd();
+ method public float getEndFraction();
+ method public android.graphics.PointF getStart();
+ method public float getStartFraction();
+ }
+
+ public final class PathUtils {
+ method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path);
+ method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path, @FloatRange(from=0) float);
+ }
+
+ public class TypefaceCompat {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @VisibleForTesting public static void clearCache();
+ method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, int);
+ method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, @IntRange(from=1, to=1000) int, boolean);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? createFromFontInfo(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![], int);
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? createFromResourcesFamilyXml(android.content.Context, androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry, android.content.res.Resources, int, int, androidx.core.content.res.ResourcesCompat.FontCallback?, android.os.Handler?, boolean);
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? createFromResourcesFontFile(android.content.Context, android.content.res.Resources, int, String!, int);
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? findFromCache(android.content.res.Resources, int, int);
+ }
+
+ @RequiresApi(26) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypefaceCompatApi26Impl {
+ ctor public TypefaceCompatApi26Impl();
+ method protected android.graphics.Typeface? createFromFamiliesWithDefault(Object!);
+ method public android.graphics.Typeface? createFromFontFamilyFilesResourceEntry(android.content.Context!, androidx.core.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry!, android.content.res.Resources!, int);
+ method public android.graphics.Typeface? createFromFontInfo(android.content.Context!, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![], int);
+ method public android.graphics.Typeface? createFromResourcesFontFile(android.content.Context!, android.content.res.Resources!, int, String!, int);
+ method protected java.lang.reflect.Method! obtainAbortCreationMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+ method protected java.lang.reflect.Method! obtainAddFontFromAssetManagerMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+ method protected java.lang.reflect.Method! obtainAddFontFromBufferMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+ method protected java.lang.reflect.Method! obtainCreateFromFamiliesWithDefaultMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+ method protected Class<?>! obtainFontFamily() throws java.lang.ClassNotFoundException;
+ method protected java.lang.reflect.Constructor<?>! obtainFontFamilyCtor(Class<?>!) throws java.lang.NoSuchMethodException;
+ method protected java.lang.reflect.Method! obtainFreezeMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+ field protected final java.lang.reflect.Method! mAbortCreation;
+ field protected final java.lang.reflect.Method! mAddFontFromAssetManager;
+ field protected final java.lang.reflect.Method! mAddFontFromBuffer;
+ field protected final java.lang.reflect.Method! mCreateFromFamiliesWithDefault;
+ field protected final Class<?>! mFontFamily;
+ field protected final java.lang.reflect.Constructor<?>! mFontFamilyCtor;
+ field protected final java.lang.reflect.Method! mFreeze;
+ }
+
+ @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypefaceCompatApi28Impl extends androidx.core.graphics.TypefaceCompatApi26Impl {
+ ctor public TypefaceCompatApi28Impl();
+ }
+
+ @RequiresApi(29) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class TypefaceCompatApi29Impl {
+ ctor public TypefaceCompatApi29Impl();
+ method public android.graphics.Typeface? createFromFontFamilyFilesResourceEntry(android.content.Context!, androidx.core.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry!, android.content.res.Resources!, int);
+ method public android.graphics.Typeface? createFromFontInfo(android.content.Context!, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![], int);
+ method protected android.graphics.Typeface! createFromInputStream(android.content.Context!, java.io.InputStream!);
+ method public android.graphics.Typeface? createFromResourcesFontFile(android.content.Context!, android.content.res.Resources!, int, String!, int);
+ method protected androidx.core.provider.FontsContractCompat.FontInfo! findBestInfo(androidx.core.provider.FontsContractCompat.FontInfo![]!, int);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypefaceCompatUtil {
+ method public static void closeQuietly(java.io.Closeable?);
+ method @RequiresApi(19) public static java.nio.ByteBuffer? copyToDirectBuffer(android.content.Context, android.content.res.Resources, int);
+ method public static boolean copyToFile(java.io.File, android.content.res.Resources, int);
+ method public static boolean copyToFile(java.io.File, java.io.InputStream);
+ method public static java.io.File? getTempFile(android.content.Context);
+ method @RequiresApi(19) public static java.nio.ByteBuffer? mmap(android.content.Context, android.os.CancellationSignal?, android.net.Uri);
+ }
+
+}
+
+package androidx.core.graphics.drawable {
+
+ public final class DrawableCompat {
+ method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
+ method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
+ method public static void clearColorFilter(android.graphics.drawable.Drawable);
+ method public static int getAlpha(android.graphics.drawable.Drawable);
+ method public static android.graphics.ColorFilter? getColorFilter(android.graphics.drawable.Drawable);
+ method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+ method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+ method @Deprecated public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+ method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+ method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+ method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+ method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
+ method public static void setTint(android.graphics.drawable.Drawable, @ColorInt int);
+ method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList?);
+ method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode?);
+ method public static <T extends android.graphics.drawable.Drawable> T! unwrap(android.graphics.drawable.Drawable);
+ method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
+ }
+
+ @androidx.versionedparcelable.VersionedParcelize(allowSerialization=true, ignoreParcelables=true, isCustom=true, jetifyAs="android.support.v4.graphics.drawable.IconCompat") public class IconCompat extends androidx.versionedparcelable.CustomVersionedParcelable {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void addToShortcutIntent(android.content.Intent, android.graphics.drawable.Drawable?, android.content.Context);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void checkResource(android.content.Context);
+ method public static androidx.core.graphics.drawable.IconCompat? createFromBundle(android.os.Bundle);
+ method @RequiresApi(23) public static androidx.core.graphics.drawable.IconCompat? createFromIcon(android.content.Context, android.graphics.drawable.Icon);
+ method @RequiresApi(23) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.drawable.IconCompat? createFromIcon(android.graphics.drawable.Icon);
+ method @RequiresApi(23) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.drawable.IconCompat? createFromIconOrNullIfZeroResId(android.graphics.drawable.Icon);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmap(android.graphics.Bitmap);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(android.net.Uri);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(String);
+ method public static androidx.core.graphics.drawable.IconCompat createWithBitmap(android.graphics.Bitmap);
+ method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(android.net.Uri);
+ method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(String);
+ method public static androidx.core.graphics.drawable.IconCompat createWithData(byte[], int, int);
+ method public static androidx.core.graphics.drawable.IconCompat createWithResource(android.content.Context, @DrawableRes int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.drawable.IconCompat createWithResource(android.content.res.Resources?, String, @DrawableRes int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.graphics.Bitmap? getBitmap();
+ method @DrawableRes public int getResId();
+ method public String getResPackage();
+ method public int getType();
+ method public android.net.Uri getUri();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public java.io.InputStream? getUriInputStream(android.content.Context);
+ method public android.graphics.drawable.Drawable? loadDrawable(android.content.Context);
+ method public androidx.core.graphics.drawable.IconCompat setTint(@ColorInt int);
+ method public androidx.core.graphics.drawable.IconCompat setTintList(android.content.res.ColorStateList?);
+ method public androidx.core.graphics.drawable.IconCompat setTintMode(android.graphics.PorterDuff.Mode?);
+ method public android.os.Bundle toBundle();
+ method @Deprecated @RequiresApi(23) public android.graphics.drawable.Icon toIcon();
+ method @RequiresApi(23) public android.graphics.drawable.Icon toIcon(android.content.Context?);
+ field public static final int TYPE_ADAPTIVE_BITMAP = 5; // 0x5
+ field public static final int TYPE_BITMAP = 1; // 0x1
+ field public static final int TYPE_DATA = 3; // 0x3
+ field public static final int TYPE_RESOURCE = 2; // 0x2
+ field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+ field public static final int TYPE_URI = 4; // 0x4
+ field public static final int TYPE_URI_ADAPTIVE_BITMAP = 6; // 0x6
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @androidx.versionedparcelable.ParcelField(value=1, defaultValue="androidx.core.graphics.drawable.IconCompat.TYPE_UNKNOWN") public int mType;
+ }
+
+ public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+ method public void draw(android.graphics.Canvas);
+ method public final android.graphics.Bitmap? getBitmap();
+ method public float getCornerRadius();
+ method public int getGravity();
+ method public int getOpacity();
+ method public final android.graphics.Paint getPaint();
+ method public boolean hasAntiAlias();
+ method public boolean hasMipMap();
+ method public boolean isCircular();
+ method public void setAlpha(int);
+ method public void setAntiAlias(boolean);
+ method public void setCircular(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter!);
+ method public void setCornerRadius(float);
+ method public void setDither(boolean);
+ method public void setGravity(int);
+ method public void setMipMap(boolean);
+ method public void setTargetDensity(android.graphics.Canvas);
+ method public void setTargetDensity(android.util.DisplayMetrics);
+ method public void setTargetDensity(int);
+ }
+
+ public final class RoundedBitmapDrawableFactory {
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap?);
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, String);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface TintAwareDrawable {
+ method public void setTint(@ColorInt int);
+ method public void setTintList(android.content.res.ColorStateList!);
+ method public void setTintMode(android.graphics.PorterDuff.Mode!);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface WrappedDrawable {
+ method public android.graphics.drawable.Drawable! getWrappedDrawable();
+ method public void setWrappedDrawable(android.graphics.drawable.Drawable!);
+ }
+
+}
+
+package androidx.core.hardware.display {
+
+ public final class DisplayManagerCompat {
+ method public android.view.Display? getDisplay(int);
+ method public android.view.Display![] getDisplays();
+ method public android.view.Display![] getDisplays(String?);
+ method public static androidx.core.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+ field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+ }
+
+}
+
+package androidx.core.hardware.fingerprint {
+
+ @Deprecated public class FingerprintManagerCompat {
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public void authenticate(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject?, int, androidx.core.os.CancellationSignal?, androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler?);
+ method @Deprecated public static androidx.core.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+ }
+
+ @Deprecated public abstract static class FingerprintManagerCompat.AuthenticationCallback {
+ ctor @Deprecated public FingerprintManagerCompat.AuthenticationCallback();
+ method @Deprecated public void onAuthenticationError(int, CharSequence!);
+ method @Deprecated public void onAuthenticationFailed();
+ method @Deprecated public void onAuthenticationHelp(int, CharSequence!);
+ method @Deprecated public void onAuthenticationSucceeded(androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult!);
+ }
+
+ @Deprecated public static final class FingerprintManagerCompat.AuthenticationResult {
+ ctor @Deprecated public FingerprintManagerCompat.AuthenticationResult(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject!);
+ method @Deprecated public androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject! getCryptoObject();
+ }
+
+ @Deprecated public static class FingerprintManagerCompat.CryptoObject {
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+ method @Deprecated public javax.crypto.Cipher? getCipher();
+ method @Deprecated public javax.crypto.Mac? getMac();
+ method @Deprecated public java.security.Signature? getSignature();
+ }
+
+}
+
+package androidx.core.internal.view {
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SupportMenu extends android.view.Menu {
+ method public void setGroupDividerEnabled(boolean);
+ field public static final int CATEGORY_MASK = -65536; // 0xffff0000
+ field public static final int CATEGORY_SHIFT = 16; // 0x10
+ field public static final int FLAG_KEEP_OPEN_ON_SUBMENU_OPENED = 4; // 0x4
+ field public static final int SUPPORTED_MODIFIERS_MASK = 69647; // 0x1100f
+ field public static final int USER_MASK = 65535; // 0xffff
+ field public static final int USER_SHIFT = 0; // 0x0
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SupportMenuItem extends android.view.MenuItem {
+ method public int getAlphabeticModifiers();
+ method public CharSequence? getContentDescription();
+ method public android.content.res.ColorStateList? getIconTintList();
+ method public android.graphics.PorterDuff.Mode? getIconTintMode();
+ method public int getNumericModifiers();
+ method public androidx.core.view.ActionProvider? getSupportActionProvider();
+ method public CharSequence? getTooltipText();
+ method public boolean requiresActionButton();
+ method public boolean requiresOverflow();
+ method public android.view.MenuItem setAlphabeticShortcut(char, int);
+ method public androidx.core.internal.view.SupportMenuItem setContentDescription(CharSequence?);
+ method public android.view.MenuItem setIconTintList(android.content.res.ColorStateList?);
+ method public android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode?);
+ method public android.view.MenuItem setNumericShortcut(char, int);
+ method public android.view.MenuItem setShortcut(char, char, int, int);
+ method public androidx.core.internal.view.SupportMenuItem setSupportActionProvider(androidx.core.view.ActionProvider?);
+ method public androidx.core.internal.view.SupportMenuItem setTooltipText(CharSequence?);
+ field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+ field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+ field public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+ field public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+ field public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SupportSubMenu extends androidx.core.internal.view.SupportMenu android.view.SubMenu {
+ }
+
+}
+
+package androidx.core.location {
+
+ public abstract class GnssStatusCompat {
+ method @FloatRange(from=0, to=360) public abstract float getAzimuthDegrees(@IntRange(from=0) int);
+ method @FloatRange(from=0, to=63) public abstract float getBasebandCn0DbHz(@IntRange(from=0) int);
+ method @FloatRange(from=0) public abstract float getCarrierFrequencyHz(@IntRange(from=0) int);
+ method @FloatRange(from=0, to=63) public abstract float getCn0DbHz(@IntRange(from=0) int);
+ method public abstract int getConstellationType(@IntRange(from=0) int);
+ method @FloatRange(from=0xffffffa6, to=90) public abstract float getElevationDegrees(@IntRange(from=0) int);
+ method @IntRange(from=0) public abstract int getSatelliteCount();
+ method @IntRange(from=1, to=200) public abstract int getSvid(@IntRange(from=0) int);
+ method public abstract boolean hasAlmanacData(@IntRange(from=0) int);
+ method public abstract boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
+ method public abstract boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
+ method public abstract boolean hasEphemerisData(@IntRange(from=0) int);
+ method public abstract boolean usedInFix(@IntRange(from=0) int);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) public static androidx.core.location.GnssStatusCompat wrap(android.location.GnssStatus);
+ method public static androidx.core.location.GnssStatusCompat wrap(android.location.GpsStatus);
+ field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_IRNSS = 7; // 0x7
+ field public static final int CONSTELLATION_QZSS = 4; // 0x4
+ field public static final int CONSTELLATION_SBAS = 2; // 0x2
+ field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public abstract static class GnssStatusCompat.Callback {
+ ctor public GnssStatusCompat.Callback();
+ method public void onFirstFix(@IntRange(from=0) int);
+ method public void onSatelliteStatusChanged(androidx.core.location.GnssStatusCompat);
+ method public void onStarted();
+ method public void onStopped();
+ }
+
+ public final class LocationCompat {
+ method public static float getBearingAccuracyDegrees(android.location.Location);
+ method public static long getElapsedRealtimeMillis(android.location.Location);
+ method public static long getElapsedRealtimeNanos(android.location.Location);
+ method @FloatRange(from=0.0) public static float getMslAltitudeAccuracyMeters(android.location.Location);
+ method public static double getMslAltitudeMeters(android.location.Location);
+ method public static float getSpeedAccuracyMetersPerSecond(android.location.Location);
+ method public static float getVerticalAccuracyMeters(android.location.Location);
+ method public static boolean hasBearingAccuracy(android.location.Location);
+ method public static boolean hasMslAltitude(android.location.Location);
+ method public static boolean hasMslAltitudeAccuracy(android.location.Location);
+ method public static boolean hasSpeedAccuracy(android.location.Location);
+ method public static boolean hasVerticalAccuracy(android.location.Location);
+ method public static boolean isMock(android.location.Location);
+ method public static void removeMslAltitude(android.location.Location);
+ method public static void removeMslAltitudeAccuracy(android.location.Location);
+ method public static void setBearingAccuracyDegrees(android.location.Location, float);
+ method public static void setMock(android.location.Location, boolean);
+ method public static void setMslAltitudeAccuracyMeters(android.location.Location, @FloatRange(from=0.0) float);
+ method public static void setMslAltitudeMeters(android.location.Location, double);
+ method public static void setSpeedAccuracyMetersPerSecond(android.location.Location, float);
+ method public static void setVerticalAccuracyMeters(android.location.Location, float);
+ field public static final String EXTRA_BEARING_ACCURACY = "bearingAccuracy";
+ field public static final String EXTRA_IS_MOCK = "mockLocation";
+ field public static final String EXTRA_MSL_ALTITUDE = "androidx.core.location.extra.MSL_ALTITUDE";
+ field public static final String EXTRA_MSL_ALTITUDE_ACCURACY = "androidx.core.location.extra.MSL_ALTITUDE_ACCURACY";
+ field public static final String EXTRA_SPEED_ACCURACY = "speedAccuracy";
+ field public static final String EXTRA_VERTICAL_ACCURACY = "verticalAccuracy";
+ }
+
+ public interface LocationListenerCompat extends android.location.LocationListener {
+ method public default void onStatusChanged(String, int, android.os.Bundle?);
+ }
+
+ public final class LocationManagerCompat {
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void getCurrentLocation(android.location.LocationManager, String, androidx.core.os.CancellationSignal?, java.util.concurrent.Executor, androidx.core.util.Consumer<android.location.Location!>);
+ method public static String? getGnssHardwareModelName(android.location.LocationManager);
+ method public static int getGnssYearOfHardware(android.location.LocationManager);
+ method public static boolean hasProvider(android.location.LocationManager, String);
+ method public static boolean isLocationEnabled(android.location.LocationManager);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssMeasurementsCallback(android.location.LocationManager, android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssMeasurementsCallback(android.location.LocationManager, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback, android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, java.util.concurrent.Executor, androidx.core.location.GnssStatusCompat.Callback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void removeUpdates(android.location.LocationManager, androidx.core.location.LocationListenerCompat);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, androidx.core.location.LocationListenerCompat, android.os.Looper);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, java.util.concurrent.Executor, androidx.core.location.LocationListenerCompat);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) public static void unregisterGnssMeasurementsCallback(android.location.LocationManager, android.location.GnssMeasurementsEvent.Callback);
+ method public static void unregisterGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback);
+ }
+
+ public final class LocationRequestCompat {
+ method @IntRange(from=1) public long getDurationMillis();
+ method @IntRange(from=0) public long getIntervalMillis();
+ method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+ method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
+ method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
+ method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
+ method @RequiresApi(31) public android.location.LocationRequest toLocationRequest();
+ method @RequiresApi(19) public android.location.LocationRequest? toLocationRequest(String);
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
+ }
+
+ public static final class LocationRequestCompat.Builder {
+ ctor public LocationRequestCompat.Builder(androidx.core.location.LocationRequestCompat);
+ ctor public LocationRequestCompat.Builder(long);
+ method public androidx.core.location.LocationRequestCompat build();
+ method public androidx.core.location.LocationRequestCompat.Builder clearMinUpdateIntervalMillis();
+ method public androidx.core.location.LocationRequestCompat.Builder setDurationMillis(@IntRange(from=1) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setIntervalMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+ method public androidx.core.location.LocationRequestCompat.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
+ method public androidx.core.location.LocationRequestCompat.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ method public androidx.core.location.LocationRequestCompat.Builder setQuality(int);
+ }
+
+}
+
+package androidx.core.math {
+
+ public class MathUtils {
+ method public static int addExact(int, int);
+ method public static long addExact(long, long);
+ method public static double clamp(double, double, double);
+ method public static float clamp(float, float, float);
+ method public static int clamp(int, int, int);
+ method public static long clamp(long, long, long);
+ method public static int decrementExact(int);
+ method public static long decrementExact(long);
+ method public static int incrementExact(int);
+ method public static long incrementExact(long);
+ method public static int multiplyExact(int, int);
+ method public static long multiplyExact(long, long);
+ method public static int negateExact(int);
+ method public static long negateExact(long);
+ method public static int subtractExact(int, int);
+ method public static long subtractExact(long, long);
+ method public static int toIntExact(long);
+ }
+
+}
+
+package androidx.core.net {
+
+ public final class ConnectivityManagerCompat {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static android.net.NetworkInfo? getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+ method @androidx.core.net.ConnectivityManagerCompat.RestrictBackgroundStatus public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+ field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+ field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+ field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+ }
+
+ @IntDef({androidx.core.net.ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_DISABLED, androidx.core.net.ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_WHITELISTED, androidx.core.net.ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_ENABLED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ConnectivityManagerCompat.RestrictBackgroundStatus {
+ }
+
+ public final class MailTo {
+ method public String? getBcc();
+ method public String? getBody();
+ method public String? getCc();
+ method public java.util.Map<java.lang.String!,java.lang.String!>? getHeaders();
+ method public String? getSubject();
+ method public String? getTo();
+ method public static boolean isMailTo(android.net.Uri?);
+ method public static boolean isMailTo(String?);
+ method public static androidx.core.net.MailTo parse(android.net.Uri) throws androidx.core.net.ParseException;
+ method public static androidx.core.net.MailTo parse(String) throws androidx.core.net.ParseException;
+ field public static final String MAILTO_SCHEME = "mailto:";
+ }
+
+ public class ParseException extends java.lang.RuntimeException {
+ field public final String response;
+ }
+
+ public final class TrafficStatsCompat {
+ method @Deprecated public static void clearThreadStatsTag();
+ method @Deprecated public static int getThreadStatsTag();
+ method @Deprecated public static void incrementOperationCount(int);
+ method @Deprecated public static void incrementOperationCount(int, int);
+ method @Deprecated public static void setThreadStatsTag(int);
+ method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method @Deprecated public static void tagSocket(java.net.Socket!) throws java.net.SocketException;
+ method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method @Deprecated public static void untagSocket(java.net.Socket!) throws java.net.SocketException;
+ }
+
+ public final class UriCompat {
+ method public static String toSafeString(android.net.Uri);
+ }
+
+}
+
+package androidx.core.os {
+
+ public class BuildCompat {
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O_MR1) public static boolean isAtLeastOMR1();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.P) public static boolean isAtLeastP();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.Q) public static boolean isAtLeastQ();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.R) public static boolean isAtLeastR();
+ method @Deprecated @ChecksSdkIntAtLeast(api=31, codename="S") public static boolean isAtLeastS();
+ method @Deprecated @ChecksSdkIntAtLeast(api=32, codename="Sv2") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastSv2();
+ method @Deprecated @ChecksSdkIntAtLeast(api=33, codename="Tiramisu") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastT();
+ method @ChecksSdkIntAtLeast(api=34, codename="UpsideDownCake") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastU();
+ method @ChecksSdkIntAtLeast(codename="VanillaIceCream") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastV();
+ field @ChecksSdkIntAtLeast(extension=android.os.ext.SdkExtensions.AD_SERVICES) public static final int AD_SERVICES_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.R) public static final int R_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.S) public static final int S_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.TIRAMISU) public static final int T_EXTENSION_INT;
+ }
+
+ @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface BuildCompat.PrereleaseSdkCheck {
+ }
+
+ public final class BundleCompat {
+ method public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+ method public static <T> T? getParcelable(android.os.Bundle, String?, Class<T!>);
+ method public static android.os.Parcelable![]? getParcelableArray(android.os.Bundle, String?, Class<? extends android.os.Parcelable>);
+ method public static <T> java.util.ArrayList<T!>? getParcelableArrayList(android.os.Bundle, String?, Class<? extends T>);
+ method public static <T> android.util.SparseArray<T!>? getSparseParcelableArray(android.os.Bundle, String?, Class<? extends T>);
+ method public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+ }
+
+ public final class CancellationSignal {
+ ctor public CancellationSignal();
+ method public void cancel();
+ method public Object? getCancellationSignalObject();
+ method public boolean isCanceled();
+ method public void setOnCancelListener(androidx.core.os.CancellationSignal.OnCancelListener?);
+ method public void throwIfCanceled();
+ }
+
+ public static interface CancellationSignal.OnCancelListener {
+ method public void onCancel();
+ }
+
+ public final class ConfigurationCompat {
+ method public static androidx.core.os.LocaleListCompat getLocales(android.content.res.Configuration);
+ method public static void setLocales(android.content.res.Configuration, androidx.core.os.LocaleListCompat);
+ }
+
+ public final class EnvironmentCompat {
+ method public static String getStorageState(java.io.File);
+ field public static final String MEDIA_UNKNOWN = "unknown";
+ }
+
+ public final class ExecutorCompat {
+ method public static java.util.concurrent.Executor create(android.os.Handler);
+ }
+
+ public final class HandlerCompat {
+ method public static android.os.Handler createAsync(android.os.Looper);
+ method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
+ method @RequiresApi(16) public static boolean hasCallbacks(android.os.Handler, Runnable);
+ method public static boolean postDelayed(android.os.Handler, Runnable, Object?, long);
+ }
+
+ public final class LocaleListCompat {
+ method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...);
+ method public static androidx.core.os.LocaleListCompat forLanguageTags(String?);
+ method public java.util.Locale? get(int);
+ method @Size(min=1) public static androidx.core.os.LocaleListCompat getAdjustedDefault();
+ method @Size(min=1) public static androidx.core.os.LocaleListCompat getDefault();
+ method public static androidx.core.os.LocaleListCompat getEmptyLocaleList();
+ method public java.util.Locale? getFirstMatch(String![]);
+ method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale?);
+ method public boolean isEmpty();
+ method @RequiresApi(21) public static boolean matchesLanguageAndScript(java.util.Locale, java.util.Locale);
+ method @IntRange(from=0) public int size();
+ method public String toLanguageTags();
+ method public Object? unwrap();
+ method @RequiresApi(24) public static androidx.core.os.LocaleListCompat wrap(android.os.LocaleList);
+ method @Deprecated @RequiresApi(24) public static androidx.core.os.LocaleListCompat! wrap(Object!);
+ }
+
+ public final class MessageCompat {
+ method public static boolean isAsynchronous(android.os.Message);
+ method public static void setAsynchronous(android.os.Message, boolean);
+ }
+
+ public class OperationCanceledException extends java.lang.RuntimeException {
+ ctor public OperationCanceledException();
+ ctor public OperationCanceledException(String?);
+ }
+
+ public final class ParcelCompat {
+ method public static <T> Object![]? readArray(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> java.util.ArrayList<T!>? readArrayList(android.os.Parcel, ClassLoader?, Class<? extends T>);
+ method public static boolean readBoolean(android.os.Parcel);
+ method public static <K, V> java.util.HashMap<K!,V!>? readHashMap(android.os.Parcel, ClassLoader?, Class<? extends K>, Class<? extends V>);
+ method public static <T> void readList(android.os.Parcel, java.util.List<? super T>, ClassLoader?, Class<T!>);
+ method public static <K, V> void readMap(android.os.Parcel, java.util.Map<? super K,? super V>, ClassLoader?, Class<K!>, Class<V!>);
+ method public static <T extends android.os.Parcelable> T? readParcelable(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @Deprecated public static <T> T![]? readParcelableArray(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> android.os.Parcelable![]? readParcelableArrayTyped(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @RequiresApi(30) public static <T> android.os.Parcelable.Creator<T!>? readParcelableCreator(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @RequiresApi(api=android.os.Build.VERSION_CODES.Q) public static <T> java.util.List<T!> readParcelableList(android.os.Parcel, java.util.List<T!>, ClassLoader?, Class<T!>);
+ method public static <T extends java.io.Serializable> T? readSerializable(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> android.util.SparseArray<T!>? readSparseArray(android.os.Parcel, ClassLoader?, Class<? extends T>);
+ method public static void writeBoolean(android.os.Parcel, boolean);
+ }
+
+ @Deprecated public final class ParcelableCompat {
+ method @Deprecated public static <T> android.os.Parcelable.Creator<T!>! newCreator(androidx.core.os.ParcelableCompatCreatorCallbacks<T!>!);
+ }
+
+ @Deprecated public interface ParcelableCompatCreatorCallbacks<T> {
+ method @Deprecated public T! createFromParcel(android.os.Parcel!, ClassLoader!);
+ method @Deprecated public T![]! newArray(int);
+ }
+
+ public final class ProcessCompat {
+ method public static boolean isApplicationUid(int);
+ }
+
+ @Deprecated public final class TraceCompat {
+ method @Deprecated public static void beginAsyncSection(String, int);
+ method @Deprecated public static void beginSection(String);
+ method @Deprecated public static void endAsyncSection(String, int);
+ method @Deprecated public static void endSection();
+ method @Deprecated public static boolean isEnabled();
+ method @Deprecated public static void setCounter(String, int);
+ }
+
+ @RequiresApi(17) public class UserHandleCompat {
+ method public static android.os.UserHandle getUserHandleForUid(int);
+ }
+
+ public class UserManagerCompat {
+ method public static boolean isUserUnlocked(android.content.Context);
+ }
+
+}
+
+package androidx.core.provider {
+
+ public final class DocumentsContractCompat {
+ method public static android.net.Uri? buildChildDocumentsUri(String, String?);
+ method public static android.net.Uri? buildChildDocumentsUriUsingTree(android.net.Uri, String);
+ method public static android.net.Uri? buildDocumentUri(String, String);
+ method public static android.net.Uri? buildDocumentUriUsingTree(android.net.Uri, String);
+ method public static android.net.Uri? buildTreeDocumentUri(String, String);
+ method public static android.net.Uri? createDocument(android.content.ContentResolver, android.net.Uri, String, String) throws java.io.FileNotFoundException;
+ method public static String? getDocumentId(android.net.Uri);
+ method public static String? getTreeDocumentId(android.net.Uri);
+ method public static boolean isDocumentUri(android.content.Context, android.net.Uri?);
+ method public static boolean isTreeUri(android.net.Uri);
+ method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.net.Uri? renameDocument(android.content.ContentResolver, android.net.Uri, String) throws java.io.FileNotFoundException;
+ }
+
+ public static final class DocumentsContractCompat.DocumentCompat {
+ field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
+ }
+
+ public final class FontRequest {
+ ctor public FontRequest(String, String, String, @ArrayRes int);
+ ctor public FontRequest(String, String, String, java.util.List<java.util.List<byte[]!>!>);
+ method public java.util.List<java.util.List<byte[]!>!>? getCertificates();
+ method @ArrayRes public int getCertificatesArrayResId();
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public String! getIdentifier();
+ method public String getProviderAuthority();
+ method public String getProviderPackage();
+ method public String getQuery();
+ }
+
+ public class FontsContractCompat {
+ method public static android.graphics.Typeface? buildTypeface(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![]);
+ method public static androidx.core.provider.FontsContractCompat.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface! getFontSync(android.content.Context!, androidx.core.provider.FontRequest!, androidx.core.content.res.ResourcesCompat.FontCallback?, android.os.Handler?, boolean, int, int);
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @VisibleForTesting public static android.content.pm.ProviderInfo? getProvider(android.content.pm.PackageManager, androidx.core.provider.FontRequest, android.content.res.Resources?) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Deprecated @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static java.util.Map<android.net.Uri!,java.nio.ByteBuffer!>! prepareFontData(android.content.Context!, androidx.core.provider.FontsContractCompat.FontInfo![]!, android.os.CancellationSignal!);
+ method public static void requestFont(android.content.Context, androidx.core.provider.FontRequest, androidx.core.provider.FontsContractCompat.FontRequestCallback, android.os.Handler);
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void resetCache();
+ field @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final String PARCEL_FONT_RESULTS = "font_results";
+ }
+
+ public static final class FontsContractCompat.Columns implements android.provider.BaseColumns {
+ ctor public FontsContractCompat.Columns();
+ field public static final String FILE_ID = "file_id";
+ field public static final String ITALIC = "font_italic";
+ field public static final String RESULT_CODE = "result_code";
+ field public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
+ field public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
+ field public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
+ field public static final int RESULT_CODE_OK = 0; // 0x0
+ field public static final String TTC_INDEX = "font_ttc_index";
+ field public static final String VARIATION_SETTINGS = "font_variation_settings";
+ field public static final String WEIGHT = "font_weight";
+ }
+
+ public static class FontsContractCompat.FontFamilyResult {
+ ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public FontsContractCompat.FontFamilyResult(int, androidx.core.provider.FontsContractCompat.FontInfo![]?);
+ method public androidx.core.provider.FontsContractCompat.FontInfo![]! getFonts();
+ method public int getStatusCode();
+ field public static final int STATUS_OK = 0; // 0x0
+ field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
+ field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
+ }
+
+ public static class FontsContractCompat.FontInfo {
+ ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public FontsContractCompat.FontInfo(android.net.Uri, @IntRange(from=0) int, @IntRange(from=1, to=1000) int, boolean, int);
+ method public int getResultCode();
+ method @IntRange(from=0) public int getTtcIndex();
+ method public android.net.Uri getUri();
+ method @IntRange(from=1, to=1000) public int getWeight();
+ method public boolean isItalic();
+ }
+
+ public static class FontsContractCompat.FontRequestCallback {
+ ctor public FontsContractCompat.FontRequestCallback();
+ method public void onTypefaceRequestFailed(@androidx.core.provider.FontsContractCompat.FontRequestCallback.FontRequestFailReason int);
+ method public void onTypefaceRetrieved(android.graphics.Typeface!);
+ field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
+ field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
+ field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
+ field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
+ field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
+ field public static final int FAIL_REASON_SECURITY_VIOLATION = -4; // 0xfffffffc
+ field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
+ field @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int RESULT_OK = 0; // 0x0
+ }
+
+ @IntDef({androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_UNAVAILABLE, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_MALFORMED_QUERY, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_WRONG_CERTIFICATES, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_SECURITY_VIOLATION, androidx.core.provider.FontsContractCompat.FontRequestCallback.RESULT_OK}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface FontsContractCompat.FontRequestCallback.FontRequestFailReason {
+ }
+
+ @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class SelfDestructiveThread {
+ ctor @Deprecated public SelfDestructiveThread(String!, int, int);
+ method @Deprecated @VisibleForTesting public int getGeneration();
+ method @Deprecated @VisibleForTesting public boolean isRunning();
+ method @Deprecated public <T> void postAndReply(java.util.concurrent.Callable<T!>!, androidx.core.provider.SelfDestructiveThread.ReplyCallback<T!>!);
+ method @Deprecated public <T> T! postAndWait(java.util.concurrent.Callable<T!>!, int) throws java.lang.InterruptedException;
+ }
+
+ @Deprecated public static interface SelfDestructiveThread.ReplyCallback<T> {
+ method @Deprecated public void onReply(T!);
+ }
+
+}
+
+package androidx.core.telephony {
+
+ @RequiresApi(22) public class SubscriptionManagerCompat {
+ method public static int getSlotIndex(int);
+ }
+
+ public class TelephonyManagerCompat {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static String? getImei(android.telephony.TelephonyManager);
+ method public static int getSubscriptionId(android.telephony.TelephonyManager);
+ }
+
+}
+
+package androidx.core.telephony.mbms {
+
+ public final class MbmsHelper {
+ method public static CharSequence? getBestNameForService(android.content.Context, android.telephony.mbms.ServiceInfo);
+ }
+
+}
+
+package androidx.core.text {
+
+ public final class BidiFormatter {
+ method public static androidx.core.text.BidiFormatter! getInstance();
+ method public static androidx.core.text.BidiFormatter! getInstance(boolean);
+ method public static androidx.core.text.BidiFormatter! getInstance(java.util.Locale!);
+ method public boolean getStereoReset();
+ method public boolean isRtl(CharSequence!);
+ method public boolean isRtl(String!);
+ method public boolean isRtlContext();
+ method public CharSequence! unicodeWrap(CharSequence!);
+ method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!);
+ method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+ method public CharSequence! unicodeWrap(CharSequence!, boolean);
+ method public String! unicodeWrap(String!);
+ method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!);
+ method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+ method public String! unicodeWrap(String!, boolean);
+ }
+
+ public static final class BidiFormatter.Builder {
+ ctor public BidiFormatter.Builder();
+ ctor public BidiFormatter.Builder(boolean);
+ ctor public BidiFormatter.Builder(java.util.Locale!);
+ method public androidx.core.text.BidiFormatter! build();
+ method public androidx.core.text.BidiFormatter.Builder! setTextDirectionHeuristic(androidx.core.text.TextDirectionHeuristicCompat!);
+ method public androidx.core.text.BidiFormatter.Builder! stereoReset(boolean);
+ }
+
+ public final class HtmlCompat {
+ method public static android.text.Spanned fromHtml(String, int);
+ method public static android.text.Spanned fromHtml(String, int, android.text.Html.ImageGetter?, android.text.Html.TagHandler?);
+ method public static String toHtml(android.text.Spanned, int);
+ field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
+ field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
+ field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32; // 0x20
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16; // 0x10
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2; // 0x2
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8; // 0x8
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4; // 0x4
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1; // 0x1
+ field public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0; // 0x0
+ field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
+ }
+
+ public final class ICUCompat {
+ method public static String? maximizeAndGetScript(java.util.Locale);
+ }
+
+ public class PrecomputedTextCompat implements android.text.Spannable {
+ method public char charAt(int);
+ method public static androidx.core.text.PrecomputedTextCompat! create(CharSequence, androidx.core.text.PrecomputedTextCompat.Params);
+ method @IntRange(from=0) public int getParagraphCount();
+ method @IntRange(from=0) public int getParagraphEnd(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getParagraphStart(@IntRange(from=0) int);
+ method public androidx.core.text.PrecomputedTextCompat.Params getParams();
+ method @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.text.PrecomputedText? getPrecomputedText();
+ method public int getSpanEnd(Object!);
+ method public int getSpanFlags(Object!);
+ method public int getSpanStart(Object!);
+ method public <T> T![]! getSpans(int, int, Class<T!>!);
+ method @UiThread public static java.util.concurrent.Future<androidx.core.text.PrecomputedTextCompat!>! getTextFuture(CharSequence, androidx.core.text.PrecomputedTextCompat.Params, java.util.concurrent.Executor?);
+ method public int length();
+ method public int nextSpanTransition(int, int, Class!);
+ method public void removeSpan(Object!);
+ method public void setSpan(Object!, int, int, int);
+ method public CharSequence! subSequence(int, int);
+ }
+
+ public static final class PrecomputedTextCompat.Params {
+ ctor @RequiresApi(28) public PrecomputedTextCompat.Params(android.text.PrecomputedText.Params);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean equalsWithoutTextDirection(androidx.core.text.PrecomputedTextCompat.Params);
+ method @RequiresApi(23) public int getBreakStrategy();
+ method @RequiresApi(23) public int getHyphenationFrequency();
+ method @RequiresApi(18) public android.text.TextDirectionHeuristic? getTextDirection();
+ method public android.text.TextPaint getTextPaint();
+ }
+
+ public static class PrecomputedTextCompat.Params.Builder {
+ ctor public PrecomputedTextCompat.Params.Builder(android.text.TextPaint);
+ method public androidx.core.text.PrecomputedTextCompat.Params build();
+ method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setBreakStrategy(int);
+ method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setHyphenationFrequency(int);
+ method @RequiresApi(18) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setTextDirection(android.text.TextDirectionHeuristic);
+ }
+
+ public interface TextDirectionHeuristicCompat {
+ method public boolean isRtl(char[]!, int, int);
+ method public boolean isRtl(CharSequence!, int, int);
+ }
+
+ public final class TextDirectionHeuristicsCompat {
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! ANYRTL_LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_RTL;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! LOCALE;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! RTL;
+ }
+
+ public final class TextUtilsCompat {
+ method public static int getLayoutDirectionFromLocale(java.util.Locale?);
+ method public static String htmlEncode(String);
+ }
+
+}
+
+package androidx.core.text.method {
+
+ public class LinkMovementMethodCompat extends android.text.method.LinkMovementMethod {
+ method public static androidx.core.text.method.LinkMovementMethodCompat getInstance();
+ }
+
+}
+
+package androidx.core.text.util {
+
+ public final class LinkifyCompat {
+ method public static boolean addLinks(android.text.Spannable, @androidx.core.text.util.LinkifyCompat.LinkifyMask int);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static boolean addLinks(android.widget.TextView, @androidx.core.text.util.LinkifyCompat.LinkifyMask int);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ }
+
+ @IntDef(flag=true, value={android.text.util.Linkify.WEB_URLS, android.text.util.Linkify.EMAIL_ADDRESSES, android.text.util.Linkify.PHONE_NUMBERS, android.text.util.Linkify.MAP_ADDRESSES, android.text.util.Linkify.ALL}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface LinkifyCompat.LinkifyMask {
+ }
+
+}
+
+package androidx.core.util {
+
+ public class AtomicFile {
+ ctor public AtomicFile(java.io.File);
+ method public void delete();
+ method public void failWrite(java.io.FileOutputStream?);
+ method public void finishWrite(java.io.FileOutputStream?);
+ method public java.io.File getBaseFile();
+ method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+ method public byte[] readFully() throws java.io.IOException;
+ method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+ }
+
+ public interface Consumer<T> {
+ method public void accept(T!);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class DebugUtils {
+ method public static void buildShortClassTag(Object!, StringBuilder!);
+ }
+
+ @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class LogWriter extends java.io.Writer {
+ ctor @Deprecated public LogWriter(String!);
+ method @Deprecated public void close();
+ method @Deprecated public void flush();
+ method @Deprecated public void write(char[]!, int, int);
+ }
+
+ public class ObjectsCompat {
+ method public static boolean equals(Object?, Object?);
+ method public static int hash(java.lang.Object!...);
+ method public static int hashCode(Object?);
+ method public static <T> T requireNonNull(T?);
+ method public static <T> T requireNonNull(T?, String);
+ method public static String? toString(Object?, String?);
+ }
+
+ public class Pair<F, S> {
+ ctor public Pair(F!, S!);
+ method public static <A, B> androidx.core.util.Pair<A!,B!> create(A!, B!);
+ field public final F! first;
+ field public final S! second;
+ }
+
+ public final class PatternsCompat {
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final java.util.regex.Pattern AUTOLINK_EMAIL_ADDRESS;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final java.util.regex.Pattern AUTOLINK_WEB_URL;
+ field public static final java.util.regex.Pattern DOMAIN_NAME;
+ field public static final java.util.regex.Pattern EMAIL_ADDRESS;
+ field public static final java.util.regex.Pattern IP_ADDRESS;
+ field public static final java.util.regex.Pattern WEB_URL;
+ }
+
+ public final class Pools {
+ }
+
+ public static interface Pools.Pool<T> {
+ method public T? acquire();
+ method public boolean release(T);
+ }
+
+ public static class Pools.SimplePool<T> implements androidx.core.util.Pools.Pool<T> {
+ ctor public Pools.SimplePool(int);
+ method public T! acquire();
+ method public boolean release(T);
+ }
+
+ public static class Pools.SynchronizedPool<T> extends androidx.core.util.Pools.SimplePool<T> {
+ ctor public Pools.SynchronizedPool(int);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class Preconditions {
+ method public static void checkArgument(boolean);
+ method public static void checkArgument(boolean, Object);
+ method public static void checkArgument(boolean, String, java.lang.Object!...);
+ method public static float checkArgumentFinite(float, String);
+ method public static double checkArgumentInRange(double, double, double, String);
+ method public static float checkArgumentInRange(float, float, float, String);
+ method public static int checkArgumentInRange(int, int, int, String);
+ method public static long checkArgumentInRange(long, long, long, String);
+ method @IntRange(from=0) public static int checkArgumentNonnegative(int);
+ method @IntRange(from=0) public static int checkArgumentNonnegative(int, String?);
+ method public static int checkFlagsArgument(int, int);
+ method public static <T> T checkNotNull(T?);
+ method public static <T> T checkNotNull(T?, Object);
+ method public static void checkState(boolean);
+ method public static void checkState(boolean, String?);
+ method public static <T extends java.lang.CharSequence> T checkStringNotEmpty(T?);
+ method public static <T extends java.lang.CharSequence> T checkStringNotEmpty(T?, Object);
+ method public static <T extends java.lang.CharSequence> T checkStringNotEmpty(T?, String, java.lang.Object!...);
+ }
+
+ public interface Predicate<T> {
+ method public default androidx.core.util.Predicate<T!>! and(androidx.core.util.Predicate<? super T>!);
+ method public static <T> androidx.core.util.Predicate<T!>! isEqual(Object!);
+ method public default androidx.core.util.Predicate<T!>! negate();
+ method public static <T> androidx.core.util.Predicate<T!>! not(androidx.core.util.Predicate<? super T>!);
+ method public default androidx.core.util.Predicate<T!>! or(androidx.core.util.Predicate<? super T>!);
+ method public boolean test(T!);
+ }
+
+ public final class SizeFCompat {
+ ctor public SizeFCompat(float, float);
+ method public float getHeight();
+ method public float getWidth();
+ method @RequiresApi(21) public android.util.SizeF toSizeF();
+ method @RequiresApi(21) public static androidx.core.util.SizeFCompat toSizeFCompat(android.util.SizeF);
+ }
+
+ public interface Supplier<T> {
+ method public T! get();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class TimeUtils {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, java.io.PrintWriter!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, java.io.PrintWriter!, int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, StringBuilder!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, long, java.io.PrintWriter!);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int HUNDRED_DAY_FIELD_LEN = 19; // 0x13
+ }
+
+}
+
+package androidx.core.view {
+
+ public class AccessibilityDelegateCompat {
+ ctor public AccessibilityDelegateCompat();
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public AccessibilityDelegateCompat(android.view.View.AccessibilityDelegate);
+ method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
+ method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+ method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+ method public void sendAccessibilityEvent(android.view.View, int);
+ method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+ }
+
+ public abstract class ActionProvider {
+ ctor public ActionProvider(android.content.Context);
+ method public android.content.Context getContext();
+ method public boolean hasSubMenu();
+ method public boolean isVisible();
+ method public abstract android.view.View onCreateActionView();
+ method public android.view.View onCreateActionView(android.view.MenuItem);
+ method public boolean onPerformDefaultAction();
+ method public void onPrepareSubMenu(android.view.SubMenu);
+ method public boolean overridesItemVisibility();
+ method public void refreshVisibility();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void reset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSubUiVisibilityListener(androidx.core.view.ActionProvider.SubUiVisibilityListener?);
+ method public void setVisibilityListener(androidx.core.view.ActionProvider.VisibilityListener?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void subUiVisibilityChanged(boolean);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface ActionProvider.SubUiVisibilityListener {
+ method public void onSubUiVisibilityChanged(boolean);
+ }
+
+ public static interface ActionProvider.VisibilityListener {
+ method public void onActionProviderVisibilityChanged(boolean);
+ }
+
+ public final class ContentInfoCompat {
+ method public android.content.ClipData getClip();
+ method public android.os.Bundle? getExtras();
+ method @androidx.core.view.ContentInfoCompat.Flags public int getFlags();
+ method public android.net.Uri? getLinkUri();
+ method @androidx.core.view.ContentInfoCompat.Source public int getSource();
+ method @RequiresApi(31) public static android.util.Pair<android.view.ContentInfo!,android.view.ContentInfo!> partition(android.view.ContentInfo, java.util.function.Predicate<android.content.ClipData.Item!>);
+ method public android.util.Pair<androidx.core.view.ContentInfoCompat!,androidx.core.view.ContentInfoCompat!> partition(androidx.core.util.Predicate<android.content.ClipData.Item!>);
+ method @RequiresApi(31) public android.view.ContentInfo toContentInfo();
+ method @RequiresApi(31) public static androidx.core.view.ContentInfoCompat toContentInfoCompat(android.view.ContentInfo);
+ field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
+ field public static final int SOURCE_APP = 0; // 0x0
+ field public static final int SOURCE_AUTOFILL = 4; // 0x4
+ field public static final int SOURCE_CLIPBOARD = 1; // 0x1
+ field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
+ field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+ field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
+ }
+
+ public static final class ContentInfoCompat.Builder {
+ ctor public ContentInfoCompat.Builder(android.content.ClipData, @androidx.core.view.ContentInfoCompat.Source int);
+ ctor public ContentInfoCompat.Builder(androidx.core.view.ContentInfoCompat);
+ method public androidx.core.view.ContentInfoCompat build();
+ method public androidx.core.view.ContentInfoCompat.Builder setClip(android.content.ClipData);
+ method public androidx.core.view.ContentInfoCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.view.ContentInfoCompat.Builder setFlags(@androidx.core.view.ContentInfoCompat.Flags int);
+ method public androidx.core.view.ContentInfoCompat.Builder setLinkUri(android.net.Uri?);
+ method public androidx.core.view.ContentInfoCompat.Builder setSource(@androidx.core.view.ContentInfoCompat.Source int);
+ }
+
+ @IntDef(flag=true, value={androidx.core.view.ContentInfoCompat.FLAG_CONVERT_TO_PLAIN_TEXT}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentInfoCompat.Flags {
+ }
+
+ @IntDef({androidx.core.view.ContentInfoCompat.SOURCE_APP, androidx.core.view.ContentInfoCompat.SOURCE_CLIPBOARD, androidx.core.view.ContentInfoCompat.SOURCE_INPUT_METHOD, androidx.core.view.ContentInfoCompat.SOURCE_DRAG_AND_DROP, androidx.core.view.ContentInfoCompat.SOURCE_AUTOFILL, androidx.core.view.ContentInfoCompat.SOURCE_PROCESS_TEXT}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentInfoCompat.Source {
+ }
+
+ public final class DisplayCompat {
+ method public static androidx.core.view.DisplayCompat.ModeCompat getMode(android.content.Context, android.view.Display);
+ method public static androidx.core.view.DisplayCompat.ModeCompat![] getSupportedModes(android.content.Context, android.view.Display);
+ }
+
+ public static final class DisplayCompat.ModeCompat {
+ method public int getPhysicalHeight();
+ method public int getPhysicalWidth();
+ method @Deprecated public boolean isNative();
+ method @RequiresApi(android.os.Build.VERSION_CODES.M) public android.view.Display.Mode? toMode();
+ }
+
+ public final class DisplayCutoutCompat {
+ ctor public DisplayCutoutCompat(android.graphics.Rect?, java.util.List<android.graphics.Rect!>?);
+ ctor public DisplayCutoutCompat(androidx.core.graphics.Insets, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, androidx.core.graphics.Insets);
+ method public java.util.List<android.graphics.Rect!> getBoundingRects();
+ method public int getSafeInsetBottom();
+ method public int getSafeInsetLeft();
+ method public int getSafeInsetRight();
+ method public int getSafeInsetTop();
+ method public androidx.core.graphics.Insets getWaterfallInsets();
+ }
+
+ public final class DragAndDropPermissionsCompat {
+ method public void release();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.view.DragAndDropPermissionsCompat? request(android.app.Activity, android.view.DragEvent);
+ }
+
+ public class DragStartHelper {
+ ctor public DragStartHelper(android.view.View, androidx.core.view.DragStartHelper.OnDragStartListener);
+ method public void attach();
+ method public void detach();
+ method public void getTouchPosition(android.graphics.Point);
+ method public boolean onLongClick(android.view.View);
+ method public boolean onTouch(android.view.View, android.view.MotionEvent);
+ }
+
+ public static interface DragStartHelper.OnDragStartListener {
+ method public boolean onDragStart(android.view.View, androidx.core.view.DragStartHelper);
+ }
+
+ public final class GestureDetectorCompat {
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener);
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler?);
+ method public boolean isLongpressEnabled();
+ method public boolean onTouchEvent(android.view.MotionEvent);
+ method public void setIsLongpressEnabled(boolean);
+ method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener?);
+ }
+
+ public final class GravityCompat {
+ method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect, int);
+ method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static int getAbsoluteGravity(int, int);
+ field public static final int END = 8388613; // 0x800005
+ field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+ field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+ field public static final int START = 8388611; // 0x800003
+ }
+
+ public final class HapticFeedbackConstantsCompat {
+ field public static final int CLOCK_TICK = 4; // 0x4
+ field public static final int CONFIRM = 16; // 0x10
+ field public static final int CONTEXT_CLICK = 6; // 0x6
+ field public static final int DRAG_START = 25; // 0x19
+ field public static final int FLAG_IGNORE_VIEW_SETTING = 1; // 0x1
+ field public static final int GESTURE_END = 13; // 0xd
+ field public static final int GESTURE_START = 12; // 0xc
+ field public static final int GESTURE_THRESHOLD_ACTIVATE = 23; // 0x17
+ field public static final int GESTURE_THRESHOLD_DEACTIVATE = 24; // 0x18
+ field public static final int KEYBOARD_PRESS = 3; // 0x3
+ field public static final int KEYBOARD_RELEASE = 7; // 0x7
+ field public static final int KEYBOARD_TAP = 3; // 0x3
+ field public static final int LONG_PRESS = 0; // 0x0
+ field public static final int NO_HAPTICS = -1; // 0xffffffff
+ field public static final int REJECT = 17; // 0x11
+ field public static final int SEGMENT_FREQUENT_TICK = 27; // 0x1b
+ field public static final int SEGMENT_TICK = 26; // 0x1a
+ field public static final int TEXT_HANDLE_MOVE = 9; // 0x9
+ field public static final int TOGGLE_OFF = 22; // 0x16
+ field public static final int TOGGLE_ON = 21; // 0x15
+ field public static final int VIRTUAL_KEY = 1; // 0x1
+ field public static final int VIRTUAL_KEY_RELEASE = 8; // 0x8
+ }
+
+ public final class InputDeviceCompat {
+ field public static final int SOURCE_ANY = -256; // 0xffffff00
+ field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+ field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+ field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+ field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+ field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+ field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+ field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+ field public static final int SOURCE_DPAD = 513; // 0x201
+ field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+ field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+ field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+ field public static final int SOURCE_KEYBOARD = 257; // 0x101
+ field public static final int SOURCE_MOUSE = 8194; // 0x2002
+ field public static final int SOURCE_ROTARY_ENCODER = 4194304; // 0x400000
+ field public static final int SOURCE_STYLUS = 16386; // 0x4002
+ field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+ field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+ field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+ field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+ field public static final int SOURCE_UNKNOWN = 0; // 0x0
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class KeyEventDispatcher {
+ method public static boolean dispatchBeforeHierarchy(android.view.View, android.view.KeyEvent);
+ method public static boolean dispatchKeyEvent(androidx.core.view.KeyEventDispatcher.Component, android.view.View?, android.view.Window.Callback?, android.view.KeyEvent);
+ }
+
+ public static interface KeyEventDispatcher.Component {
+ method public boolean superDispatchKeyEvent(android.view.KeyEvent);
+ }
+
+ public final class LayoutInflaterCompat {
+ method @Deprecated public static androidx.core.view.LayoutInflaterFactory! getFactory(android.view.LayoutInflater!);
+ method @Deprecated public static void setFactory(android.view.LayoutInflater, androidx.core.view.LayoutInflaterFactory);
+ method public static void setFactory2(android.view.LayoutInflater, android.view.LayoutInflater.Factory2);
+ }
+
+ @Deprecated public interface LayoutInflaterFactory {
+ method @Deprecated public android.view.View! onCreateView(android.view.View!, String!, android.content.Context!, android.util.AttributeSet!);
+ }
+
+ public final class MarginLayoutParamsCompat {
+ method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
+ method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
+ method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
+ }
+
+ public final class MenuCompat {
+ method public static void setGroupDividerEnabled(android.view.Menu, boolean);
+ method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+ }
+
+ public interface MenuHost {
+ method public void addMenuProvider(androidx.core.view.MenuProvider);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State);
+ method public void invalidateMenu();
+ method public void removeMenuProvider(androidx.core.view.MenuProvider);
+ }
+
+ public class MenuHostHelper {
+ ctor public MenuHostHelper(Runnable);
+ method public void addMenuProvider(androidx.core.view.MenuProvider);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State);
+ method public void onCreateMenu(android.view.Menu, android.view.MenuInflater);
+ method public void onMenuClosed(android.view.Menu);
+ method public boolean onMenuItemSelected(android.view.MenuItem);
+ method public void onPrepareMenu(android.view.Menu);
+ method public void removeMenuProvider(androidx.core.view.MenuProvider);
+ }
+
+ public final class MenuItemCompat {
+ method @Deprecated public static boolean collapseActionView(android.view.MenuItem!);
+ method @Deprecated public static boolean expandActionView(android.view.MenuItem!);
+ method public static androidx.core.view.ActionProvider? getActionProvider(android.view.MenuItem);
+ method @Deprecated public static android.view.View! getActionView(android.view.MenuItem!);
+ method public static int getAlphabeticModifiers(android.view.MenuItem);
+ method public static CharSequence? getContentDescription(android.view.MenuItem);
+ method public static android.content.res.ColorStateList? getIconTintList(android.view.MenuItem);
+ method public static android.graphics.PorterDuff.Mode? getIconTintMode(android.view.MenuItem);
+ method public static int getNumericModifiers(android.view.MenuItem);
+ method public static CharSequence? getTooltipText(android.view.MenuItem);
+ method @Deprecated public static boolean isActionViewExpanded(android.view.MenuItem!);
+ method public static android.view.MenuItem? setActionProvider(android.view.MenuItem, androidx.core.view.ActionProvider?);
+ method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
+ method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
+ method public static void setAlphabeticShortcut(android.view.MenuItem, char, int);
+ method public static void setContentDescription(android.view.MenuItem, CharSequence?);
+ method public static void setIconTintList(android.view.MenuItem, android.content.res.ColorStateList?);
+ method public static void setIconTintMode(android.view.MenuItem, android.graphics.PorterDuff.Mode?);
+ method public static void setNumericShortcut(android.view.MenuItem, char, int);
+ method @Deprecated public static android.view.MenuItem! setOnActionExpandListener(android.view.MenuItem!, androidx.core.view.MenuItemCompat.OnActionExpandListener!);
+ method public static void setShortcut(android.view.MenuItem, char, char, int, int);
+ method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+ method public static void setTooltipText(android.view.MenuItem, CharSequence?);
+ field @Deprecated public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+ field @Deprecated public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+ field @Deprecated public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+ field @Deprecated public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+ field @Deprecated public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+ }
+
+ @Deprecated public static interface MenuItemCompat.OnActionExpandListener {
+ method @Deprecated public boolean onMenuItemActionCollapse(android.view.MenuItem!);
+ method @Deprecated public boolean onMenuItemActionExpand(android.view.MenuItem!);
+ }
+
+ public interface MenuProvider {
+ method public void onCreateMenu(android.view.Menu, android.view.MenuInflater);
+ method public default void onMenuClosed(android.view.Menu);
+ method public boolean onMenuItemSelected(android.view.MenuItem);
+ method public default void onPrepareMenu(android.view.Menu);
+ }
+
+ public final class MotionEventCompat {
+ method @Deprecated public static int findPointerIndex(android.view.MotionEvent!, int);
+ method @Deprecated public static int getActionIndex(android.view.MotionEvent!);
+ method @Deprecated public static int getActionMasked(android.view.MotionEvent!);
+ method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int);
+ method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int, int);
+ method @Deprecated public static int getButtonState(android.view.MotionEvent!);
+ method @Deprecated public static int getPointerCount(android.view.MotionEvent!);
+ method @Deprecated public static int getPointerId(android.view.MotionEvent!, int);
+ method @Deprecated public static int getSource(android.view.MotionEvent!);
+ method @Deprecated public static float getX(android.view.MotionEvent!, int);
+ method @Deprecated public static float getY(android.view.MotionEvent!, int);
+ method public static boolean isFromSource(android.view.MotionEvent, int);
+ field @Deprecated public static final int ACTION_HOVER_ENTER = 9; // 0x9
+ field @Deprecated public static final int ACTION_HOVER_EXIT = 10; // 0xa
+ field @Deprecated public static final int ACTION_HOVER_MOVE = 7; // 0x7
+ field @Deprecated public static final int ACTION_MASK = 255; // 0xff
+ field @Deprecated public static final int ACTION_POINTER_DOWN = 5; // 0x5
+ field @Deprecated public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+ field @Deprecated public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+ field @Deprecated public static final int ACTION_POINTER_UP = 6; // 0x6
+ field @Deprecated public static final int ACTION_SCROLL = 8; // 0x8
+ field @Deprecated public static final int AXIS_BRAKE = 23; // 0x17
+ field @Deprecated public static final int AXIS_DISTANCE = 24; // 0x18
+ field @Deprecated public static final int AXIS_GAS = 22; // 0x16
+ field @Deprecated public static final int AXIS_GENERIC_1 = 32; // 0x20
+ field @Deprecated public static final int AXIS_GENERIC_10 = 41; // 0x29
+ field @Deprecated public static final int AXIS_GENERIC_11 = 42; // 0x2a
+ field @Deprecated public static final int AXIS_GENERIC_12 = 43; // 0x2b
+ field @Deprecated public static final int AXIS_GENERIC_13 = 44; // 0x2c
+ field @Deprecated public static final int AXIS_GENERIC_14 = 45; // 0x2d
+ field @Deprecated public static final int AXIS_GENERIC_15 = 46; // 0x2e
+ field @Deprecated public static final int AXIS_GENERIC_16 = 47; // 0x2f
+ field @Deprecated public static final int AXIS_GENERIC_2 = 33; // 0x21
+ field @Deprecated public static final int AXIS_GENERIC_3 = 34; // 0x22
+ field @Deprecated public static final int AXIS_GENERIC_4 = 35; // 0x23
+ field @Deprecated public static final int AXIS_GENERIC_5 = 36; // 0x24
+ field @Deprecated public static final int AXIS_GENERIC_6 = 37; // 0x25
+ field @Deprecated public static final int AXIS_GENERIC_7 = 38; // 0x26
+ field @Deprecated public static final int AXIS_GENERIC_8 = 39; // 0x27
+ field @Deprecated public static final int AXIS_GENERIC_9 = 40; // 0x28
+ field @Deprecated public static final int AXIS_HAT_X = 15; // 0xf
+ field @Deprecated public static final int AXIS_HAT_Y = 16; // 0x10
+ field @Deprecated public static final int AXIS_HSCROLL = 10; // 0xa
+ field @Deprecated public static final int AXIS_LTRIGGER = 17; // 0x11
+ field @Deprecated public static final int AXIS_ORIENTATION = 8; // 0x8
+ field @Deprecated public static final int AXIS_PRESSURE = 2; // 0x2
+ field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+ field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
+ field @Deprecated public static final int AXIS_RTRIGGER = 18; // 0x12
+ field @Deprecated public static final int AXIS_RUDDER = 20; // 0x14
+ field @Deprecated public static final int AXIS_RX = 12; // 0xc
+ field @Deprecated public static final int AXIS_RY = 13; // 0xd
+ field @Deprecated public static final int AXIS_RZ = 14; // 0xe
+ field public static final int AXIS_SCROLL = 26; // 0x1a
+ field @Deprecated public static final int AXIS_SIZE = 3; // 0x3
+ field @Deprecated public static final int AXIS_THROTTLE = 19; // 0x13
+ field @Deprecated public static final int AXIS_TILT = 25; // 0x19
+ field @Deprecated public static final int AXIS_TOOL_MAJOR = 6; // 0x6
+ field @Deprecated public static final int AXIS_TOOL_MINOR = 7; // 0x7
+ field @Deprecated public static final int AXIS_TOUCH_MAJOR = 4; // 0x4
+ field @Deprecated public static final int AXIS_TOUCH_MINOR = 5; // 0x5
+ field @Deprecated public static final int AXIS_VSCROLL = 9; // 0x9
+ field @Deprecated public static final int AXIS_WHEEL = 21; // 0x15
+ field @Deprecated public static final int AXIS_X = 0; // 0x0
+ field @Deprecated public static final int AXIS_Y = 1; // 0x1
+ field @Deprecated public static final int AXIS_Z = 11; // 0xb
+ field @Deprecated public static final int BUTTON_PRIMARY = 1; // 0x1
+ }
+
+ public interface NestedScrollingChild {
+ method public boolean dispatchNestedFling(float, float, boolean);
+ method public boolean dispatchNestedPreFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+ method public boolean hasNestedScrollingParent();
+ method public boolean isNestedScrollingEnabled();
+ method public void setNestedScrollingEnabled(boolean);
+ method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int);
+ method public void stopNestedScroll();
+ }
+
+ public interface NestedScrollingChild2 extends androidx.core.view.NestedScrollingChild {
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean hasNestedScrollingParent(@androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void stopNestedScroll(@androidx.core.view.ViewCompat.NestedScrollType int);
+ }
+
+ public interface NestedScrollingChild3 extends androidx.core.view.NestedScrollingChild2 {
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int, int[]);
+ }
+
+ public class NestedScrollingChildHelper {
+ ctor public NestedScrollingChildHelper(android.view.View);
+ method public boolean dispatchNestedFling(float, float, boolean);
+ method public boolean dispatchNestedPreFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int, int[]?);
+ method public boolean hasNestedScrollingParent();
+ method public boolean hasNestedScrollingParent(@androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean isNestedScrollingEnabled();
+ method public void onDetachedFromWindow();
+ method public void onStopNestedScroll(android.view.View);
+ method public void setNestedScrollingEnabled(boolean);
+ method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int);
+ method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void stopNestedScroll();
+ method public void stopNestedScroll(@androidx.core.view.ViewCompat.NestedScrollType int);
+ }
+
+ public interface NestedScrollingParent {
+ method @androidx.core.view.ViewCompat.ScrollAxis public int getNestedScrollAxes();
+ method public boolean onNestedFling(android.view.View, float, float, boolean);
+ method public boolean onNestedPreFling(android.view.View, float, float);
+ method public void onNestedPreScroll(android.view.View, int, int, int[]);
+ method public void onNestedScroll(android.view.View, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+ method public void onStopNestedScroll(android.view.View);
+ }
+
+ public interface NestedScrollingParent2 extends androidx.core.view.NestedScrollingParent {
+ method public void onNestedPreScroll(android.view.View, int, int, int[], @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void onStopNestedScroll(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+ }
+
+ public interface NestedScrollingParent3 extends androidx.core.view.NestedScrollingParent2 {
+ method public void onNestedScroll(android.view.View, int, int, int, int, @androidx.core.view.ViewCompat.NestedScrollType int, int[]);
+ }
+
+ public class NestedScrollingParentHelper {
+ ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+ method @androidx.core.view.ViewCompat.ScrollAxis public int getNestedScrollAxes();
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void onStopNestedScroll(android.view.View);
+ method public void onStopNestedScroll(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+ }
+
+ public interface OnApplyWindowInsetsListener {
+ method public androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ }
+
+ public interface OnReceiveContentListener {
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ }
+
+ public interface OnReceiveContentViewBehavior {
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(androidx.core.view.ContentInfoCompat);
+ }
+
+ public final class OneShotPreDrawListener implements android.view.View.OnAttachStateChangeListener android.view.ViewTreeObserver.OnPreDrawListener {
+ method public static androidx.core.view.OneShotPreDrawListener add(android.view.View, Runnable);
+ method public boolean onPreDraw();
+ method public void onViewAttachedToWindow(android.view.View);
+ method public void onViewDetachedFromWindow(android.view.View);
+ method public void removeListener();
+ }
+
+ public final class PointerIconCompat {
+ method public static androidx.core.view.PointerIconCompat create(android.graphics.Bitmap, float, float);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public Object? getPointerIcon();
+ method public static androidx.core.view.PointerIconCompat getSystemIcon(android.content.Context, int);
+ method public static androidx.core.view.PointerIconCompat load(android.content.res.Resources, int);
+ field public static final int TYPE_ALIAS = 1010; // 0x3f2
+ field public static final int TYPE_ALL_SCROLL = 1013; // 0x3f5
+ field public static final int TYPE_ARROW = 1000; // 0x3e8
+ field public static final int TYPE_CELL = 1006; // 0x3ee
+ field public static final int TYPE_CONTEXT_MENU = 1001; // 0x3e9
+ field public static final int TYPE_COPY = 1011; // 0x3f3
+ field public static final int TYPE_CROSSHAIR = 1007; // 0x3ef
+ field public static final int TYPE_DEFAULT = 1000; // 0x3e8
+ field public static final int TYPE_GRAB = 1020; // 0x3fc
+ field public static final int TYPE_GRABBING = 1021; // 0x3fd
+ field public static final int TYPE_HAND = 1002; // 0x3ea
+ field public static final int TYPE_HELP = 1003; // 0x3eb
+ field public static final int TYPE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+ field public static final int TYPE_NO_DROP = 1012; // 0x3f4
+ field public static final int TYPE_NULL = 0; // 0x0
+ field public static final int TYPE_TEXT = 1008; // 0x3f0
+ field public static final int TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+ field public static final int TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+ field public static final int TYPE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+ field public static final int TYPE_VERTICAL_TEXT = 1009; // 0x3f1
+ field public static final int TYPE_WAIT = 1004; // 0x3ec
+ field public static final int TYPE_ZOOM_IN = 1018; // 0x3fa
+ field public static final int TYPE_ZOOM_OUT = 1019; // 0x3fb
+ }
+
+ public final class ScaleGestureDetectorCompat {
+ method public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector);
+ method @Deprecated public static boolean isQuickScaleEnabled(Object!);
+ method public static void setQuickScaleEnabled(android.view.ScaleGestureDetector, boolean);
+ method @Deprecated public static void setQuickScaleEnabled(Object!, boolean);
+ }
+
+ public interface ScrollingView {
+ method public int computeHorizontalScrollExtent();
+ method public int computeHorizontalScrollOffset();
+ method public int computeHorizontalScrollRange();
+ method public int computeVerticalScrollExtent();
+ method public int computeVerticalScrollOffset();
+ method public int computeVerticalScrollRange();
+ }
+
+ public final class SoftwareKeyboardControllerCompat {
+ ctor public SoftwareKeyboardControllerCompat(android.view.View);
+ method public void hide();
+ method public void show();
+ }
+
+ public interface TintableBackgroundView {
+ method public android.content.res.ColorStateList? getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportBackgroundTintMode();
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList?);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ @Deprecated public final class VelocityTrackerCompat {
+ method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
+ method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+ }
+
+ public class ViewCompat {
+ ctor @Deprecated protected ViewCompat();
+ method public static int addAccessibilityAction(android.view.View, CharSequence, androidx.core.view.accessibility.AccessibilityViewCommand);
+ method public static void addKeyboardNavigationClusters(android.view.View, java.util.Collection<android.view.View!>, int);
+ method public static void addOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+ method public static androidx.core.view.ViewPropertyAnimatorCompat animate(android.view.View);
+ method @Deprecated public static boolean canScrollHorizontally(android.view.View!, int);
+ method @Deprecated public static boolean canScrollVertically(android.view.View!, int);
+ method public static void cancelDragAndDrop(android.view.View);
+ method @Deprecated public static int combineMeasuredStates(int, int);
+ method public static androidx.core.view.WindowInsetsCompat computeSystemWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat, android.graphics.Rect);
+ method public static androidx.core.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ method public static void dispatchFinishTemporaryDetach(android.view.View);
+ method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+ method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+ method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?);
+ method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?);
+ method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public static void dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int, int[]);
+ method public static void dispatchStartTemporaryDetach(android.view.View);
+ method public static void enableAccessibleClickableSpanSupport(android.view.View);
+ method public static int generateViewId();
+ method public static androidx.core.view.AccessibilityDelegateCompat? getAccessibilityDelegate(android.view.View);
+ method public static int getAccessibilityLiveRegion(android.view.View);
+ method public static androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
+ method @UiThread public static CharSequence? getAccessibilityPaneTitle(android.view.View);
+ method @Deprecated public static float getAlpha(android.view.View!);
+ method public static androidx.core.view.autofill.AutofillIdCompat? getAutofillId(android.view.View);
+ method public static android.content.res.ColorStateList? getBackgroundTintList(android.view.View);
+ method public static android.graphics.PorterDuff.Mode? getBackgroundTintMode(android.view.View);
+ method public static android.graphics.Rect? getClipBounds(android.view.View);
+ method public static androidx.core.view.contentcapture.ContentCaptureSessionCompat? getContentCaptureSession(android.view.View);
+ method public static android.view.Display? getDisplay(android.view.View);
+ method public static float getElevation(android.view.View);
+ method public static boolean getFitsSystemWindows(android.view.View);
+ method public static int getImportantForAccessibility(android.view.View);
+ method public static int getImportantForAutofill(android.view.View);
+ method public static int getImportantForContentCapture(android.view.View);
+ method public static int getLabelFor(android.view.View);
+ method @Deprecated public static int getLayerType(android.view.View!);
+ method public static int getLayoutDirection(android.view.View);
+ method @Deprecated public static android.graphics.Matrix? getMatrix(android.view.View!);
+ method @Deprecated public static int getMeasuredHeightAndState(android.view.View!);
+ method @Deprecated public static int getMeasuredState(android.view.View!);
+ method @Deprecated public static int getMeasuredWidthAndState(android.view.View!);
+ method public static int getMinimumHeight(android.view.View);
+ method public static int getMinimumWidth(android.view.View);
+ method public static int getNextClusterForwardId(android.view.View);
+ method public static String![]? getOnReceiveContentMimeTypes(android.view.View);
+ method @Deprecated public static int getOverScrollMode(android.view.View!);
+ method @Px public static int getPaddingEnd(android.view.View);
+ method @Px public static int getPaddingStart(android.view.View);
+ method public static android.view.ViewParent? getParentForAccessibility(android.view.View);
+ method @Deprecated public static float getPivotX(android.view.View!);
+ method @Deprecated public static float getPivotY(android.view.View!);
+ method public static androidx.core.view.WindowInsetsCompat? getRootWindowInsets(android.view.View);
+ method @Deprecated public static float getRotation(android.view.View!);
+ method @Deprecated public static float getRotationX(android.view.View!);
+ method @Deprecated public static float getRotationY(android.view.View!);
+ method @Deprecated public static float getScaleX(android.view.View!);
+ method @Deprecated public static float getScaleY(android.view.View!);
+ method public static int getScrollIndicators(android.view.View);
+ method @UiThread public static CharSequence? getStateDescription(android.view.View);
+ method public static java.util.List<android.graphics.Rect!> getSystemGestureExclusionRects(android.view.View);
+ method public static String? getTransitionName(android.view.View);
+ method @Deprecated public static float getTranslationX(android.view.View!);
+ method @Deprecated public static float getTranslationY(android.view.View!);
+ method public static float getTranslationZ(android.view.View);
+ method @Deprecated public static androidx.core.view.WindowInsetsControllerCompat? getWindowInsetsController(android.view.View);
+ method @Deprecated public static int getWindowSystemUiVisibility(android.view.View);
+ method @Deprecated public static float getX(android.view.View!);
+ method @Deprecated public static float getY(android.view.View!);
+ method public static float getZ(android.view.View);
+ method public static boolean hasAccessibilityDelegate(android.view.View);
+ method public static boolean hasExplicitFocusable(android.view.View);
+ method public static boolean hasNestedScrollingParent(android.view.View);
+ method public static boolean hasNestedScrollingParent(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public static boolean hasOnClickListeners(android.view.View);
+ method public static boolean hasOverlappingRendering(android.view.View);
+ method public static boolean hasTransientState(android.view.View);
+ method @UiThread public static boolean isAccessibilityHeading(android.view.View);
+ method public static boolean isAttachedToWindow(android.view.View);
+ method public static boolean isFocusedByDefault(android.view.View);
+ method public static boolean isImportantForAccessibility(android.view.View);
+ method public static boolean isImportantForAutofill(android.view.View);
+ method public static boolean isImportantForContentCapture(android.view.View);
+ method public static boolean isInLayout(android.view.View);
+ method public static boolean isKeyboardNavigationCluster(android.view.View);
+ method public static boolean isLaidOut(android.view.View);
+ method public static boolean isLayoutDirectionResolved(android.view.View);
+ method public static boolean isNestedScrollingEnabled(android.view.View);
+ method @Deprecated public static boolean isOpaque(android.view.View!);
+ method public static boolean isPaddingRelative(android.view.View);
+ method @UiThread public static boolean isScreenReaderFocusable(android.view.View);
+ method @Deprecated public static void jumpDrawablesToCurrentState(android.view.View!);
+ method public static android.view.View? keyboardNavigationClusterSearch(android.view.View, android.view.View?, @androidx.core.view.ViewCompat.FocusDirection int);
+ method public static void offsetLeftAndRight(android.view.View, int);
+ method public static void offsetTopAndBottom(android.view.View, int);
+ method public static androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ method @Deprecated public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+ method @Deprecated public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+ method public static boolean performHapticFeedback(android.view.View, int);
+ method public static boolean performHapticFeedback(android.view.View, int, int);
+ method public static androidx.core.view.ContentInfoCompat? performReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ method public static void postInvalidateOnAnimation(android.view.View);
+ method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+ method public static void postOnAnimation(android.view.View, Runnable);
+ method public static void postOnAnimationDelayed(android.view.View, Runnable, long);
+ method public static void removeAccessibilityAction(android.view.View, int);
+ method public static void removeOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+ method public static void replaceAccessibilityAction(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat, CharSequence?, androidx.core.view.accessibility.AccessibilityViewCommand?);
+ method public static void requestApplyInsets(android.view.View);
+ method public static <T extends android.view.View> T requireViewById(android.view.View, @IdRes int);
+ method @Deprecated public static int resolveSizeAndState(int, int, int);
+ method public static boolean restoreDefaultFocus(android.view.View);
+ method public static void saveAttributeDataForStyleable(android.view.View, android.content.Context, int[], android.util.AttributeSet?, android.content.res.TypedArray, int, int);
+ method public static void setAccessibilityDelegate(android.view.View, androidx.core.view.AccessibilityDelegateCompat?);
+ method @UiThread public static void setAccessibilityHeading(android.view.View, boolean);
+ method public static void setAccessibilityLiveRegion(android.view.View, int);
+ method @UiThread public static void setAccessibilityPaneTitle(android.view.View, CharSequence?);
+ method @Deprecated public static void setActivated(android.view.View!, boolean);
+ method @Deprecated public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
+ method public static void setAutofillHints(android.view.View, java.lang.String!...);
+ method public static void setAutofillId(android.view.View, androidx.core.view.autofill.AutofillIdCompat?);
+ method public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
+ method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList?);
+ method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode?);
+ method @Deprecated public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup!, boolean);
+ method public static void setClipBounds(android.view.View, android.graphics.Rect?);
+ method public static void setContentCaptureSession(android.view.View, androidx.core.view.contentcapture.ContentCaptureSessionCompat?);
+ method public static void setElevation(android.view.View, float);
+ method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
+ method public static void setFocusedByDefault(android.view.View, boolean);
+ method public static void setHasTransientState(android.view.View, boolean);
+ method @UiThread public static void setImportantForAccessibility(android.view.View, int);
+ method public static void setImportantForAutofill(android.view.View, int);
+ method public static void setImportantForContentCapture(android.view.View, int);
+ method public static void setKeyboardNavigationCluster(android.view.View, boolean);
+ method public static void setLabelFor(android.view.View, @IdRes int);
+ method public static void setLayerPaint(android.view.View, android.graphics.Paint?);
+ method @Deprecated public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
+ method public static void setLayoutDirection(android.view.View, int);
+ method public static void setNestedScrollingEnabled(android.view.View, boolean);
+ method public static void setNextClusterForwardId(android.view.View, int);
+ method public static void setOnApplyWindowInsetsListener(android.view.View, androidx.core.view.OnApplyWindowInsetsListener?);
+ method public static void setOnReceiveContentListener(android.view.View, String![]?, androidx.core.view.OnReceiveContentListener?);
+ method @Deprecated public static void setOverScrollMode(android.view.View!, int);
+ method public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
+ method @Deprecated public static void setPivotX(android.view.View!, float);
+ method @Deprecated public static void setPivotY(android.view.View!, float);
+ method public static void setPointerIcon(android.view.View, androidx.core.view.PointerIconCompat?);
+ method @Deprecated public static void setRotation(android.view.View!, float);
+ method @Deprecated public static void setRotationX(android.view.View!, float);
+ method @Deprecated public static void setRotationY(android.view.View!, float);
+ method @Deprecated public static void setSaveFromParentEnabled(android.view.View!, boolean);
+ method @Deprecated public static void setScaleX(android.view.View!, float);
+ method @Deprecated public static void setScaleY(android.view.View!, float);
+ method @UiThread public static void setScreenReaderFocusable(android.view.View, boolean);
+ method public static void setScrollIndicators(android.view.View, @androidx.core.view.ViewCompat.ScrollIndicators int);
+ method public static void setScrollIndicators(android.view.View, @androidx.core.view.ViewCompat.ScrollIndicators int, @androidx.core.view.ViewCompat.ScrollIndicators int);
+ method @UiThread public static void setStateDescription(android.view.View, CharSequence?);
+ method public static void setSystemGestureExclusionRects(android.view.View, java.util.List<android.graphics.Rect!>);
+ method public static void setTooltipText(android.view.View, CharSequence?);
+ method public static void setTransitionName(android.view.View, String?);
+ method @Deprecated public static void setTranslationX(android.view.View!, float);
+ method @Deprecated public static void setTranslationY(android.view.View!, float);
+ method public static void setTranslationZ(android.view.View, float);
+ method public static void setWindowInsetsAnimationCallback(android.view.View, androidx.core.view.WindowInsetsAnimationCompat.Callback?);
+ method @Deprecated public static void setX(android.view.View!, float);
+ method @Deprecated public static void setY(android.view.View!, float);
+ method public static void setZ(android.view.View, float);
+ method public static boolean startDragAndDrop(android.view.View, android.content.ClipData?, android.view.View.DragShadowBuilder, Object?, int);
+ method public static boolean startNestedScroll(android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+ method public static boolean startNestedScroll(android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public static void stopNestedScroll(android.view.View);
+ method public static void stopNestedScroll(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder);
+ field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+ field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+ field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+ field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0; // 0x0
+ field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 2; // 0x2
+ field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 8; // 0x8
+ field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 1; // 0x1
+ field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 4; // 0x4
+ field @Deprecated public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+ field @Deprecated public static final int LAYER_TYPE_NONE = 0; // 0x0
+ field @Deprecated public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+ field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+ field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+ field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+ field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+ field @Deprecated public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+ field @Deprecated public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+ field @Deprecated public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
+ field @Deprecated public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+ field @Deprecated public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
+ field @Deprecated public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+ field @Deprecated public static final int OVER_SCROLL_NEVER = 2; // 0x2
+ field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+ field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+ field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+ field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+ field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+ field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+ field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+ field public static final int TYPE_NON_TOUCH = 1; // 0x1
+ field public static final int TYPE_TOUCH = 0; // 0x0
+ }
+
+ @IntDef({android.view.View.FOCUS_LEFT, android.view.View.FOCUS_UP, android.view.View.FOCUS_RIGHT, android.view.View.FOCUS_DOWN, android.view.View.FOCUS_FORWARD, android.view.View.FOCUS_BACKWARD}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.FocusDirection {
+ }
+
+ @IntDef({android.view.View.FOCUS_LEFT, android.view.View.FOCUS_UP, android.view.View.FOCUS_RIGHT, android.view.View.FOCUS_DOWN}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.FocusRealDirection {
+ }
+
+ @IntDef({android.view.View.FOCUS_FORWARD, android.view.View.FOCUS_BACKWARD}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.FocusRelativeDirection {
+ }
+
+ @IntDef({androidx.core.view.ViewCompat.TYPE_TOUCH, androidx.core.view.ViewCompat.TYPE_NON_TOUCH}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.NestedScrollType {
+ }
+
+ public static interface ViewCompat.OnUnhandledKeyEventListenerCompat {
+ method public boolean onUnhandledKeyEvent(android.view.View, android.view.KeyEvent);
+ }
+
+ @IntDef(value={androidx.core.view.ViewCompat.SCROLL_AXIS_NONE, androidx.core.view.ViewCompat.SCROLL_AXIS_HORIZONTAL, androidx.core.view.ViewCompat.SCROLL_AXIS_VERTICAL}, flag=true) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.ScrollAxis {
+ }
+
+ @IntDef(flag=true, value={androidx.core.view.ViewCompat.SCROLL_INDICATOR_TOP, androidx.core.view.ViewCompat.SCROLL_INDICATOR_BOTTOM, androidx.core.view.ViewCompat.SCROLL_INDICATOR_LEFT, androidx.core.view.ViewCompat.SCROLL_INDICATOR_RIGHT, androidx.core.view.ViewCompat.SCROLL_INDICATOR_START, androidx.core.view.ViewCompat.SCROLL_INDICATOR_END}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.ScrollIndicators {
+ }
+
+ public final class ViewConfigurationCompat {
+ method public static float getScaledHorizontalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+ method public static int getScaledHoverSlop(android.view.ViewConfiguration);
+ method @Deprecated public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
+ method public static float getScaledVerticalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+ method @Deprecated public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
+ method public static boolean shouldShowMenuShortcutsWhenKeyboardPresent(android.view.ViewConfiguration, android.content.Context);
+ }
+
+ public final class ViewGroupCompat {
+ method public static int getLayoutMode(android.view.ViewGroup);
+ method @androidx.core.view.ViewCompat.ScrollAxis public static int getNestedScrollAxes(android.view.ViewGroup);
+ method public static boolean isTransitionGroup(android.view.ViewGroup);
+ method @Deprecated public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static void setLayoutMode(android.view.ViewGroup, int);
+ method @Deprecated public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
+ method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+ field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+ field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+ }
+
+ public final class ViewParentCompat {
+ method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onNestedFling(android.view.ViewParent, android.view.View, float, float, boolean);
+ method public static boolean onNestedPreFling(android.view.ViewParent, android.view.View, float, float);
+ method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[]);
+ method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[], int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int, int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int, int, int[]);
+ method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int, int);
+ method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int, int);
+ method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
+ method public static void onStopNestedScroll(android.view.ViewParent, android.view.View, int);
+ method @Deprecated public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ }
+
+ public final class ViewPropertyAnimatorCompat {
+ method public androidx.core.view.ViewPropertyAnimatorCompat alpha(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat alphaBy(float);
+ method public void cancel();
+ method public long getDuration();
+ method public android.view.animation.Interpolator? getInterpolator();
+ method public long getStartDelay();
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotation(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setDuration(long);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setInterpolator(android.view.animation.Interpolator?);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setListener(androidx.core.view.ViewPropertyAnimatorListener?);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setStartDelay(long);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setUpdateListener(androidx.core.view.ViewPropertyAnimatorUpdateListener?);
+ method public void start();
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationZ(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationZBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat withEndAction(Runnable);
+ method public androidx.core.view.ViewPropertyAnimatorCompat withLayer();
+ method public androidx.core.view.ViewPropertyAnimatorCompat withStartAction(Runnable);
+ method public androidx.core.view.ViewPropertyAnimatorCompat x(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat xBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat y(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat yBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat z(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat zBy(float);
+ }
+
+ public interface ViewPropertyAnimatorListener {
+ method public void onAnimationCancel(android.view.View);
+ method public void onAnimationEnd(android.view.View);
+ method public void onAnimationStart(android.view.View);
+ }
+
+ public class ViewPropertyAnimatorListenerAdapter implements androidx.core.view.ViewPropertyAnimatorListener {
+ ctor public ViewPropertyAnimatorListenerAdapter();
+ method public void onAnimationCancel(android.view.View);
+ method public void onAnimationEnd(android.view.View);
+ method public void onAnimationStart(android.view.View);
+ }
+
+ public interface ViewPropertyAnimatorUpdateListener {
+ method public void onAnimationUpdate(android.view.View);
+ }
+
+ public class ViewStructureCompat {
+ method public void setClassName(String);
+ method public void setContentDescription(CharSequence);
+ method public void setDimens(int, int, int, int, int, int);
+ method public void setText(CharSequence);
+ method @RequiresApi(23) public android.view.ViewStructure toViewStructure();
+ method @RequiresApi(23) public static androidx.core.view.ViewStructureCompat toViewStructureCompat(android.view.ViewStructure);
+ }
+
+ public final class WindowCompat {
+ method public static androidx.core.view.WindowInsetsControllerCompat getInsetsController(android.view.Window, android.view.View);
+ method public static <T extends android.view.View> T requireViewById(android.view.Window, @IdRes int);
+ method public static void setDecorFitsSystemWindows(android.view.Window, boolean);
+ field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+ field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+ field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+ }
+
+ public final class WindowInsetsAnimationCompat {
+ ctor public WindowInsetsAnimationCompat(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, android.view.animation.Interpolator?, long);
+ method @FloatRange(from=0.0f, to=1.0f) public float getAlpha();
+ method public long getDurationMillis();
+ method @FloatRange(from=0.0f, to=1.0f) public float getFraction();
+ method public float getInterpolatedFraction();
+ method public android.view.animation.Interpolator? getInterpolator();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public int getTypeMask();
+ method public void setAlpha(@FloatRange(from=0.0f, to=1.0f) float);
+ method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float);
+ }
+
+ public static final class WindowInsetsAnimationCompat.BoundsCompat {
+ ctor public WindowInsetsAnimationCompat.BoundsCompat(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public androidx.core.graphics.Insets getLowerBound();
+ method public androidx.core.graphics.Insets getUpperBound();
+ method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat inset(androidx.core.graphics.Insets);
+ method @RequiresApi(30) public android.view.WindowInsetsAnimation.Bounds toBounds();
+ method @RequiresApi(30) public static androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat toBoundsCompat(android.view.WindowInsetsAnimation.Bounds);
+ }
+
+ public abstract static class WindowInsetsAnimationCompat.Callback {
+ ctor public WindowInsetsAnimationCompat.Callback(@androidx.core.view.WindowInsetsAnimationCompat.Callback.DispatchMode int);
+ method @androidx.core.view.WindowInsetsAnimationCompat.Callback.DispatchMode public final int getDispatchMode();
+ method public void onEnd(androidx.core.view.WindowInsetsAnimationCompat);
+ method public void onPrepare(androidx.core.view.WindowInsetsAnimationCompat);
+ method public abstract androidx.core.view.WindowInsetsCompat onProgress(androidx.core.view.WindowInsetsCompat, java.util.List<androidx.core.view.WindowInsetsAnimationCompat!>);
+ method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat onStart(androidx.core.view.WindowInsetsAnimationCompat, androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat);
+ field public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; // 0x1
+ field public static final int DISPATCH_MODE_STOP = 0; // 0x0
+ }
+
+ @IntDef({androidx.core.view.WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_STOP, androidx.core.view.WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface WindowInsetsAnimationCompat.Callback.DispatchMode {
+ }
+
+ public interface WindowInsetsAnimationControlListenerCompat {
+ method public void onCancelled(androidx.core.view.WindowInsetsAnimationControllerCompat?);
+ method public void onFinished(androidx.core.view.WindowInsetsAnimationControllerCompat);
+ method public void onReady(androidx.core.view.WindowInsetsAnimationControllerCompat, @androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ }
+
+ public final class WindowInsetsAnimationControllerCompat {
+ method public void finish(boolean);
+ method public float getCurrentAlpha();
+ method @FloatRange(from=0.0f, to=1.0f) public float getCurrentFraction();
+ method public androidx.core.graphics.Insets getCurrentInsets();
+ method public androidx.core.graphics.Insets getHiddenStateInsets();
+ method public androidx.core.graphics.Insets getShownStateInsets();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public int getTypes();
+ method public boolean isCancelled();
+ method public boolean isFinished();
+ method public boolean isReady();
+ method public void setInsetsAndAlpha(androidx.core.graphics.Insets?, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+ }
+
+ public class WindowInsetsCompat {
+ ctor public WindowInsetsCompat(androidx.core.view.WindowInsetsCompat?);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeDisplayCutout();
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeStableInsets();
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeSystemWindowInsets();
+ method public androidx.core.view.DisplayCutoutCompat? getDisplayCutout();
+ method public androidx.core.graphics.Insets getInsets(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ method public androidx.core.graphics.Insets getInsetsIgnoringVisibility(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ method @Deprecated public androidx.core.graphics.Insets getMandatorySystemGestureInsets();
+ method @Deprecated public int getStableInsetBottom();
+ method @Deprecated public int getStableInsetLeft();
+ method @Deprecated public int getStableInsetRight();
+ method @Deprecated public int getStableInsetTop();
+ method @Deprecated public androidx.core.graphics.Insets getStableInsets();
+ method @Deprecated public androidx.core.graphics.Insets getSystemGestureInsets();
+ method @Deprecated public int getSystemWindowInsetBottom();
+ method @Deprecated public int getSystemWindowInsetLeft();
+ method @Deprecated public int getSystemWindowInsetRight();
+ method @Deprecated public int getSystemWindowInsetTop();
+ method @Deprecated public androidx.core.graphics.Insets getSystemWindowInsets();
+ method @Deprecated public androidx.core.graphics.Insets getTappableElementInsets();
+ method public boolean hasInsets();
+ method @Deprecated public boolean hasStableInsets();
+ method @Deprecated public boolean hasSystemWindowInsets();
+ method public androidx.core.view.WindowInsetsCompat inset(androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+ method public boolean isConsumed();
+ method public boolean isRound();
+ method public boolean isVisible(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+ method @RequiresApi(20) public android.view.WindowInsets? toWindowInsets();
+ method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets);
+ method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets, android.view.View?);
+ field public static final androidx.core.view.WindowInsetsCompat CONSUMED;
+ }
+
+ public static final class WindowInsetsCompat.Builder {
+ ctor public WindowInsetsCompat.Builder();
+ ctor public WindowInsetsCompat.Builder(androidx.core.view.WindowInsetsCompat);
+ method public androidx.core.view.WindowInsetsCompat build();
+ method public androidx.core.view.WindowInsetsCompat.Builder setDisplayCutout(androidx.core.view.DisplayCutoutCompat?);
+ method public androidx.core.view.WindowInsetsCompat.Builder setInsets(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat.Builder setInsetsIgnoringVisibility(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setMandatorySystemGestureInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setStableInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemGestureInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemWindowInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setTappableElementInsets(androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat.Builder setVisible(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, boolean);
+ }
+
+ public static final class WindowInsetsCompat.Type {
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int captionBar();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int displayCutout();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int ime();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int mandatorySystemGestures();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int navigationBars();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int statusBars();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int systemBars();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int systemGestures();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int tappableElement();
+ }
+
+ @IntDef(flag=true, value={0x1, 0x2, 0x4, 0x8, 0x100, 0x10, 0x20, 0x40, 0x80}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface WindowInsetsCompat.Type.InsetsType {
+ }
+
+ public final class WindowInsetsControllerCompat {
+ ctor public WindowInsetsControllerCompat(android.view.Window, android.view.View);
+ method public void addOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+ method public void controlWindowInsetsAnimation(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, long, android.view.animation.Interpolator?, android.os.CancellationSignal?, androidx.core.view.WindowInsetsAnimationControlListenerCompat);
+ method public int getSystemBarsBehavior();
+ method public void hide(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ method public boolean isAppearanceLightNavigationBars();
+ method public boolean isAppearanceLightStatusBars();
+ method public void removeOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+ method public void setAppearanceLightNavigationBars(boolean);
+ method public void setAppearanceLightStatusBars(boolean);
+ method public void setSystemBarsBehavior(int);
+ method public void show(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ method @Deprecated @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
+ field public static final int BEHAVIOR_DEFAULT = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
+ field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
+ }
+
+ public static interface WindowInsetsControllerCompat.OnControllableInsetsChangedListener {
+ method public void onControllableInsetsChanged(androidx.core.view.WindowInsetsControllerCompat, @androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ }
+
+}
+
+package androidx.core.view.accessibility {
+
+ public final class AccessibilityClickableSpanCompat extends android.text.style.ClickableSpan {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public AccessibilityClickableSpanCompat(int, androidx.core.view.accessibility.AccessibilityNodeInfoCompat, int);
+ method public void onClick(android.view.View);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final String SPAN_ID = "ACCESSIBILITY_CLICKABLE_SPAN_ID";
+ }
+
+ public final class AccessibilityEventCompat {
+ method @Deprecated public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! asRecord(android.view.accessibility.AccessibilityEvent!);
+ method public static int getAction(android.view.accessibility.AccessibilityEvent);
+ method @androidx.core.view.accessibility.AccessibilityEventCompat.ContentChangeType public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
+ method public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! getRecord(android.view.accessibility.AccessibilityEvent!, int);
+ method @Deprecated public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
+ method public static void setAction(android.view.accessibility.AccessibilityEvent, int);
+ method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, @androidx.core.view.accessibility.AccessibilityEventCompat.ContentChangeType int);
+ method public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent, int);
+ field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 256; // 0x100
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 128; // 0x80
+ field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
+ field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
+ field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
+ field public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 64; // 0x40
+ field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+ field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+ field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+ field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+ field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
+ field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+ field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+ field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+ field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+ field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+ field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+ field public static final int TYPE_VIEW_CONTEXT_CLICKED = 8388608; // 0x800000
+ field @Deprecated public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+ field @Deprecated public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+ field @Deprecated public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+ field @Deprecated public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+ field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+ field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
+ field @Deprecated public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+ }
+
+ @IntDef(flag=true, value={androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_SUBTREE, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_TEXT, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_UNDEFINED, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_DRAG_STARTED, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_DRAG_DROPPED, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_DRAG_CANCELLED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AccessibilityEventCompat.ContentChangeType {
+ }
+
+ public final class AccessibilityManagerCompat {
+ method @Deprecated public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+ method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+ method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
+ method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
+ method @Deprecated public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
+ method @Deprecated public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+ method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+ }
+
+ @Deprecated public static interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
+ method @Deprecated public void onAccessibilityStateChanged(boolean);
+ }
+
+ @Deprecated public abstract static class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat implements androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener {
+ ctor @Deprecated public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+ }
+
+ public static interface AccessibilityManagerCompat.TouchExplorationStateChangeListener {
+ method public void onTouchExplorationStateChanged(boolean);
+ }
+
+ public class AccessibilityNodeInfoCompat {
+ ctor @Deprecated public AccessibilityNodeInfoCompat(Object!);
+ method public void addAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+ method public void addAction(int);
+ method public void addChild(android.view.View!);
+ method public void addChild(android.view.View!, int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void addSpansToExtras(CharSequence!, android.view.View!);
+ method public boolean canOpenPopup();
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByText(String!);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByViewId(String!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! findFocus(int);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! focusSearch(int);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!>! getActionList();
+ method @Deprecated public int getActions();
+ method public java.util.List<java.lang.String!> getAvailableExtraData();
+ method @Deprecated public void getBoundsInParent(android.graphics.Rect!);
+ method public void getBoundsInScreen(android.graphics.Rect!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getChild(int);
+ method public int getChildCount();
+ method public CharSequence! getClassName();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.text.style.ClickableSpan![]! getClickableSpans(CharSequence!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! getCollectionInfo();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! getCollectionItemInfo();
+ method public CharSequence! getContentDescription();
+ method public int getDrawingOrder();
+ method public CharSequence! getError();
+ method public android.view.accessibility.AccessibilityNodeInfo.ExtraRenderingInfo? getExtraRenderingInfo();
+ method public android.os.Bundle! getExtras();
+ method public CharSequence? getHintText();
+ method @Deprecated public Object! getInfo();
+ method public int getInputType();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabelFor();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabeledBy();
+ method public int getLiveRegion();
+ method public int getMaxTextLength();
+ method public long getMinDurationBetweenContentChangesMillis();
+ method public int getMovementGranularities();
+ method public CharSequence! getPackageName();
+ method public CharSequence? getPaneTitle();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getParent();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! getRangeInfo();
+ method public CharSequence? getRoleDescription();
+ method public CharSequence? getStateDescription();
+ method public CharSequence! getText();
+ method public int getTextSelectionEnd();
+ method public int getTextSelectionStart();
+ method public CharSequence? getTooltipText();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat? getTouchDelegateInfo();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalAfter();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalBefore();
+ method public String? getUniqueId();
+ method public String! getViewIdResourceName();
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getWindow();
+ method public int getWindowId();
+ method public boolean hasRequestInitialAccessibilityFocus();
+ method public boolean isAccessibilityFocused();
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isContentInvalid();
+ method public boolean isContextClickable();
+ method public boolean isDismissable();
+ method public boolean isEditable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isHeading();
+ method public boolean isImportantForAccessibility();
+ method public boolean isLongClickable();
+ method public boolean isMultiLine();
+ method public boolean isPassword();
+ method public boolean isScreenReaderFocusable();
+ method public boolean isScrollable();
+ method public boolean isSelected();
+ method public boolean isShowingHintText();
+ method public boolean isTextEntryKey();
+ method public boolean isTextSelectable();
+ method public boolean isVisibleToUser();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!, int);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+ method public boolean performAction(int);
+ method public boolean performAction(int, android.os.Bundle!);
+ method @Deprecated public void recycle();
+ method public boolean refresh();
+ method public boolean removeAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+ method public boolean removeChild(android.view.View!);
+ method public boolean removeChild(android.view.View!, int);
+ method public void setAccessibilityFocused(boolean);
+ method public void setAvailableExtraData(java.util.List<java.lang.String!>);
+ method @Deprecated public void setBoundsInParent(android.graphics.Rect!);
+ method public void setBoundsInScreen(android.graphics.Rect!);
+ method public void setCanOpenPopup(boolean);
+ method public void setCheckable(boolean);
+ method public void setChecked(boolean);
+ method public void setClassName(CharSequence!);
+ method public void setClickable(boolean);
+ method public void setCollectionInfo(Object!);
+ method public void setCollectionItemInfo(Object!);
+ method public void setContentDescription(CharSequence!);
+ method public void setContentInvalid(boolean);
+ method public void setContextClickable(boolean);
+ method public void setDismissable(boolean);
+ method public void setDrawingOrder(int);
+ method public void setEditable(boolean);
+ method public void setEnabled(boolean);
+ method public void setError(CharSequence!);
+ method public void setFocusable(boolean);
+ method public void setFocused(boolean);
+ method public void setHeading(boolean);
+ method public void setHintText(CharSequence?);
+ method public void setImportantForAccessibility(boolean);
+ method public void setInputType(int);
+ method public void setLabelFor(android.view.View!);
+ method public void setLabelFor(android.view.View!, int);
+ method public void setLabeledBy(android.view.View!);
+ method public void setLabeledBy(android.view.View!, int);
+ method public void setLiveRegion(int);
+ method public void setLongClickable(boolean);
+ method public void setMaxTextLength(int);
+ method public void setMinDurationBetweenContentChangesMillis(long);
+ method public void setMovementGranularities(int);
+ method public void setMultiLine(boolean);
+ method public void setPackageName(CharSequence!);
+ method public void setPaneTitle(CharSequence?);
+ method public void setParent(android.view.View!);
+ method public void setParent(android.view.View!, int);
+ method public void setPassword(boolean);
+ method public void setRangeInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat!);
+ method public void setRequestInitialAccessibilityFocus(boolean);
+ method public void setRoleDescription(CharSequence?);
+ method public void setScreenReaderFocusable(boolean);
+ method public void setScrollable(boolean);
+ method public void setSelected(boolean);
+ method public void setShowingHintText(boolean);
+ method public void setSource(android.view.View!);
+ method public void setSource(android.view.View!, int);
+ method public void setStateDescription(CharSequence?);
+ method public void setText(CharSequence!);
+ method public void setTextEntryKey(boolean);
+ method public void setTextSelectable(boolean);
+ method public void setTextSelection(int, int);
+ method public void setTooltipText(CharSequence?);
+ method public void setTouchDelegateInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat);
+ method public void setTraversalAfter(android.view.View!);
+ method public void setTraversalAfter(android.view.View!, int);
+ method public void setTraversalBefore(android.view.View!);
+ method public void setTraversalBefore(android.view.View!, int);
+ method public void setUniqueId(String?);
+ method public void setViewIdResourceName(String!);
+ method public void setVisibleToUser(boolean);
+ method public android.view.accessibility.AccessibilityNodeInfo! unwrap();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! wrap(android.view.accessibility.AccessibilityNodeInfo);
+ field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+ field public static final String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+ field public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+ field public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+ field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+ field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
+ field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+ field public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
+ field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
+ field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
+ field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+ field public static final String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+ field public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+ field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+ field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+ field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+ field public static final int ACTION_CLICK = 16; // 0x10
+ field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+ field public static final int ACTION_COPY = 16384; // 0x4000
+ field public static final int ACTION_CUT = 65536; // 0x10000
+ field public static final int ACTION_DISMISS = 1048576; // 0x100000
+ field public static final int ACTION_EXPAND = 262144; // 0x40000
+ field public static final int ACTION_FOCUS = 1; // 0x1
+ field public static final int ACTION_LONG_CLICK = 32; // 0x20
+ field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+ field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+ field public static final int ACTION_PASTE = 32768; // 0x8000
+ field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+ field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+ field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+ field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+ field public static final int ACTION_SELECT = 4; // 0x4
+ field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+ field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+ field public static final int EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH = 20000; // 0x4e20
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
+ field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+ field public static final int FOCUS_INPUT = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+ field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+ field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+ field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int mParentVirtualDescendantId;
+ }
+
+ public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+ ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, CharSequence!);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, CharSequence!, androidx.core.view.accessibility.AccessibilityViewCommand!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! createReplacementAction(CharSequence!, androidx.core.view.accessibility.AccessibilityViewCommand!);
+ method public int getId();
+ method public CharSequence! getLabel();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean perform(android.view.View!, android.os.Bundle!);
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_ACCESSIBILITY_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_SELECTION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COLLAPSE;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CONTEXT_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COPY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CUT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_DISMISS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_CANCEL;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_DROP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_START;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_EXPAND;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_HIDE_TOOLTIP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_IME_ENTER;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_LONG_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_MOVE_WINDOW;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_HTML_ELEMENT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_DOWN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_LEFT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_RIGHT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_UP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PASTE;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PRESS_AND_HOLD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_HTML_ELEMENT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_BACKWARD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_DOWN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_FORWARD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_LEFT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_RIGHT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_TO_POSITION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_UP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SELECT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_PROGRESS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_SELECTION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_TEXT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_ON_SCREEN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SHOW_TEXT_SUGGESTIONS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_TOOLTIP;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected final androidx.core.view.accessibility.AccessibilityViewCommand! mCommand;
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+ method public int getColumnCount();
+ method public int getRowCount();
+ method public int getSelectionMode();
+ method public boolean isHierarchical();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean, int);
+ field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+ field public static final int SELECTION_MODE_NONE = 0; // 0x0
+ field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+ method public int getColumnIndex();
+ method public int getColumnSpan();
+ method public int getRowIndex();
+ method public int getRowSpan();
+ method @Deprecated public boolean isHeading();
+ method public boolean isSelected();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean, boolean);
+ }
+
+ public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+ method public float getCurrent();
+ method public float getMax();
+ method public float getMin();
+ method public int getType();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! obtain(int, float, float, float);
+ field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+ field public static final int RANGE_TYPE_INT = 0; // 0x0
+ field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+ }
+
+ public static final class AccessibilityNodeInfoCompat.TouchDelegateInfoCompat {
+ ctor public AccessibilityNodeInfoCompat.TouchDelegateInfoCompat(java.util.Map<android.graphics.Region!,android.view.View!>);
+ method public android.graphics.Region? getRegionAt(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getRegionCount();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getTargetForRegion(android.graphics.Region);
+ }
+
+ public class AccessibilityNodeProviderCompat {
+ ctor public AccessibilityNodeProviderCompat();
+ ctor public AccessibilityNodeProviderCompat(Object?);
+ method public void addExtraDataToAccessibilityNodeInfo(int, androidx.core.view.accessibility.AccessibilityNodeInfoCompat, String, android.os.Bundle?);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? createAccessibilityNodeInfo(int);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>? findAccessibilityNodeInfosByText(String, int);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? findFocus(int);
+ method public Object? getProvider();
+ method public boolean performAction(int, int, android.os.Bundle?);
+ field public static final int HOST_VIEW_ID = -1; // 0xffffffff
+ }
+
+ public class AccessibilityRecordCompat {
+ ctor @Deprecated public AccessibilityRecordCompat(Object!);
+ method @Deprecated public boolean equals(Object?);
+ method @Deprecated public int getAddedCount();
+ method @Deprecated public CharSequence! getBeforeText();
+ method @Deprecated public CharSequence! getClassName();
+ method @Deprecated public CharSequence! getContentDescription();
+ method @Deprecated public int getCurrentItemIndex();
+ method @Deprecated public int getFromIndex();
+ method @Deprecated public Object! getImpl();
+ method @Deprecated public int getItemCount();
+ method @Deprecated public int getMaxScrollX();
+ method public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord);
+ method @Deprecated public int getMaxScrollY();
+ method public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord);
+ method @Deprecated public android.os.Parcelable! getParcelableData();
+ method @Deprecated public int getRemovedCount();
+ method @Deprecated public int getScrollX();
+ method @Deprecated public int getScrollY();
+ method @Deprecated public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getSource();
+ method @Deprecated public java.util.List<java.lang.CharSequence!>! getText();
+ method @Deprecated public int getToIndex();
+ method @Deprecated public int getWindowId();
+ method @Deprecated public int hashCode();
+ method @Deprecated public boolean isChecked();
+ method @Deprecated public boolean isEnabled();
+ method @Deprecated public boolean isFullScreen();
+ method @Deprecated public boolean isPassword();
+ method @Deprecated public boolean isScrollable();
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain();
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain(androidx.core.view.accessibility.AccessibilityRecordCompat!);
+ method @Deprecated public void recycle();
+ method @Deprecated public void setAddedCount(int);
+ method @Deprecated public void setBeforeText(CharSequence!);
+ method @Deprecated public void setChecked(boolean);
+ method @Deprecated public void setClassName(CharSequence!);
+ method @Deprecated public void setContentDescription(CharSequence!);
+ method @Deprecated public void setCurrentItemIndex(int);
+ method @Deprecated public void setEnabled(boolean);
+ method @Deprecated public void setFromIndex(int);
+ method @Deprecated public void setFullScreen(boolean);
+ method @Deprecated public void setItemCount(int);
+ method public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord, int);
+ method @Deprecated public void setMaxScrollX(int);
+ method public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord, int);
+ method @Deprecated public void setMaxScrollY(int);
+ method @Deprecated public void setParcelableData(android.os.Parcelable!);
+ method @Deprecated public void setPassword(boolean);
+ method @Deprecated public void setRemovedCount(int);
+ method @Deprecated public void setScrollX(int);
+ method @Deprecated public void setScrollY(int);
+ method @Deprecated public void setScrollable(boolean);
+ method public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View?, int);
+ method @Deprecated public void setSource(android.view.View!);
+ method @Deprecated public void setSource(android.view.View!, int);
+ method @Deprecated public void setToIndex(int);
+ }
+
+ public interface AccessibilityViewCommand {
+ method public boolean perform(android.view.View, androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments?);
+ }
+
+ public abstract static class AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.CommandArguments();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setBundle(android.os.Bundle?);
+ }
+
+ public static final class AccessibilityViewCommand.MoveAtGranularityArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveAtGranularityArguments();
+ method public boolean getExtendSelection();
+ method public int getGranularity();
+ }
+
+ public static final class AccessibilityViewCommand.MoveHtmlArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveHtmlArguments();
+ method public String? getHTMLElement();
+ }
+
+ public static final class AccessibilityViewCommand.MoveWindowArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveWindowArguments();
+ method public int getX();
+ method public int getY();
+ }
+
+ public static final class AccessibilityViewCommand.ScrollToPositionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.ScrollToPositionArguments();
+ method public int getColumn();
+ method public int getRow();
+ }
+
+ public static final class AccessibilityViewCommand.SetProgressArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetProgressArguments();
+ method public float getProgress();
+ }
+
+ public static final class AccessibilityViewCommand.SetSelectionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetSelectionArguments();
+ method public int getEnd();
+ method public int getStart();
+ }
+
+ public static final class AccessibilityViewCommand.SetTextArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetTextArguments();
+ method public CharSequence? getText();
+ }
+
+ public class AccessibilityWindowInfoCompat {
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getAnchor();
+ method public void getBoundsInScreen(android.graphics.Rect);
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getChild(int);
+ method public int getChildCount();
+ method public int getDisplayId();
+ method public int getId();
+ method public int getLayer();
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getParent();
+ method public void getRegionInScreen(android.graphics.Region);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getRoot();
+ method public CharSequence? getTitle();
+ method public int getType();
+ method public boolean isAccessibilityFocused();
+ method public boolean isActive();
+ method public boolean isFocused();
+ method public boolean isInPictureInPictureMode();
+ method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat? obtain();
+ method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat? obtain(androidx.core.view.accessibility.AccessibilityWindowInfoCompat?);
+ method @Deprecated public void recycle();
+ method public android.view.accessibility.AccessibilityWindowInfo? unwrap();
+ field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+ field public static final int TYPE_APPLICATION = 1; // 0x1
+ field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
+ field public static final int TYPE_SYSTEM = 3; // 0x3
+ }
+
+}
+
+package androidx.core.view.animation {
+
+ public final class PathInterpolatorCompat {
+ method public static android.view.animation.Interpolator create(android.graphics.Path);
+ method public static android.view.animation.Interpolator create(float, float);
+ method public static android.view.animation.Interpolator create(float, float, float, float);
+ }
+
+}
+
+package androidx.core.view.autofill {
+
+ public class AutofillIdCompat {
+ method @RequiresApi(26) public android.view.autofill.AutofillId toAutofillId();
+ method @RequiresApi(26) public static androidx.core.view.autofill.AutofillIdCompat toAutofillIdCompat(android.view.autofill.AutofillId);
+ }
+
+}
+
+package androidx.core.view.contentcapture {
+
+ public class ContentCaptureSessionCompat {
+ method public android.view.autofill.AutofillId? newAutofillId(long);
+ method public androidx.core.view.ViewStructureCompat? newVirtualViewStructure(android.view.autofill.AutofillId, long);
+ method public void notifyViewTextChanged(android.view.autofill.AutofillId, CharSequence?);
+ method public void notifyViewsAppeared(java.util.List<android.view.ViewStructure!>);
+ method public void notifyViewsDisappeared(long[]);
+ method @RequiresApi(29) public android.view.contentcapture.ContentCaptureSession toContentCaptureSession();
+ method @RequiresApi(29) public static androidx.core.view.contentcapture.ContentCaptureSessionCompat toContentCaptureSessionCompat(android.view.contentcapture.ContentCaptureSession, android.view.View);
+ }
+
+}
+
+package androidx.core.view.inputmethod {
+
+ public final class EditorInfoCompat {
+ ctor @Deprecated public EditorInfoCompat();
+ method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo);
+ method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
+ method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, String![]?);
+ method public static void setInitialSurroundingSubText(android.view.inputmethod.EditorInfo, CharSequence, int);
+ method public static void setInitialSurroundingText(android.view.inputmethod.EditorInfo, CharSequence);
+ field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
+ field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
+ }
+
+ public final class InputConnectionCompat {
+ ctor @Deprecated public InputConnectionCompat();
+ method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+ method @Deprecated public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
+ method public static android.view.inputmethod.InputConnection createWrapper(android.view.View, android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
+ field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
+ }
+
+ public static interface InputConnectionCompat.OnCommitContentListener {
+ method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+ }
+
+ public final class InputContentInfoCompat {
+ ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri?);
+ method public android.net.Uri getContentUri();
+ method public android.content.ClipDescription getDescription();
+ method public android.net.Uri? getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
+ method public Object? unwrap();
+ method public static androidx.core.view.inputmethod.InputContentInfoCompat? wrap(Object?);
+ }
+
+}
+
+package androidx.core.widget {
+
+ public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+ ctor public AutoScrollHelper(android.view.View);
+ method public abstract boolean canTargetScrollHorizontally(int);
+ method public abstract boolean canTargetScrollVertically(int);
+ method public boolean isEnabled();
+ method public boolean isExclusive();
+ method public boolean onTouch(android.view.View!, android.view.MotionEvent!);
+ method public abstract void scrollTargetBy(int, int);
+ method public androidx.core.widget.AutoScrollHelper setActivationDelay(int);
+ method public androidx.core.widget.AutoScrollHelper setEdgeType(int);
+ method public androidx.core.widget.AutoScrollHelper! setEnabled(boolean);
+ method public androidx.core.widget.AutoScrollHelper! setExclusive(boolean);
+ method public androidx.core.widget.AutoScrollHelper setMaximumEdges(float, float);
+ method public androidx.core.widget.AutoScrollHelper setMaximumVelocity(float, float);
+ method public androidx.core.widget.AutoScrollHelper setMinimumVelocity(float, float);
+ method public androidx.core.widget.AutoScrollHelper setRampDownDuration(int);
+ method public androidx.core.widget.AutoScrollHelper setRampUpDuration(int);
+ method public androidx.core.widget.AutoScrollHelper setRelativeEdges(float, float);
+ method public androidx.core.widget.AutoScrollHelper setRelativeVelocity(float, float);
+ field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+ field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+ field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+ field public static final float NO_MAX = 3.4028235E38f;
+ field public static final float NO_MIN = 0.0f;
+ field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface AutoSizeableTextView {
+ method public int getAutoSizeMaxTextSize();
+ method public int getAutoSizeMinTextSize();
+ method public int getAutoSizeStepGranularity();
+ method public int[]! getAutoSizeTextAvailableSizes();
+ method @androidx.core.widget.TextViewCompat.AutoSizeTextType public int getAutoSizeTextType();
+ method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int) throws java.lang.IllegalArgumentException;
+ method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int) throws java.lang.IllegalArgumentException;
+ method public void setAutoSizeTextTypeWithDefaults(@androidx.core.widget.TextViewCompat.AutoSizeTextType int);
+ field @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final boolean PLATFORM_SUPPORTS_AUTOSIZE;
+ }
+
+ public final class CheckedTextViewCompat {
+ method public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
+ method public static android.content.res.ColorStateList? getCheckMarkTintList(android.widget.CheckedTextView);
+ method public static android.graphics.PorterDuff.Mode? getCheckMarkTintMode(android.widget.CheckedTextView);
+ method public static void setCheckMarkTintList(android.widget.CheckedTextView, android.content.res.ColorStateList?);
+ method public static void setCheckMarkTintMode(android.widget.CheckedTextView, android.graphics.PorterDuff.Mode?);
+ }
+
+ public final class CompoundButtonCompat {
+ method public static android.graphics.drawable.Drawable? getButtonDrawable(android.widget.CompoundButton);
+ method public static android.content.res.ColorStateList? getButtonTintList(android.widget.CompoundButton);
+ method public static android.graphics.PorterDuff.Mode? getButtonTintMode(android.widget.CompoundButton);
+ method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList?);
+ method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode?);
+ }
+
+ public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+ ctor public ContentLoadingProgressBar(android.content.Context);
+ ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet?);
+ method public void hide();
+ method public void onAttachedToWindow();
+ method public void onDetachedFromWindow();
+ method public void show();
+ }
+
+ public final class EdgeEffectCompat {
+ ctor @Deprecated public EdgeEffectCompat(android.content.Context!);
+ method public static android.widget.EdgeEffect create(android.content.Context, android.util.AttributeSet?);
+ method @Deprecated public boolean draw(android.graphics.Canvas!);
+ method @Deprecated public void finish();
+ method public static float getDistance(android.widget.EdgeEffect);
+ method @Deprecated public boolean isFinished();
+ method @Deprecated public boolean onAbsorb(int);
+ method public static void onPull(android.widget.EdgeEffect, float, float);
+ method @Deprecated public boolean onPull(float);
+ method @Deprecated public boolean onPull(float, float);
+ method public static float onPullDistance(android.widget.EdgeEffect, float, float);
+ method @Deprecated public boolean onRelease();
+ method @Deprecated public void setSize(int, int);
+ }
+
+ public class ImageViewCompat {
+ method public static android.content.res.ColorStateList? getImageTintList(android.widget.ImageView);
+ method public static android.graphics.PorterDuff.Mode? getImageTintMode(android.widget.ImageView);
+ method public static void setImageTintList(android.widget.ImageView, android.content.res.ColorStateList?);
+ method public static void setImageTintMode(android.widget.ImageView, android.graphics.PorterDuff.Mode?);
+ }
+
+ public final class ListPopupWindowCompat {
+ method public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
+ method @Deprecated public static android.view.View.OnTouchListener! createDragToOpenListener(Object!, android.view.View!);
+ }
+
+ public class ListViewAutoScrollHelper extends androidx.core.widget.AutoScrollHelper {
+ ctor public ListViewAutoScrollHelper(android.widget.ListView);
+ method public boolean canTargetScrollHorizontally(int);
+ method public boolean canTargetScrollVertically(int);
+ method public void scrollTargetBy(int, int);
+ }
+
+ public final class ListViewCompat {
+ method public static boolean canScrollList(android.widget.ListView, int);
+ method public static void scrollListBy(android.widget.ListView, int);
+ }
+
+ public class NestedScrollView extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingChild3 androidx.core.view.NestedScrollingParent3 androidx.core.view.ScrollingView {
+ ctor public NestedScrollView(android.content.Context);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?, int);
+ method public boolean arrowScroll(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollExtent();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollOffset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollRange();
+ method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollExtent();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollOffset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollRange();
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+ method public boolean executeKeyEvent(android.view.KeyEvent);
+ method public void fling(int);
+ method public boolean fullScroll(int);
+ method public int getMaxScrollAmount();
+ method public boolean hasNestedScrollingParent(int);
+ method public boolean isFillViewport();
+ method public boolean isSmoothScrollingEnabled();
+ method public void onAttachedToWindow();
+ method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View, int);
+ method public boolean pageScroll(int);
+ method public void setFillViewport(boolean);
+ method public void setOnScrollChangeListener(androidx.core.widget.NestedScrollView.OnScrollChangeListener?);
+ method public void setSmoothScrollingEnabled(boolean);
+ method public final void smoothScrollBy(int, int);
+ method public final void smoothScrollBy(int, int, int);
+ method public final void smoothScrollTo(int, int);
+ method public final void smoothScrollTo(int, int, int);
+ method public boolean startNestedScroll(int, int);
+ method public void stopNestedScroll(int);
+ }
+
+ public static interface NestedScrollView.OnScrollChangeListener {
+ method public void onScrollChange(androidx.core.widget.NestedScrollView, int, int, int, int);
+ }
+
+ public final class PopupMenuCompat {
+ method public static android.view.View.OnTouchListener? getDragToOpenListener(Object);
+ }
+
+ public final class PopupWindowCompat {
+ method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+ method public static int getWindowLayoutType(android.widget.PopupWindow);
+ method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+ method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+ method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+ }
+
+ @Deprecated public final class ScrollerCompat {
+ method @Deprecated public void abortAnimation();
+ method @Deprecated public boolean computeScrollOffset();
+ method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!);
+ method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!, android.view.animation.Interpolator!);
+ method @Deprecated public void fling(int, int, int, int, int, int, int, int);
+ method @Deprecated public void fling(int, int, int, int, int, int, int, int, int, int);
+ method @Deprecated public float getCurrVelocity();
+ method @Deprecated public int getCurrX();
+ method @Deprecated public int getCurrY();
+ method @Deprecated public int getFinalX();
+ method @Deprecated public int getFinalY();
+ method @Deprecated public boolean isFinished();
+ method @Deprecated public boolean isOverScrolled();
+ method @Deprecated public void notifyHorizontalEdgeReached(int, int, int);
+ method @Deprecated public void notifyVerticalEdgeReached(int, int, int);
+ method @Deprecated public boolean springBack(int, int, int, int, int, int);
+ method @Deprecated public void startScroll(int, int, int, int);
+ method @Deprecated public void startScroll(int, int, int, int, int);
+ }
+
+ public final class TextViewCompat {
+ method public static int getAutoSizeMaxTextSize(android.widget.TextView);
+ method public static int getAutoSizeMinTextSize(android.widget.TextView);
+ method public static int getAutoSizeStepGranularity(android.widget.TextView);
+ method public static int[] getAutoSizeTextAvailableSizes(android.widget.TextView);
+ method public static int getAutoSizeTextType(android.widget.TextView);
+ method public static android.content.res.ColorStateList? getCompoundDrawableTintList(android.widget.TextView);
+ method public static android.graphics.PorterDuff.Mode? getCompoundDrawableTintMode(android.widget.TextView);
+ method public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
+ method public static int getFirstBaselineToTopHeight(android.widget.TextView);
+ method public static int getLastBaselineToBottomHeight(android.widget.TextView);
+ method public static int getMaxLines(android.widget.TextView);
+ method public static int getMinLines(android.widget.TextView);
+ method public static androidx.core.text.PrecomputedTextCompat.Params getTextMetricsParams(android.widget.TextView);
+ method public static void setAutoSizeTextTypeUniformWithConfiguration(android.widget.TextView, int, int, int, int) throws java.lang.IllegalArgumentException;
+ method public static void setAutoSizeTextTypeUniformWithPresetSizes(android.widget.TextView, int[], int) throws java.lang.IllegalArgumentException;
+ method public static void setAutoSizeTextTypeWithDefaults(android.widget.TextView, int);
+ method public static void setCompoundDrawableTintList(android.widget.TextView, android.content.res.ColorStateList?);
+ method public static void setCompoundDrawableTintMode(android.widget.TextView, android.graphics.PorterDuff.Mode?);
+ method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+ method public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
+ method public static void setFirstBaselineToTopHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setLastBaselineToBottomHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setLineHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setPrecomputedText(android.widget.TextView, androidx.core.text.PrecomputedTextCompat);
+ method public static void setTextAppearance(android.widget.TextView, @StyleRes int);
+ method public static void setTextMetricsParams(android.widget.TextView, androidx.core.text.PrecomputedTextCompat.Params);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.view.ActionMode.Callback? unwrapCustomSelectionActionModeCallback(android.view.ActionMode.Callback?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.view.ActionMode.Callback? wrapCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback?);
+ field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
+ field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
+ }
+
+ @IntDef({androidx.core.widget.TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE, androidx.core.widget.TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface TextViewCompat.AutoSizeTextType {
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class TextViewOnReceiveContentListener implements androidx.core.view.OnReceiveContentListener {
+ ctor public TextViewOnReceiveContentListener();
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface TintableCheckedTextView {
+ method public android.content.res.ColorStateList? getSupportCheckMarkTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportCheckMarkTintMode();
+ method public void setSupportCheckMarkTintList(android.content.res.ColorStateList?);
+ method public void setSupportCheckMarkTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ public interface TintableCompoundButton {
+ method public android.content.res.ColorStateList? getSupportButtonTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportButtonTintMode();
+ method public void setSupportButtonTintList(android.content.res.ColorStateList?);
+ method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ public interface TintableCompoundDrawablesView {
+ method public android.content.res.ColorStateList? getSupportCompoundDrawablesTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportCompoundDrawablesTintMode();
+ method public void setSupportCompoundDrawablesTintList(android.content.res.ColorStateList?);
+ method public void setSupportCompoundDrawablesTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface TintableImageSourceView {
+ method public android.content.res.ColorStateList? getSupportImageTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportImageTintMode();
+ method public void setSupportImageTintList(android.content.res.ColorStateList?);
+ method public void setSupportImageTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+}
+
diff --git a/core/core/api/restricted_current.ignore b/core/core/api/restricted_current.ignore
deleted file mode 100644
index 3ff8fad..0000000
--- a/core/core/api/restricted_current.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-// Baseline format: 1.0
-InvalidNullConversion: androidx.core.app.PendingIntentCompat#getBroadcast(android.content.Context, int, android.content.Intent, int, boolean):
- Attempted to change method return from @NonNull to @Nullable: incompatible change for method androidx.core.app.PendingIntentCompat.getBroadcast(android.content.Context,int,android.content.Intent,int,boolean)
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 29edb7b..f02ce1a 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -1506,7 +1506,7 @@
package androidx.core.content.res {
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class CamColor {
- method public static void getM3HCTfromColor(@ColorInt int, float[]);
+ method public static void getM3HCTfromColor(@ColorInt int, @Size(3) float[]);
method public static int toColor(@FloatRange(from=0.0, to=360.0) float, @FloatRange(from=0.0, to=java.lang.Double.POSITIVE_INFINITY, toInclusive=false) float, @FloatRange(from=0.0, to=100.0) float);
}
@@ -1687,7 +1687,7 @@
method @ColorInt public static int HSLToColor(float[]);
method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
- method @ColorInt public static int M3HCTtoColor(float, float, float);
+ method @ColorInt public static int M3HCTToColor(@FloatRange(from=0.0, to=360, toInclusive=false) float, @FloatRange(from=0.0, to=java.lang.Double.POSITIVE_INFINITY, toInclusive=false) float, @FloatRange(from=0.0, to=100) float);
method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
@@ -1701,7 +1701,7 @@
method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
method public static void colorToHSL(@ColorInt int, float[]);
method public static void colorToLAB(@ColorInt int, double[]);
- method public static void colorToM3HCT(@ColorInt int, float[]);
+ method public static void colorToM3HCT(@ColorInt int, @Size(3) float[]);
method public static void colorToXYZ(@ColorInt int, double[]);
method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
method public static int compositeColors(@ColorInt int, @ColorInt int);
diff --git a/core/core/lint-baseline.xml b/core/core/lint-baseline.xml
index dc58fea..15bf316 100644
--- a/core/core/lint-baseline.xml
+++ b/core/core/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
+<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">
<issue
id="NewApi"
@@ -731,96 +731,6 @@
</issue>
<issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static int sizeAtStep(int srcSize, int dstSize, int step, int totalSteps) {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/graphics/BitmapCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected static boolean isAtLeastPreReleaseCodename(@NonNull String codename,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/os/BuildCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static void resetTypefaceCache() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/provider/FontsContractCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final class TvExtender implements Extender {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" static final String EXTRA_TV_EXTENDER = "android.tv.EXTENSIONS";"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" private static final String EXTRA_FLAGS = "flags";"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" static final String EXTRA_CONTENT_INTENT = "content_intent";"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" static final String EXTRA_DELETE_INTENT = "delete_intent";"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" static final String EXTRA_CHANNEL_ID = "channel_id";"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" static final String EXTRA_SUPPRESS_SHOW_OVER_APPS = "suppressShowOverApps";"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
id="BanThreadSleep"
message="Uses Thread.sleep()"
errorLine1=" Thread.sleep(timeSliceMs);"
diff --git a/core/core/src/androidTest/java/androidx/core/view/DragStartHelperTest.java b/core/core/src/androidTest/java/androidx/core/view/DragStartHelperTest.java
index b32fa94..0dfb788 100644
--- a/core/core/src/androidTest/java/androidx/core/view/DragStartHelperTest.java
+++ b/core/core/src/androidTest/java/androidx/core/view/DragStartHelperTest.java
@@ -375,4 +375,23 @@
eq(mDragSource), eq(helper), argThat(new TouchPositionMatcher(0, 0)));
verifyNoMoreInteractions(listener);
}
+
+ @LargeTest
+ @Test
+ public void mouseDragThenLongPress() throws Throwable {
+ final DragStartListener listener = createListener(true);
+ final DragStartHelper helper = createDragStartHelper(listener);
+ helper.attach();
+
+ sendMouseEvent(MotionEvent.ACTION_DOWN, MotionEvent.BUTTON_PRIMARY, mDragSource, 0, 0);
+ sendMouseEvent(MotionEvent.ACTION_MOVE, MotionEvent.BUTTON_PRIMARY, mDragSource, 1, 2);
+
+ verify(listener, times(1)).onDragStart(
+ eq(mDragSource), eq(helper), argThat(new TouchPositionMatcher(mDragSource, 1, 2)));
+
+ waitForLongPress();
+
+ // Long press doesn't triggers OnDragStart for a second time.
+ verifyNoMoreInteractions(listener);
+ }
}
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompat.java b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
index 8f7f1e3..36de5f08 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompat.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
@@ -8461,11 +8461,9 @@
public static final class TvExtender implements Extender {
private static final String TAG = "TvExtender";
- /** @hide **/
@RestrictTo(LIBRARY_GROUP_PREFIX)
static final String EXTRA_TV_EXTENDER = "android.tv.EXTENSIONS";
- /** @hide **/
@RestrictTo(LIBRARY_GROUP_PREFIX)
private static final String EXTRA_FLAGS = "flags";
diff --git a/core/core/src/main/java/androidx/core/content/res/CamColor.java b/core/core/src/main/java/androidx/core/content/res/CamColor.java
index 5aca7c5..9cd05c0 100644
--- a/core/core/src/main/java/androidx/core/content/res/CamColor.java
+++ b/core/core/src/main/java/androidx/core/content/res/CamColor.java
@@ -21,6 +21,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.annotation.Size;
import androidx.core.graphics.ColorUtils;
/**
@@ -170,6 +171,10 @@
*
* Get the values for M3HCT color from ARGB color.
*
+ * HCT color space is a new color space proposed in Material Design 3
+ * @see
+ * <a href="https://developer.android.com/design/ui/mobile/guides/styles/color#about-color-spaces">About Color Spaces</a>
+ *
*<ul>
*<li>outM3HCT[0] is Hue in M3HCT [0, 360); invalid values are corrected.</li>
*<li>outM3HCT[1] is Chroma in M3HCT [0, ?); Chroma may decrease because chroma has a
@@ -182,7 +187,7 @@
* Chroma, Tone).
*/
public static void getM3HCTfromColor(@ColorInt int color,
- @NonNull float[] outM3HCT) {
+ @NonNull @Size(3) float[] outM3HCT) {
fromColorInViewingConditions(color, ViewingConditions.DEFAULT, null, outM3HCT);
outM3HCT[2] = CamUtils.lStarFromInt(color);
}
@@ -192,8 +197,8 @@
* ViewingConditions in which the color was viewed. Prefer Cam.fromColor.
*/
static void fromColorInViewingConditions(@ColorInt int color,
- @NonNull ViewingConditions viewingConditions, @Nullable float[] outCamColor,
- @NonNull float[] outM3HCT) {
+ @NonNull ViewingConditions viewingConditions, @Nullable @Size(7) float[] outCamColor,
+ @NonNull @Size(3) float[] outM3HCT) {
// Transform ARGB int to XYZ, reusing outM3HCT array to avoid a new allocation.
CamUtils.xyzFromInt(color, outM3HCT);
float[] xyz = outM3HCT;
diff --git a/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java b/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java
index 8fb5cf5..d8b67a1 100644
--- a/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java
+++ b/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java
@@ -317,10 +317,9 @@
* Return the size that a scratch bitmap dimension (x or y) should be at a given step.
* When scaling up step counts down to zero from positive numbers.
* When scaling down, step counts up to zero from negative numbers.
- * @hide
*/
@VisibleForTesting
- public static int sizeAtStep(int srcSize, int dstSize, int step, int totalSteps) {
+ static int sizeAtStep(int srcSize, int dstSize, int step, int totalSteps) {
if (step == 0) {
return dstSize;
} else if (step > 0) { // upscale
diff --git a/core/core/src/main/java/androidx/core/graphics/ColorUtils.java b/core/core/src/main/java/androidx/core/graphics/ColorUtils.java
index b709487..7d26837 100644
--- a/core/core/src/main/java/androidx/core/graphics/ColorUtils.java
+++ b/core/core/src/main/java/androidx/core/graphics/ColorUtils.java
@@ -25,6 +25,7 @@
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
+import androidx.annotation.Size;
import androidx.annotation.VisibleForTesting;
import androidx.core.content.res.CamColor;
@@ -683,7 +684,11 @@
}
/**
- * Generate an ARGB color using M3HCT color parameters (Hue, Chroma, and Tone).
+ * Generate an ARGB color using M3HCT color parameters.
+ *
+ * HCT color space is a new color space proposed in Material Design 3
+ * @see
+ * <a href="https://developer.android.com/design/ui/mobile/guides/styles/color#about-color-spaces">About Color Spaces</a>
*
* @param hue is Hue in M3HCT [0, 360); invalid values are corrected.
* @param chroma is Chroma in M3HCT [0, ?); Chroma may decrease because chroma has a
@@ -692,13 +697,19 @@
*/
@SuppressWarnings("AcronymName")
@ColorInt
- public static int M3HCTtoColor(float hue, float chroma, float tone) {
+ public static int M3HCTToColor(@FloatRange(from = 0.0, to = 360, toInclusive = false) float hue,
+ @FloatRange(from = 0.0, to = Double.POSITIVE_INFINITY, toInclusive = false)
+ float chroma, @FloatRange(from = 0.0, to = 100) float tone) {
return CamColor.toColor(hue, chroma, tone);
}
/**
* Generate a M3HCT color from an ARGB color.
*
+ * HCT color space is a new color space proposed in Material Design 3
+ * @see
+ * <a href="https://developer.android.com/design/ui/mobile/guides/styles/color#about-color-spaces">About Color Spaces</a>
+ *
* <ul>
* <li>outM3HCT[0] is Hue in M3HCT [0, 360); invalid values are corrected.</li>
* <li>outM3HCT[1] is Chroma in M3HCT [0, ?); Chroma may decrease because chroma has a
@@ -711,7 +722,7 @@
* Tone).
*/
@SuppressWarnings("AcronymName")
- public static void colorToM3HCT(@ColorInt int color, @NonNull float[] outM3HCT) {
+ public static void colorToM3HCT(@ColorInt int color, @NonNull @Size(3) float[] outM3HCT) {
CamColor.getM3HCTfromColor(color, outM3HCT);
}
diff --git a/core/core/src/main/java/androidx/core/os/BuildCompat.java b/core/core/src/main/java/androidx/core/os/BuildCompat.java
index 4dfca8e..896db47 100644
--- a/core/core/src/main/java/androidx/core/os/BuildCompat.java
+++ b/core/core/src/main/java/androidx/core/os/BuildCompat.java
@@ -47,11 +47,9 @@
* @param buildCodename the value of {@link Build.VERSION#CODENAME}
*
* @return {@code true} if APIs from the requested codename are available in the build.
- *
- * @hide
*/
@VisibleForTesting
- protected static boolean isAtLeastPreReleaseCodename(@NonNull String codename,
+ static boolean isAtLeastPreReleaseCodename(@NonNull String codename,
@NonNull String buildCodename) {
// Special case "REL", which means the build is not a pre-release build.
diff --git a/core/core/src/main/java/androidx/core/provider/FontsContractCompat.java b/core/core/src/main/java/androidx/core/provider/FontsContractCompat.java
index 4f9487b..7d60696 100644
--- a/core/core/src/main/java/androidx/core/provider/FontsContractCompat.java
+++ b/core/core/src/main/java/androidx/core/provider/FontsContractCompat.java
@@ -169,7 +169,7 @@
}
}
- /** @hide */
+ @RestrictTo(LIBRARY)
@VisibleForTesting
public static void resetTypefaceCache() {
FontRequestWorker.resetTypefaceCache();
diff --git a/core/core/src/main/java/androidx/core/view/DragStartHelper.java b/core/core/src/main/java/androidx/core/view/DragStartHelper.java
index ed099dc..0c6db11 100644
--- a/core/core/src/main/java/androidx/core/view/DragStartHelper.java
+++ b/core/core/src/main/java/androidx/core/view/DragStartHelper.java
@@ -169,7 +169,12 @@
* @return true if the callback consumed the long click, false otherwise.
*/
public boolean onLongClick(@NonNull View v) {
- return mListener.onDragStart(v, this);
+ if (mDragging) {
+ // Ignore long click once the drag operation is in progress.
+ return true;
+ }
+ mDragging = mListener.onDragStart(v, this);
+ return mDragging;
}
/**
diff --git a/core/core/src/main/res/values-eu/strings.xml b/core/core/src/main/res/values-eu/strings.xml
index bbc7fae..18b6880 100644
--- a/core/core/src/main/res/values-eu/strings.xml
+++ b/core/core/src/main/res/values-eu/strings.xml
@@ -22,7 +22,7 @@
<string name="call_notification_answer_video_action" msgid="8793775615905189152">"Bideoa"</string>
<string name="call_notification_decline_action" msgid="3229508546291798546">"Baztertu"</string>
<string name="call_notification_hang_up_action" msgid="2659457946726154263">"Amaitu deia"</string>
- <string name="call_notification_incoming_text" msgid="6107532579223922871">"Jasotako deia"</string>
+ <string name="call_notification_incoming_text" msgid="6107532579223922871">"Sarrerako deia"</string>
<string name="call_notification_ongoing_text" msgid="8623827134497363134">"Deia abian da"</string>
- <string name="call_notification_screening_text" msgid="59049573811482460">"Jasotako dei bat bistaratzen"</string>
+ <string name="call_notification_screening_text" msgid="59049573811482460">"Sarrerako dei bat bistaratzen"</string>
</resources>
diff --git a/core/core/src/main/stableAidl/android/support/v4/app/INotificationSideChannel.aidl b/core/core/src/main/stableAidl/android/support/v4/app/INotificationSideChannel.aidl
index dae811d..9deddf2 100644
--- a/core/core/src/main/stableAidl/android/support/v4/app/INotificationSideChannel.aidl
+++ b/core/core/src/main/stableAidl/android/support/v4/app/INotificationSideChannel.aidl
@@ -21,9 +21,8 @@
/**
* Interface used for delivering notifications via a side channel that bypasses
* the NotificationManagerService.
- *
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
oneway interface INotificationSideChannel {
/**
* Send an ambient notification to the service.
diff --git a/core/core/src/main/stableAidl/android/support/v4/os/IResultReceiver.aidl b/core/core/src/main/stableAidl/android/support/v4/os/IResultReceiver.aidl
index f31d6ae..722f199 100644
--- a/core/core/src/main/stableAidl/android/support/v4/os/IResultReceiver.aidl
+++ b/core/core/src/main/stableAidl/android/support/v4/os/IResultReceiver.aidl
@@ -18,7 +18,7 @@
import android.os.Bundle;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
oneway interface IResultReceiver {
void send(int resultCode, in Bundle resultData);
}
diff --git a/core/core/src/main/stableAidl/android/support/v4/os/IResultReceiver2.aidl b/core/core/src/main/stableAidl/android/support/v4/os/IResultReceiver2.aidl
index 19914e7..2e7550f 100644
--- a/core/core/src/main/stableAidl/android/support/v4/os/IResultReceiver2.aidl
+++ b/core/core/src/main/stableAidl/android/support/v4/os/IResultReceiver2.aidl
@@ -18,7 +18,7 @@
import android.os.Bundle;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
oneway interface IResultReceiver2 {
void send(int resultCode, in Bundle resultData);
}
diff --git a/core/core/src/main/stableAidl/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportCallback.aidl b/core/core/src/main/stableAidl/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportCallback.aidl
index f927a8e..e92c93a 100644
--- a/core/core/src/main/stableAidl/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportCallback.aidl
+++ b/core/core/src/main/stableAidl/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportCallback.aidl
@@ -16,7 +16,7 @@
package androidx.core.app.unusedapprestrictions;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IUnusedAppRestrictionsBackportCallback {
/**
diff --git a/core/core/src/main/stableAidl/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportService.aidl b/core/core/src/main/stableAidl/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportService.aidl
index 8e62742..266d6d3 100644
--- a/core/core/src/main/stableAidl/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportService.aidl
+++ b/core/core/src/main/stableAidl/androidx/core/app/unusedapprestrictions/IUnusedAppRestrictionsBackportService.aidl
@@ -18,7 +18,7 @@
import androidx.core.app.unusedapprestrictions.IUnusedAppRestrictionsBackportCallback;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IUnusedAppRestrictionsBackportService {
/**
diff --git a/core/haptics/OWNERS b/core/haptics/OWNERS
new file mode 100644
index 0000000..86e9f3c
--- /dev/null
+++ b/core/haptics/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 1369717
+lsandrade@google.com
+sbowden@google.com
+khalilahmad@google.com
+michaelwr@google.com
\ No newline at end of file
diff --git a/core/haptics/haptics/api/current.txt b/core/haptics/haptics/api/current.txt
new file mode 100644
index 0000000..fb8d5b9
--- /dev/null
+++ b/core/haptics/haptics/api/current.txt
@@ -0,0 +1,30 @@
+// Signature format: 4.0
+package androidx.core.haptics {
+
+ public interface HapticManager {
+ method public default static androidx.core.haptics.HapticManager create(android.content.Context context);
+ method @RequiresPermission(android.Manifest.permission.VIBRATE) public void play(androidx.core.haptics.signal.PredefinedEffect effect);
+ field public static final androidx.core.haptics.HapticManager.Companion Companion;
+ }
+
+ public static final class HapticManager.Companion {
+ method public androidx.core.haptics.HapticManager create(android.content.Context context);
+ }
+
+}
+
+package androidx.core.haptics.signal {
+
+ public final class PredefinedEffect {
+ field public static final androidx.core.haptics.signal.PredefinedEffect.Companion Companion;
+ field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedClick;
+ field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedDoubleClick;
+ field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedHeavyClick;
+ field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedTick;
+ }
+
+ public static final class PredefinedEffect.Companion {
+ }
+
+}
+
diff --git a/core/haptics/haptics/api/res-current.txt b/core/haptics/haptics/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/haptics/haptics/api/res-current.txt
diff --git a/core/haptics/haptics/api/restricted_current.txt b/core/haptics/haptics/api/restricted_current.txt
new file mode 100644
index 0000000..fb8d5b9
--- /dev/null
+++ b/core/haptics/haptics/api/restricted_current.txt
@@ -0,0 +1,30 @@
+// Signature format: 4.0
+package androidx.core.haptics {
+
+ public interface HapticManager {
+ method public default static androidx.core.haptics.HapticManager create(android.content.Context context);
+ method @RequiresPermission(android.Manifest.permission.VIBRATE) public void play(androidx.core.haptics.signal.PredefinedEffect effect);
+ field public static final androidx.core.haptics.HapticManager.Companion Companion;
+ }
+
+ public static final class HapticManager.Companion {
+ method public androidx.core.haptics.HapticManager create(android.content.Context context);
+ }
+
+}
+
+package androidx.core.haptics.signal {
+
+ public final class PredefinedEffect {
+ field public static final androidx.core.haptics.signal.PredefinedEffect.Companion Companion;
+ field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedClick;
+ field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedDoubleClick;
+ field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedHeavyClick;
+ field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedTick;
+ }
+
+ public static final class PredefinedEffect.Companion {
+ }
+
+}
+
diff --git a/core/haptics/haptics/build.gradle b/core/haptics/haptics/build.gradle
new file mode 100644
index 0000000..eb4448c
--- /dev/null
+++ b/core/haptics/haptics/build.gradle
@@ -0,0 +1,50 @@
+/*
+ * 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 androidx.build.LibraryType
+import androidx.build.RunApiTasks
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+ id("kotlin-android")
+}
+
+dependencies {
+ api(libs.kotlinStdlib)
+
+ implementation(projectOrArtifact(":annotation:annotation"))
+ implementation(projectOrArtifact(":core:core"))
+ samples(project(":core:haptics:haptics-samples"))
+
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.mockitoCore4)
+ androidTestImplementation(libs.dexmakerMockitoInline)
+}
+
+android {
+ namespace "androidx.core.haptics"
+}
+
+androidx {
+ name = "AndroidX Core Haptics"
+ type = LibraryType.PUBLISHED_LIBRARY
+ inceptionYear = "2023"
+ description = "Core Haptics Libraries to help navigate different device and Android SDK " +
+ "functionalities and create reliable haptic effects across all of Android."
+}
diff --git a/core/haptics/haptics/integration-tests/demos/build.gradle b/core/haptics/haptics/integration-tests/demos/build.gradle
new file mode 100644
index 0000000..3bf7a05
--- /dev/null
+++ b/core/haptics/haptics/integration-tests/demos/build.gradle
@@ -0,0 +1,37 @@
+/*
+ * 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 {
+ implementation(libs.kotlinStdlib)
+
+ implementation(project(":appcompat:appcompat"))
+ implementation(project(":core:haptics:haptics"))
+}
+
+android {
+ defaultConfig {
+ applicationId "androidx.core.haptics.demos"
+ minSdkVersion 19
+ multiDexEnabled true
+ }
+ namespace "androidx.core.haptics.demos"
+}
diff --git a/core/haptics/haptics/integration-tests/demos/src/main/AndroidManifest.xml b/core/haptics/haptics/integration-tests/demos/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..4c19b57
--- /dev/null
+++ b/core/haptics/haptics/integration-tests/demos/src/main/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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">
+ <uses-permission android:name="android.permission.VIBRATE" />
+ <application
+ android:allowBackup="false"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+ <activity
+ android:allowBackup="false"
+ android:name=".HapticSamplesActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/core/haptics/haptics/integration-tests/demos/src/main/java/androidx/core/haptics/demos/HapticSamplesActivity.kt b/core/haptics/haptics/integration-tests/demos/src/main/java/androidx/core/haptics/demos/HapticSamplesActivity.kt
new file mode 100644
index 0000000..5fb1076
--- /dev/null
+++ b/core/haptics/haptics/integration-tests/demos/src/main/java/androidx/core/haptics/demos/HapticSamplesActivity.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.haptics.demos
+
+import android.os.Bundle
+import android.widget.Button
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.haptics.HapticManager
+import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedClick
+
+/**
+ * Demo with multiple selection of haptic effect samples.
+ */
+class HapticSamplesActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.haptic_samples_activity)
+
+ val hapticManager = HapticManager.create(this)
+ findViewById<Button>(R.id.standard_click_btn).setOnClickListener {
+ hapticManager.play(PredefinedClick)
+ }
+ }
+}
diff --git a/core/haptics/haptics/integration-tests/demos/src/main/res/layout/haptic_samples_activity.xml b/core/haptics/haptics/integration-tests/demos/src/main/res/layout/haptic_samples_activity.xml
new file mode 100644
index 0000000..24002ee
--- /dev/null
+++ b/core/haptics/haptics/integration-tests/demos/src/main/res/layout/haptic_samples_activity.xml
@@ -0,0 +1,31 @@
+<?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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ tools:context="androidx.core.haptics.demos.HapticSamplesActivity">
+
+ <Button
+ android:id="@+id/standard_click_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/standard_click" />
+
+</LinearLayout>
diff --git a/core/haptics/haptics/integration-tests/demos/src/main/res/values/donottranslate-strings.xml b/core/haptics/haptics/integration-tests/demos/src/main/res/values/donottranslate-strings.xml
new file mode 100644
index 0000000..903a0be
--- /dev/null
+++ b/core/haptics/haptics/integration-tests/demos/src/main/res/values/donottranslate-strings.xml
@@ -0,0 +1,20 @@
+<?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.
+ -->
+<resources>
+ <string name="app_name">Haptic Demos</string>
+ <string name="standard_click">Standard Click</string>
+</resources>
diff --git a/core/haptics/haptics/integration-tests/demos/src/main/res/values/style.xml b/core/haptics/haptics/integration-tests/demos/src/main/res/values/style.xml
new file mode 100644
index 0000000..e3680c8
--- /dev/null
+++ b/core/haptics/haptics/integration-tests/demos/src/main/res/values/style.xml
@@ -0,0 +1,19 @@
+<?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.
+ -->
+<resources>
+ <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"/>
+</resources>
diff --git a/core/haptics/haptics/samples/build.gradle b/core/haptics/haptics/samples/build.gradle
new file mode 100644
index 0000000..2f6769e
--- /dev/null
+++ b/core/haptics/haptics/samples/build.gradle
@@ -0,0 +1,35 @@
+/*
+ * 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 androidx.build.LibraryType
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+dependencies {
+ api(libs.kotlinStdlib)
+ compileOnly(project(":annotation:annotation-sampled"))
+ implementation(project(":core:haptics:haptics"))
+}
+android {
+ namespace "androidx.core.haptics.samples"
+}
+androidx {
+ name = "AndroidX Core Haptics Samples"
+ type = LibraryType.SAMPLES
+ inceptionYear = "2023"
+ description = "Samples for the AndroidX Core Haptics Libraries"
+}
diff --git a/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/HapticManagerSamples.kt b/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/HapticManagerSamples.kt
new file mode 100644
index 0000000..e1d3df4
--- /dev/null
+++ b/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/HapticManagerSamples.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.
+ */
+
+package androidx.core.haptics.samples
+
+import android.content.Context
+import androidx.annotation.Sampled
+import androidx.core.haptics.HapticManager
+import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedClick
+
+/**
+ * Sample showing how to play a standard click haptic effect on the system vibrator.
+ */
+@Sampled
+fun PlaySystemStandardClick(context: Context) {
+ val hapticManager = HapticManager.create(context)
+ hapticManager.play(PredefinedClick)
+}
diff --git a/core/haptics/haptics/src/androidTest/AndroidManifest.xml b/core/haptics/haptics/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..d6eba8b
--- /dev/null
+++ b/core/haptics/haptics/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?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">
+ <uses-permission android:name="android.permission.VIBRATE" />
+</manifest>
diff --git a/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayPredefinedEffectTest.kt b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayPredefinedEffectTest.kt
new file mode 100644
index 0000000..fab916e
--- /dev/null
+++ b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayPredefinedEffectTest.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.haptics
+
+import android.os.Build
+import android.os.VibrationEffect
+import android.os.Vibrator
+import androidx.core.haptics.signal.PredefinedEffect
+import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedClick
+import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedDoubleClick
+import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedHeavyClick
+import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedTick
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+
+@RunWith(Parameterized::class)
+@SmallTest
+class PlayPredefinedEffectTest(
+ private val effect: PredefinedEffect,
+ private val expectedFallbackPattern: LongArray,
+) {
+ // Vibrator has package-protected constructor and cannot be extended by a FakeVibrator
+ // TODO(b/275084444): replace with a testable interface to allow all SDK levels
+ private val vibrator = mock(Vibrator::class.java)
+ private val hapticManager = HapticManager.createForVibrator(vibrator)
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
+ @Test
+ fun perform_api29AndAbove() {
+ hapticManager.play(effect)
+ verify(vibrator).vibrate(eq(VibrationEffect.createPredefined(effect.effectId)))
+ }
+
+ @Suppress("DEPRECATION") // Verifying deprecated APIs are triggered by this test
+ @SdkSuppress(
+ minSdkVersion = 28, // TODO(b/275084444): remove this once we introduce fake vibrator
+ maxSdkVersion = Build.VERSION_CODES.P
+ )
+ @Test
+ fun perform_belowApi29() {
+ hapticManager.play(effect)
+ verify(vibrator).vibrate(eq(expectedFallbackPattern), eq(-1))
+ }
+
+ companion object {
+
+ @JvmStatic
+ @Parameterized.Parameters(name = "effect:{0}, expectedFallbackPattern:{1}")
+ fun data(): Collection<Array<Any>> = listOf(
+ arrayOf(PredefinedTick, longArrayOf(0, 10)),
+ arrayOf(PredefinedClick, longArrayOf(0, 20)),
+ arrayOf(PredefinedHeavyClick, longArrayOf(0, 30)),
+ arrayOf(PredefinedDoubleClick, longArrayOf(0, 30, 100, 30)),
+ )
+ }
+}
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/HapticManager.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/HapticManager.kt
new file mode 100644
index 0000000..1ca0bd0
--- /dev/null
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/HapticManager.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.haptics
+
+import android.content.Context
+import android.os.Vibrator
+import androidx.annotation.RequiresPermission
+import androidx.core.haptics.impl.HapticManagerImpl
+import androidx.core.haptics.signal.PredefinedEffect
+
+/**
+ * Manager for the vibrators of a device.
+ *
+ * <p>If your process exits, any vibration you started will stop.
+ */
+interface HapticManager {
+
+ companion object {
+
+ /**
+ * Creates haptic manager for the system vibrators.
+ *
+ * Sample code:
+ * @sample androidx.core.haptics.samples.PlaySystemStandardClick
+ *
+ * @param context Context to load the device vibrators.
+ * @return a new instance of HapticManager for the system vibrators.
+ */
+ @JvmStatic
+ fun create(context: Context): HapticManager {
+ return HapticManagerImpl(context)
+ }
+
+ /** Creates haptic manager for given vibrator. */
+ internal fun createForVibrator(vibrator: Vibrator): HapticManager {
+ return HapticManagerImpl(vibrator)
+ }
+ }
+
+ /**
+ * Play a [PredefinedEffect].
+ *
+ * The app should be in the foreground for the vibration to happen.
+ *
+ * Sample code:
+ * @sample androidx.core.haptics.samples.PlaySystemStandardClick
+ *
+ * @param effect The predefined haptic effect to be played.
+ */
+ @RequiresPermission(android.Manifest.permission.VIBRATE)
+ fun play(effect: PredefinedEffect)
+}
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/androidx-core-haptics-haptics-documentation.md b/core/haptics/haptics/src/main/java/androidx/core/haptics/androidx-core-haptics-haptics-documentation.md
new file mode 100644
index 0000000..96e7a26
--- /dev/null
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/androidx-core-haptics-haptics-documentation.md
@@ -0,0 +1,8 @@
+# Module root
+
+AndroidX Core Haptics
+
+# Package androidx.core.haptics
+
+Core Haptics Libraries to help navigate different device and Android SDK functionalities and create
+reliable haptic effects across all of Android.
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/HapticManagerImpl.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/HapticManagerImpl.kt
new file mode 100644
index 0000000..a5c518c
--- /dev/null
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/HapticManagerImpl.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.core.haptics.impl
+
+import android.content.Context
+import android.os.Build.VERSION
+import android.os.VibrationEffect
+import android.os.Vibrator
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.annotation.RequiresPermission
+import androidx.core.content.ContextCompat
+import androidx.core.haptics.HapticManager
+import androidx.core.haptics.signal.PredefinedEffect
+import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedClick
+import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedDoubleClick
+import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedHeavyClick
+import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedTick
+
+/**
+ * [HapticManager] implementation for the [Vibrator] service.
+ */
+internal class HapticManagerImpl internal constructor(
+ private val vibrator: Vibrator
+) : HapticManager {
+
+ internal constructor(context: Context) : this(
+ requireNotNull(ContextCompat.getSystemService(context, Vibrator::class.java)) {
+ "Vibrator service not found"
+ }
+ )
+
+ @RequiresPermission(android.Manifest.permission.VIBRATE)
+ override fun play(effect: PredefinedEffect) {
+ if (VERSION.SDK_INT >= 29) {
+ Api29Impl.play(vibrator, effect)
+ } else {
+ ApiImpl.play(vibrator, effect)
+ }
+ }
+
+ /** Version-specific static inner class. */
+ @RequiresApi(29)
+ private object Api29Impl {
+
+ @JvmStatic
+ @DoNotInline
+ @RequiresPermission(android.Manifest.permission.VIBRATE)
+ fun play(vibrator: Vibrator, effect: PredefinedEffect) {
+ vibrator.vibrate(VibrationEffect.createPredefined(effect.effectId))
+ }
+ }
+
+ /** Version-specific static inner class. */
+ private object ApiImpl {
+
+ private val predefinedEffectFallbackPatterns = mapOf(
+ PredefinedTick to longArrayOf(0, 10),
+ PredefinedClick to longArrayOf(0, 20),
+ PredefinedHeavyClick to longArrayOf(0, 30),
+ PredefinedDoubleClick to longArrayOf(0, 30, 100, 30)
+ )
+
+ @JvmStatic
+ @Suppress("DEPRECATION") // ApkVariant for compatibility
+ @RequiresPermission(android.Manifest.permission.VIBRATE)
+ fun play(vibrator: Vibrator, effect: PredefinedEffect) {
+ predefinedEffectFallbackPatterns[effect]?.let {
+ vibrator.vibrate(/* pattern= */ it, /* repeat= */ -1)
+ }
+ }
+ }
+}
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/PredefinedEffect.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/PredefinedEffect.kt
new file mode 100644
index 0000000..abe1b89
--- /dev/null
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/PredefinedEffect.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.haptics.signal
+
+/**
+ * A [PredefinedEffect] describes a haptic effect to be played by a vibrator.
+ *
+ * Predefined effects represent common vibration effects that should be identical, regardless of
+ * the app they come from, in order to provide a cohesive experience for users across the entire
+ * device.
+ *
+ * They also may be custom tailored to the device hardware in order to provide a better
+ * experience than you could otherwise build using the generic building blocks.
+ *
+ * This will fallback to a generic pattern if one exists and there is no hardware-specific
+ * implementation of the effect available.
+ */
+class PredefinedEffect private constructor(
+
+ /** The id of the effect to be played. */
+ internal val effectId: Int
+) {
+
+ companion object {
+
+ /**
+ * A standard tick effect.
+ *
+ * This effect is less strong than the [PredefinedClick].
+ */
+ @JvmField
+ val PredefinedTick = PredefinedEffect(2) // VibrationEffect.EFFECT_TICK
+
+ /**
+ * A standard click effect.
+ *
+ * Use this effect as a baseline, as it's the most common type of click effect.
+ */
+ @JvmField
+ val PredefinedClick = PredefinedEffect(0) // VibrationEffect.EFFECT_CLICK
+
+ /**
+ * A heavy click effect.
+ *
+ * This effect is stronger than the [PredefinedClick].
+ */
+ @JvmField
+ val PredefinedHeavyClick = PredefinedEffect(5) // VibrationEffect.EFFECT_HEAVY_CLICK
+
+ /**
+ * A double-click effect.
+ */
+ @JvmField
+ val PredefinedDoubleClick = PredefinedEffect(1) // VibrationEffect.EFFECT_DOUBLE_CLICK
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is PredefinedEffect) return false
+ if (effectId != other.effectId) return false
+ return true
+ }
+
+ override fun hashCode(): Int {
+ return effectId.hashCode()
+ }
+}
diff --git a/core/settings.gradle b/core/settings.gradle
index ffa5f61..40cad8b 100644
--- a/core/settings.gradle
+++ b/core/settings.gradle
@@ -11,6 +11,7 @@
playground {
setupPlayground("..")
selectProjectsFromAndroidX({ name ->
+ if (name.contains("haptics")) return false // b/285039694
if (name.startsWith(":core")) return true
if (name == ":internal-testutils-mockito") return true
if (name == ":internal-testutils-fonts") return true
diff --git a/core/uwb/uwb-rxjava3/src/androidTest/java/androidx/core/uwb/rxjava3/UwbClientSessionScopeRxTest.java b/core/uwb/uwb-rxjava3/src/androidTest/java/androidx/core/uwb/rxjava3/UwbClientSessionScopeRxTest.java
index e8e3295..fd97fa6 100644
--- a/core/uwb/uwb-rxjava3/src/androidTest/java/androidx/core/uwb/rxjava3/UwbClientSessionScopeRxTest.java
+++ b/core/uwb/uwb-rxjava3/src/androidTest/java/androidx/core/uwb/rxjava3/UwbClientSessionScopeRxTest.java
@@ -41,7 +41,9 @@
private final RangingParameters rangingParameters = new RangingParameters(
RangingParameters.CONFIG_UNICAST_DS_TWR,
0,
+ 0,
/*sessionKeyInfo=*/ null,
+ /*subSessionKeyInfo=*/ null,
/*complexChannel=*/ null,
ImmutableList.of(UWB_DEVICE),
RangingParameters.RANGING_UPDATE_RATE_AUTOMATIC
diff --git a/core/uwb/uwb-rxjava3/src/androidTest/java/androidx/core/uwb/rxjava3/mock/TestUwbClientSessionScope.kt b/core/uwb/uwb-rxjava3/src/androidTest/java/androidx/core/uwb/rxjava3/mock/TestUwbClientSessionScope.kt
index 6c2a4fb..76eeebb 100644
--- a/core/uwb/uwb-rxjava3/src/androidTest/java/androidx/core/uwb/rxjava3/mock/TestUwbClientSessionScope.kt
+++ b/core/uwb/uwb-rxjava3/src/androidTest/java/androidx/core/uwb/rxjava3/mock/TestUwbClientSessionScope.kt
@@ -42,6 +42,8 @@
val defaultRangingParameters = RangingParameters(
RangingParameters.CONFIG_UNICAST_DS_TWR,
0,
+ 0,
+ null,
null,
null,
ImmutableList.of(uwbDevice),
diff --git a/core/uwb/uwb/api/current.txt b/core/uwb/uwb/api/current.txt
index 569a8ef..269bf8e 100644
--- a/core/uwb/uwb/api/current.txt
+++ b/core/uwb/uwb/api/current.txt
@@ -24,25 +24,32 @@
}
public final class RangingParameters {
- ctor public RangingParameters(int uwbConfigType, int sessionId, byte[]? sessionKeyInfo, androidx.core.uwb.UwbComplexChannel? complexChannel, java.util.List<androidx.core.uwb.UwbDevice> peerDevices, int updateRateType);
+ ctor public RangingParameters(int uwbConfigType, int sessionId, int subSessionId, byte[]? sessionKeyInfo, byte[]? subSessionKeyInfo, androidx.core.uwb.UwbComplexChannel? complexChannel, java.util.List<androidx.core.uwb.UwbDevice> peerDevices, int updateRateType);
method public androidx.core.uwb.UwbComplexChannel? getComplexChannel();
method public java.util.List<androidx.core.uwb.UwbDevice> getPeerDevices();
method public int getSessionId();
method public byte[]? getSessionKeyInfo();
+ method public int getSubSessionId();
+ method public byte[]? getSubSessionKeyInfo();
method public int getUpdateRateType();
method public int getUwbConfigType();
property public final androidx.core.uwb.UwbComplexChannel? complexChannel;
property public final java.util.List<androidx.core.uwb.UwbDevice> peerDevices;
property public final int sessionId;
property public final byte[]? sessionKeyInfo;
+ property public final int subSessionId;
+ property public final byte[]? subSessionKeyInfo;
property public final int updateRateType;
property public final int uwbConfigType;
- field public static final int CONFIG_MULTICAST_DS_TWR;
- field public static final int CONFIG_UNICAST_DS_TWR;
+ field public static final int CONFIG_MULTICAST_DS_TWR = 2; // 0x2
+ field public static final int CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR = 7; // 0x7
+ field public static final int CONFIG_PROVISIONED_MULTICAST_DS_TWR = 5; // 0x5
+ field public static final int CONFIG_PROVISIONED_UNICAST_DS_TWR = 4; // 0x4
+ field public static final int CONFIG_UNICAST_DS_TWR = 1; // 0x1
field public static final androidx.core.uwb.RangingParameters.Companion Companion;
- field public static final int RANGING_UPDATE_RATE_AUTOMATIC;
- field public static final int RANGING_UPDATE_RATE_FREQUENT;
- field public static final int RANGING_UPDATE_RATE_INFREQUENT;
+ field public static final int RANGING_UPDATE_RATE_AUTOMATIC = 1; // 0x1
+ field public static final int RANGING_UPDATE_RATE_FREQUENT = 3; // 0x3
+ field public static final int RANGING_UPDATE_RATE_INFREQUENT = 2; // 0x2
}
public static final class RangingParameters.Companion {
diff --git a/core/uwb/uwb/api/public_plus_experimental_current.txt b/core/uwb/uwb/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..6df94fe
--- /dev/null
+++ b/core/uwb/uwb/api/public_plus_experimental_current.txt
@@ -0,0 +1,173 @@
+// Signature format: 4.0
+package androidx.core.uwb {
+
+ public final class RangingCapabilities {
+ ctor public RangingCapabilities(boolean isDistanceSupported, boolean isAzimuthalAngleSupported, boolean isElevationAngleSupported, int minRangingInterval, java.util.Set<java.lang.Integer> supportedChannels, java.util.Set<java.lang.Integer> supportedConfigIds);
+ method public int getMinRangingInterval();
+ method public java.util.Set<java.lang.Integer> getSupportedChannels();
+ method public java.util.Set<java.lang.Integer> getSupportedConfigIds();
+ method public boolean isAzimuthalAngleSupported();
+ method public boolean isDistanceSupported();
+ method public boolean isElevationAngleSupported();
+ property public final boolean isAzimuthalAngleSupported;
+ property public final boolean isDistanceSupported;
+ property public final boolean isElevationAngleSupported;
+ property public final int minRangingInterval;
+ property public final java.util.Set<java.lang.Integer> supportedChannels;
+ property public final java.util.Set<java.lang.Integer> supportedConfigIds;
+ }
+
+ public final class RangingMeasurement {
+ ctor public RangingMeasurement(float value);
+ method public float getValue();
+ property public final float value;
+ }
+
+ public final class RangingParameters {
+ ctor public RangingParameters(int uwbConfigType, int sessionId, int subSessionId, byte[]? sessionKeyInfo, byte[]? subSessionKeyInfo, androidx.core.uwb.UwbComplexChannel? complexChannel, java.util.List<androidx.core.uwb.UwbDevice> peerDevices, int updateRateType);
+ method public androidx.core.uwb.UwbComplexChannel? getComplexChannel();
+ method public java.util.List<androidx.core.uwb.UwbDevice> getPeerDevices();
+ method public int getSessionId();
+ method public byte[]? getSessionKeyInfo();
+ method public int getSubSessionId();
+ method public byte[]? getSubSessionKeyInfo();
+ method public int getUpdateRateType();
+ method public int getUwbConfigType();
+ property public final androidx.core.uwb.UwbComplexChannel? complexChannel;
+ property public final java.util.List<androidx.core.uwb.UwbDevice> peerDevices;
+ property public final int sessionId;
+ property public final byte[]? sessionKeyInfo;
+ property public final int subSessionId;
+ property public final byte[]? subSessionKeyInfo;
+ property public final int updateRateType;
+ property public final int uwbConfigType;
+ field public static final int CONFIG_MULTICAST_DS_TWR = 2; // 0x2
+ field public static final int CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR = 7; // 0x7
+ field public static final int CONFIG_PROVISIONED_MULTICAST_DS_TWR = 5; // 0x5
+ field public static final int CONFIG_PROVISIONED_UNICAST_DS_TWR = 4; // 0x4
+ field public static final int CONFIG_UNICAST_DS_TWR = 1; // 0x1
+ field public static final androidx.core.uwb.RangingParameters.Companion Companion;
+ field public static final int RANGING_UPDATE_RATE_AUTOMATIC = 1; // 0x1
+ field public static final int RANGING_UPDATE_RATE_FREQUENT = 3; // 0x3
+ field public static final int RANGING_UPDATE_RATE_INFREQUENT = 2; // 0x2
+ }
+
+ public static final class RangingParameters.Companion {
+ }
+
+ public final class RangingPosition {
+ ctor public RangingPosition(androidx.core.uwb.RangingMeasurement? distance, androidx.core.uwb.RangingMeasurement? azimuth, androidx.core.uwb.RangingMeasurement? elevation, long elapsedRealtimeNanos);
+ method public androidx.core.uwb.RangingMeasurement? getAzimuth();
+ method public androidx.core.uwb.RangingMeasurement? getDistance();
+ method public long getElapsedRealtimeNanos();
+ method public androidx.core.uwb.RangingMeasurement? getElevation();
+ property public final androidx.core.uwb.RangingMeasurement? azimuth;
+ property public final androidx.core.uwb.RangingMeasurement? distance;
+ property public final long elapsedRealtimeNanos;
+ property public final androidx.core.uwb.RangingMeasurement? elevation;
+ }
+
+ public abstract class RangingResult {
+ method public abstract androidx.core.uwb.UwbDevice getDevice();
+ property public abstract androidx.core.uwb.UwbDevice device;
+ }
+
+ public static final class RangingResult.RangingResultPeerDisconnected extends androidx.core.uwb.RangingResult {
+ ctor public RangingResult.RangingResultPeerDisconnected(androidx.core.uwb.UwbDevice device);
+ method public androidx.core.uwb.UwbDevice getDevice();
+ property public androidx.core.uwb.UwbDevice device;
+ }
+
+ public static final class RangingResult.RangingResultPosition extends androidx.core.uwb.RangingResult {
+ ctor public RangingResult.RangingResultPosition(androidx.core.uwb.UwbDevice device, androidx.core.uwb.RangingPosition position);
+ method public androidx.core.uwb.UwbDevice getDevice();
+ method public androidx.core.uwb.RangingPosition getPosition();
+ property public androidx.core.uwb.UwbDevice device;
+ property public final androidx.core.uwb.RangingPosition position;
+ }
+
+ public final class UwbAddress {
+ ctor public UwbAddress(byte[] address);
+ ctor public UwbAddress(String address);
+ method public byte[] getAddress();
+ property public final byte[] address;
+ field public static final androidx.core.uwb.UwbAddress.Companion Companion;
+ }
+
+ public static final class UwbAddress.Companion {
+ }
+
+ public interface UwbClientSessionScope {
+ method public androidx.core.uwb.UwbAddress getLocalAddress();
+ method public androidx.core.uwb.RangingCapabilities getRangingCapabilities();
+ method public kotlinx.coroutines.flow.Flow<androidx.core.uwb.RangingResult> prepareSession(androidx.core.uwb.RangingParameters parameters);
+ property public abstract androidx.core.uwb.UwbAddress localAddress;
+ property public abstract androidx.core.uwb.RangingCapabilities rangingCapabilities;
+ }
+
+ public final class UwbComplexChannel {
+ ctor public UwbComplexChannel(int channel, int preambleIndex);
+ method public int getChannel();
+ method public int getPreambleIndex();
+ property public final int channel;
+ property public final int preambleIndex;
+ }
+
+ public interface UwbControleeSessionScope extends androidx.core.uwb.UwbClientSessionScope {
+ }
+
+ public interface UwbControllerSessionScope extends androidx.core.uwb.UwbClientSessionScope {
+ method public suspend Object? addControlee(androidx.core.uwb.UwbAddress address, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public androidx.core.uwb.UwbComplexChannel getUwbComplexChannel();
+ method public suspend Object? removeControlee(androidx.core.uwb.UwbAddress address, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public abstract androidx.core.uwb.UwbComplexChannel uwbComplexChannel;
+ }
+
+ public final class UwbDevice {
+ ctor public UwbDevice(androidx.core.uwb.UwbAddress address);
+ method public static androidx.core.uwb.UwbDevice createForAddress(String address);
+ method public static androidx.core.uwb.UwbDevice createForAddress(byte[] address);
+ method public androidx.core.uwb.UwbAddress getAddress();
+ property public final androidx.core.uwb.UwbAddress address;
+ field public static final androidx.core.uwb.UwbDevice.Companion Companion;
+ }
+
+ public static final class UwbDevice.Companion {
+ method public androidx.core.uwb.UwbDevice createForAddress(String address);
+ method public androidx.core.uwb.UwbDevice createForAddress(byte[] address);
+ }
+
+ @kotlin.jvm.JvmDefaultWithCompatibility public interface UwbManager {
+ method @Deprecated public suspend Object? clientSessionScope(kotlin.coroutines.Continuation<? super androidx.core.uwb.UwbClientSessionScope>);
+ method public suspend Object? controleeSessionScope(kotlin.coroutines.Continuation<? super androidx.core.uwb.UwbControleeSessionScope>);
+ method public suspend Object? controllerSessionScope(kotlin.coroutines.Continuation<? super androidx.core.uwb.UwbControllerSessionScope>);
+ method public default static androidx.core.uwb.UwbManager createInstance(android.content.Context context);
+ field public static final androidx.core.uwb.UwbManager.Companion Companion;
+ }
+
+ public static final class UwbManager.Companion {
+ method public androidx.core.uwb.UwbManager createInstance(android.content.Context context);
+ }
+
+}
+
+package androidx.core.uwb.exceptions {
+
+ public class UwbApiException extends java.lang.Exception {
+ ctor public UwbApiException(String message);
+ }
+
+ public final class UwbHardwareNotAvailableException extends androidx.core.uwb.exceptions.UwbApiException {
+ ctor public UwbHardwareNotAvailableException(String message);
+ }
+
+ public final class UwbServiceNotAvailableException extends androidx.core.uwb.exceptions.UwbApiException {
+ ctor public UwbServiceNotAvailableException(String message);
+ }
+
+ public final class UwbSystemCallbackException extends androidx.core.uwb.exceptions.UwbApiException {
+ ctor public UwbSystemCallbackException(String message);
+ }
+
+}
+
diff --git a/core/uwb/uwb/api/restricted_current.txt b/core/uwb/uwb/api/restricted_current.txt
index 569a8ef..269bf8e 100644
--- a/core/uwb/uwb/api/restricted_current.txt
+++ b/core/uwb/uwb/api/restricted_current.txt
@@ -24,25 +24,32 @@
}
public final class RangingParameters {
- ctor public RangingParameters(int uwbConfigType, int sessionId, byte[]? sessionKeyInfo, androidx.core.uwb.UwbComplexChannel? complexChannel, java.util.List<androidx.core.uwb.UwbDevice> peerDevices, int updateRateType);
+ ctor public RangingParameters(int uwbConfigType, int sessionId, int subSessionId, byte[]? sessionKeyInfo, byte[]? subSessionKeyInfo, androidx.core.uwb.UwbComplexChannel? complexChannel, java.util.List<androidx.core.uwb.UwbDevice> peerDevices, int updateRateType);
method public androidx.core.uwb.UwbComplexChannel? getComplexChannel();
method public java.util.List<androidx.core.uwb.UwbDevice> getPeerDevices();
method public int getSessionId();
method public byte[]? getSessionKeyInfo();
+ method public int getSubSessionId();
+ method public byte[]? getSubSessionKeyInfo();
method public int getUpdateRateType();
method public int getUwbConfigType();
property public final androidx.core.uwb.UwbComplexChannel? complexChannel;
property public final java.util.List<androidx.core.uwb.UwbDevice> peerDevices;
property public final int sessionId;
property public final byte[]? sessionKeyInfo;
+ property public final int subSessionId;
+ property public final byte[]? subSessionKeyInfo;
property public final int updateRateType;
property public final int uwbConfigType;
- field public static final int CONFIG_MULTICAST_DS_TWR;
- field public static final int CONFIG_UNICAST_DS_TWR;
+ field public static final int CONFIG_MULTICAST_DS_TWR = 2; // 0x2
+ field public static final int CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR = 7; // 0x7
+ field public static final int CONFIG_PROVISIONED_MULTICAST_DS_TWR = 5; // 0x5
+ field public static final int CONFIG_PROVISIONED_UNICAST_DS_TWR = 4; // 0x4
+ field public static final int CONFIG_UNICAST_DS_TWR = 1; // 0x1
field public static final androidx.core.uwb.RangingParameters.Companion Companion;
- field public static final int RANGING_UPDATE_RATE_AUTOMATIC;
- field public static final int RANGING_UPDATE_RATE_FREQUENT;
- field public static final int RANGING_UPDATE_RATE_INFREQUENT;
+ field public static final int RANGING_UPDATE_RATE_AUTOMATIC = 1; // 0x1
+ field public static final int RANGING_UPDATE_RATE_FREQUENT = 3; // 0x3
+ field public static final int RANGING_UPDATE_RATE_INFREQUENT = 2; // 0x2
}
public static final class RangingParameters.Companion {
diff --git a/core/uwb/uwb/src/androidTest/java/androidx/core/uwb/common/TestCommons.kt b/core/uwb/uwb/src/androidTest/java/androidx/core/uwb/common/TestCommons.kt
index 3290b14..7175825 100644
--- a/core/uwb/uwb/src/androidTest/java/androidx/core/uwb/common/TestCommons.kt
+++ b/core/uwb/uwb/src/androidTest/java/androidx/core/uwb/common/TestCommons.kt
@@ -37,7 +37,9 @@
val RANGING_PARAMETERS = RangingParameters(
RangingParameters.CONFIG_UNICAST_DS_TWR,
sessionId = 0,
+ subSessionId = 0,
sessionKeyInfo = null,
+ subSessionKeyInfo = null,
complexChannel = null,
listOf(UWB_DEVICE),
RangingParameters.RANGING_UPDATE_RATE_AUTOMATIC
diff --git a/core/uwb/uwb/src/main/java/androidx/core/uwb/RangingParameters.kt b/core/uwb/uwb/src/main/java/androidx/core/uwb/RangingParameters.kt
index e89c265..051a3920 100644
--- a/core/uwb/uwb/src/main/java/androidx/core/uwb/RangingParameters.kt
+++ b/core/uwb/uwb/src/main/java/androidx/core/uwb/RangingParameters.kt
@@ -29,14 +29,24 @@
*
* The same session IDs should be used at both ends (Controller and controlee).
*
+ * @property subSessionId
+ * The ID of the ranging sub-session. This value should be set when the Provisioned STS
+ * individual responder case is used.
+ * If other config is used, it should remain SUB_SESSION_UNSET (0)
+ *
* @property sessionKeyInfo
* The session key info to use for the ranging.
- * If the profile uses STATIC
- * STS, this byte array is 8-byte long with first two bytes as
- * Vendor_ID and next six bytes as STATIC_STS_IV.
+ * If the profile uses STATIC STS, this byte array is 8-byte long with first two bytes as
+ * Vendor_ID and next six bytes as STATIC_STS_IV. If the profile uses PROVISIONED STS, this
+ * byte array is 16 or 32-byte long which represent session key.
*
* The same session keys should be used at both ends (Controller and controlee).
*
+ * @property subSessionKeyInfo
+ * The sub-session key info to use for the ranging. This byte array is 16 or 32-byte long when
+ * the profile uses PROVISIONED STS individual responder cases.
+ * If other STS is used, this field should remain null.
+ *
* @property complexChannel
* Optional. If device type is ROLE_CONTROLEE then complex channel should be set.
*
@@ -51,7 +61,9 @@
class RangingParameters(
val uwbConfigType: Int,
val sessionId: Int,
+ val subSessionId: Int,
val sessionKeyInfo: ByteArray?,
+ val subSessionKeyInfo: ByteArray?,
val complexChannel: UwbComplexChannel?,
val peerDevices: List<UwbDevice>,
val updateRateType: Int
@@ -71,8 +83,7 @@
*
* <p> Typical use case: device tracking tags
*/
- @JvmField
- val CONFIG_UNICAST_DS_TWR = 1
+ const val CONFIG_UNICAST_DS_TWR = 1
/**
* Pre-defined one-to-many STATIC STS DS-TWR ranging
@@ -86,19 +97,28 @@
*
* <p> Typical use case: smart phone interacts with many smart devices
*/
- @JvmField
- val CONFIG_MULTICAST_DS_TWR = 2
+ const val CONFIG_MULTICAST_DS_TWR = 2
/** Same as CONFIG_ID_1, except AoA data is not reported. */
- @JvmField
- internal val UWB_CONFIG_ID_3 = 3
+ internal const val CONFIG_UNICAST_DS_TWR_NO_AOA = 3
+
+ /** Same as CONFIG_ID_1, except P-STS security mode is enabled. */
+ const val CONFIG_PROVISIONED_UNICAST_DS_TWR = 4
+
+ /** Same as CONFIG_ID_2, except P-STS security mode is enabled. */
+ const val CONFIG_PROVISIONED_MULTICAST_DS_TWR = 5
+
+ /** Same as CONFIG_ID_3, except P-STS security mode is enabled. */
+ internal const val CONFIG_PROVISIONED_UNICAST_DS_TWR_NO_AOA = 6
+
+ /** Same as CONFIG_ID_2, except P-STS individual controlee key mode is enabled. */
+ const val CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR = 7
/**
* When the screen is on, the reporting interval is hundreds of milliseconds.
* When the screen is off, the reporting interval is a few seconds.
*/
- @JvmField
- val RANGING_UPDATE_RATE_AUTOMATIC = 1
+ const val RANGING_UPDATE_RATE_AUTOMATIC = 1
/**
* The reporting interval is the same as in the AUTOMATIC screen-off case. The
@@ -106,8 +126,7 @@
* reports. (The implementation is hardware and software dependent and it may
* change between different versions.)
*/
- @JvmField
- val RANGING_UPDATE_RATE_INFREQUENT = 2
+ const val RANGING_UPDATE_RATE_INFREQUENT = 2
/**
* The reporting interval is the same as in the AUTOMATIC screen-on case.
@@ -115,7 +134,6 @@
* The actual reporting interval is UwbConfigId related. Different
* configuration may use different values. (The default reporting interval at INFREQUENT mode is 4 seconds)
*/
- @JvmField
- val RANGING_UPDATE_RATE_FREQUENT = 3
+ const val RANGING_UPDATE_RATE_FREQUENT = 3
}
}
diff --git a/core/uwb/uwb/src/main/java/androidx/core/uwb/backend/RangingParameters.java b/core/uwb/uwb/src/main/java/androidx/core/uwb/backend/RangingParameters.java
index 52d466c..c00ce34 100644
--- a/core/uwb/uwb/src/main/java/androidx/core/uwb/backend/RangingParameters.java
+++ b/core/uwb/uwb/src/main/java/androidx/core/uwb/backend/RangingParameters.java
@@ -32,14 +32,19 @@
public class RangingParameters implements android.os.Parcelable
{
@SuppressLint("MutableBareField")
- public int uwbConfigId;
+ public int uwbConfigId = 0;
@SuppressLint("MutableBareField")
public int sessionId = 0;
+ @SuppressLint("MutableBareField")
+ public int subSessionId = 0;
@Nullable
@SuppressLint("MutableBareField")
public byte[] sessionKeyInfo;
@Nullable
@SuppressLint("MutableBareField")
+ public byte[] subSessionKeyInfo;
+ @Nullable
+ @SuppressLint("MutableBareField")
public androidx.core.uwb.backend.UwbComplexChannel complexChannel;
@Nullable
@SuppressLint({"MutableBareField", "NullableCollection"})
@@ -65,7 +70,9 @@
_aidl_parcel.writeInt(0);
_aidl_parcel.writeInt(uwbConfigId);
_aidl_parcel.writeInt(sessionId);
+ _aidl_parcel.writeInt(subSessionId);
_aidl_parcel.writeByteArray(sessionKeyInfo);
+ _aidl_parcel.writeByteArray(subSessionKeyInfo);
_aidl_parcel.writeTypedObject(complexChannel, _aidl_flag);
_aidl_parcel.writeTypedList(peerDevices);
_aidl_parcel.writeInt(rangingUpdateRate);
@@ -86,8 +93,12 @@
if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
sessionId = _aidl_parcel.readInt();
if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+ subSessionId = _aidl_parcel.readInt();
+ if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
sessionKeyInfo = _aidl_parcel.createByteArray();
if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+ subSessionKeyInfo = _aidl_parcel.createByteArray();
+ if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
complexChannel = _aidl_parcel.readTypedObject(androidx.core.uwb.backend.UwbComplexChannel.CREATOR);
if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
peerDevices = _aidl_parcel.createTypedArrayList(androidx.core.uwb.backend.UwbDevice.CREATOR);
diff --git a/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbClientSessionScopeAospImpl.kt b/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbClientSessionScopeAospImpl.kt
index 55ee243..201b5d8 100644
--- a/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbClientSessionScopeAospImpl.kt
+++ b/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbClientSessionScopeAospImpl.kt
@@ -54,7 +54,16 @@
parametersBuilder1.uwbConfigId = when (parameters.uwbConfigType) {
RangingParameters.CONFIG_UNICAST_DS_TWR -> RangingParameters.CONFIG_UNICAST_DS_TWR
RangingParameters.CONFIG_MULTICAST_DS_TWR -> RangingParameters.CONFIG_MULTICAST_DS_TWR
- RangingParameters.UWB_CONFIG_ID_3 -> RangingParameters.UWB_CONFIG_ID_3
+ RangingParameters.CONFIG_UNICAST_DS_TWR_NO_AOA ->
+ RangingParameters.CONFIG_UNICAST_DS_TWR_NO_AOA
+ RangingParameters.CONFIG_PROVISIONED_UNICAST_DS_TWR ->
+ RangingParameters.CONFIG_PROVISIONED_UNICAST_DS_TWR
+ RangingParameters.CONFIG_PROVISIONED_MULTICAST_DS_TWR ->
+ RangingParameters.CONFIG_PROVISIONED_MULTICAST_DS_TWR
+ RangingParameters.CONFIG_PROVISIONED_UNICAST_DS_TWR_NO_AOA ->
+ RangingParameters.CONFIG_PROVISIONED_UNICAST_DS_TWR_NO_AOA
+ RangingParameters.CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR ->
+ RangingParameters.CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR
else -> throw IllegalArgumentException("The selected UWB Config Id is not a valid id.")
}
parametersBuilder1.rangingUpdateRate = when (parameters.updateRateType) {
@@ -69,6 +78,11 @@
}
parametersBuilder1.sessionId = parameters.sessionId
parametersBuilder1.sessionKeyInfo = parameters.sessionKeyInfo
+ if (parameters.uwbConfigType
+ == RangingParameters.CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR) {
+ parametersBuilder1.subSessionId = parameters.subSessionId
+ parametersBuilder1.subSessionKeyInfo = parameters.subSessionKeyInfo
+ }
if (parameters.complexChannel != null) {
val channel = UwbComplexChannel()
channel.channel = parameters.complexChannel.channel
diff --git a/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbClientSessionScopeImpl.kt b/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbClientSessionScopeImpl.kt
index aafd713..2423cec 100644
--- a/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbClientSessionScopeImpl.kt
+++ b/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbClientSessionScopeImpl.kt
@@ -59,8 +59,16 @@
com.google.android.gms.nearby.uwb.RangingParameters.UwbConfigId.CONFIG_ID_1
RangingParameters.CONFIG_MULTICAST_DS_TWR ->
com.google.android.gms.nearby.uwb.RangingParameters.UwbConfigId.CONFIG_ID_2
- RangingParameters.UWB_CONFIG_ID_3 ->
+ RangingParameters.CONFIG_UNICAST_DS_TWR_NO_AOA ->
com.google.android.gms.nearby.uwb.RangingParameters.UwbConfigId.CONFIG_ID_3
+ RangingParameters.CONFIG_PROVISIONED_UNICAST_DS_TWR ->
+ com.google.android.gms.nearby.uwb.RangingParameters.UwbConfigId.CONFIG_ID_4
+ RangingParameters.CONFIG_PROVISIONED_MULTICAST_DS_TWR ->
+ com.google.android.gms.nearby.uwb.RangingParameters.UwbConfigId.CONFIG_ID_5
+ RangingParameters.CONFIG_PROVISIONED_UNICAST_DS_TWR_NO_AOA ->
+ com.google.android.gms.nearby.uwb.RangingParameters.UwbConfigId.CONFIG_ID_6
+ RangingParameters.CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR ->
+ com.google.android.gms.nearby.uwb.RangingParameters.UwbConfigId.CONFIG_ID_7
else ->
throw IllegalArgumentException("The selected UWB Config Id is not a valid id.")
}
@@ -89,6 +97,11 @@
if (parameters.sessionKeyInfo != null) {
parametersBuilder.setSessionKeyInfo(parameters.sessionKeyInfo)
}
+ if (configId == com.google.android.gms.nearby.uwb
+ .RangingParameters.UwbConfigId.CONFIG_ID_7) {
+ parametersBuilder.setSubSessionId(parameters.subSessionId)
+ parametersBuilder.setSubSessionKeyInfo(parameters.subSessionKeyInfo)
+ }
for (peer in parameters.peerDevices) {
parametersBuilder.addPeerDevice(UwbDevice.createForAddress(peer.address.address))
}
diff --git a/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbManagerImpl.kt b/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbManagerImpl.kt
index 489bef6..7af9774 100644
--- a/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbManagerImpl.kt
+++ b/core/uwb/uwb/src/main/java/androidx/core/uwb/impl/UwbManagerImpl.kt
@@ -73,8 +73,8 @@
private suspend fun createClientSessionScope(isController: Boolean): UwbClientSessionScope {
checkSystemFeature(context)
- val hasGmsCore = GoogleApiAvailability.getInstance()
- .isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS
+ val hasGmsCore = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(
+ context, /* minApkVersion */230100000) == ConnectionResult.SUCCESS
return if (hasGmsCore) createGmsClientSessionScope(isController)
else createAospClientSessionScope(isController)
}
diff --git a/credentials/credentials-play-services-auth/lint-baseline.xml b/credentials/credentials-play-services-auth/lint-baseline.xml
index 1a5d2ae..25997f7 100644
--- a/credentials/credentials-play-services-auth/lint-baseline.xml
+++ b/credentials/credentials-play-services-auth/lint-baseline.xml
@@ -1,95 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class BeginSignInControllerUtility {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/playservices/controllers/BeginSignIn/BeginSignInControllerUtility.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="open class CredentialProviderBaseController(private val context: Context) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class CredentialProviderBeginSignInController(private val context: Context) :"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/playservices/controllers/BeginSignIn/CredentialProviderBeginSignInController.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="abstract class CredentialProviderController<T1 : Any, T2 : Any, R2 : Any, R1 : Any,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/playservices/controllers/CredentialProviderController.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class CredentialProviderCreatePasswordController(private val context: Context) :"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/playservices/controllers/CreatePassword/CredentialProviderCreatePasswordController.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class CredentialProviderCreatePublicKeyCredentialController(private val context: Context) :"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/CredentialProviderCreatePublicKeyCredentialController.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class CredentialProviderMetadataHolder : Service() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/playservices/CredentialProviderMetadataHolder.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class CredentialProviderPlayServicesImpl(private val context: Context) : CredentialProvider {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="open class HiddenActivity : Activity() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/playservices/HiddenActivity.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class PublicKeyCredentialControllerUtility {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt"/>
- </issue>
+<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">
<issue
id="UsesNonDefaultVisibleForTesting"
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderMetadataHolder.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderMetadataHolder.kt
index 08d725c..4847ac0 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderMetadataHolder.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderMetadataHolder.kt
@@ -19,13 +19,13 @@
import android.app.Service
import android.content.Intent
import android.os.IBinder
+import androidx.annotation.RestrictTo
/**
* Metadata holder service for the purpose of defining the class that implements
* the [androidx.credentials.CredentialProvider] interface
- *
- * @hide
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY)
class CredentialProviderMetadataHolder : Service() {
override fun onBind(p0: Intent?): IBinder? {
TODO("Not yet implemented")
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt
index d4dc2c5..263fb78 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt
@@ -20,6 +20,7 @@
import android.content.Context
import android.os.CancellationSignal
import android.util.Log
+import androidx.annotation.RestrictTo
import androidx.annotation.VisibleForTesting
import androidx.credentials.ClearCredentialStateRequest
import androidx.credentials.CreateCredentialRequest
@@ -45,9 +46,8 @@
/**
* Entry point of all credential manager requests to the play-services-auth
* module.
- *
- * @hide
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY)
@Suppress("deprecation")
class CredentialProviderPlayServicesImpl(private val context: Context) : CredentialProvider {
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt
index 725d21b..6fd351b7 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt
@@ -23,6 +23,7 @@
import android.os.Bundle
import android.os.ResultReceiver
import android.util.Log
+import androidx.annotation.RestrictTo
import androidx.credentials.exceptions.CreateCredentialInterruptedException
import androidx.credentials.exceptions.CreateCredentialUnknownException
import androidx.credentials.exceptions.GetCredentialInterruptedException
@@ -38,8 +39,8 @@
/**
* An activity used to ensure all required API versions work as intended.
- * @hide
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY)
@Suppress("Deprecation", "ForbiddenSuperClass")
open class HiddenActivity : Activity() {
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/BeginSignIn/BeginSignInControllerUtility.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/BeginSignIn/BeginSignInControllerUtility.kt
index cf5f665..b0ba84e 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/BeginSignIn/BeginSignInControllerUtility.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/BeginSignIn/BeginSignInControllerUtility.kt
@@ -16,41 +16,29 @@
package androidx.credentials.playservices.controllers.BeginSignIn
-/*
- * 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.
- * 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 android.content.Context
+import android.content.pm.PackageManager
import androidx.credentials.GetCredentialRequest
import androidx.credentials.GetPasswordOption
import androidx.credentials.GetPublicKeyCredentialOption
import androidx.credentials.playservices.controllers.CreatePublicKeyCredential.PublicKeyCredentialControllerUtility.Companion.convertToPlayAuthPasskeyJsonRequest
+import androidx.credentials.playservices.controllers.CreatePublicKeyCredential.PublicKeyCredentialControllerUtility.Companion.convertToPlayAuthPasskeyRequest
import com.google.android.gms.auth.api.identity.BeginSignInRequest
import com.google.android.gms.auth.api.identity.BeginSignInRequest.GoogleIdTokenRequestOptions
+import com.google.android.gms.common.GoogleApiAvailability
import com.google.android.libraries.identity.googleid.GetGoogleIdOption
/**
* A utility class to handle logic for the begin sign in controller.
- *
- * @hide
*/
-class BeginSignInControllerUtility {
+@Suppress("deprecation")
+internal class BeginSignInControllerUtility {
companion object {
private val TAG = BeginSignInControllerUtility::class.java.name
- internal fun constructBeginSignInRequest(request: GetCredentialRequest):
+ private const val AUTH_MIN_VERSION_JSON_PARSING: Long = 231815000
+ internal fun constructBeginSignInRequest(request: GetCredentialRequest, context: Context):
BeginSignInRequest {
var isPublicKeyCredReqFound = false
val requestBuilder = BeginSignInRequest.Builder()
@@ -64,15 +52,23 @@
)
autoSelect = autoSelect || option.isAutoSelectAllowed
} else if (option is GetPublicKeyCredentialOption && !isPublicKeyCredReqFound) {
- requestBuilder.setPasskeyJsonSignInRequestOptions(
- convertToPlayAuthPasskeyJsonRequest(option)
- )
+ val curAuthVersion = determineDeviceGMSVersionCode(context)
+ if (needsBackwardsCompatibleRequest(curAuthVersion)) {
+ requestBuilder.setPasskeysSignInRequestOptions(
+ convertToPlayAuthPasskeyRequest(option)
+ )
+ } else {
+ requestBuilder.setPasskeyJsonSignInRequestOptions(
+ convertToPlayAuthPasskeyJsonRequest(option)
+ )
+ }
isPublicKeyCredReqFound = true
// TODO(b/262924507) : watch for GIS update on single vs multiple options of a
// single type. Also make allow list update as GIS has done it.
} else if (option is GetGoogleIdOption) {
requestBuilder.setGoogleIdTokenRequestOptions(
- convertToGoogleIdTokenOption(option))
+ convertToGoogleIdTokenOption(option)
+ )
autoSelect = autoSelect || option.autoSelectEnabled
}
}
@@ -81,8 +77,31 @@
.build()
}
+ /**
+ * Recovers the current GMS version code *running on the device*. This is needed because
+ * even if a dependency knows the methods and functions of a newer code, the device may
+ * only contain the older module, which can cause exceptions due to the discrepancy.
+ */
+ private fun determineDeviceGMSVersionCode(context: Context): Long {
+ val packageManager: PackageManager = context.packageManager
+ val packageName = GoogleApiAvailability.GOOGLE_PLAY_SERVICES_PACKAGE
+ return packageManager.getPackageInfo(packageName, 0).versionCode.toLong()
+ }
+
+ /**
+ * Determines if curAuthVersion needs the backwards compatible GIS json parsing flow or
+ * not. If curAuthVersion >= minVersion for the new flow, this returns false.
+ * Otherwise, it's < than the minVersion for the new flow, so this is true.
+ */
+ private fun needsBackwardsCompatibleRequest(curAuthVersion: Long): Boolean {
+ if (curAuthVersion >= AUTH_MIN_VERSION_JSON_PARSING) {
+ return false
+ }
+ return true
+ }
+
private fun convertToGoogleIdTokenOption(option: GetGoogleIdOption):
- GoogleIdTokenRequestOptions {
+ GoogleIdTokenRequestOptions {
var idTokenOption =
GoogleIdTokenRequestOptions.builder()
.setFilterByAuthorizedAccounts(option.filterByAuthorizedAccounts)
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/BeginSignIn/CredentialProviderBeginSignInController.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/BeginSignIn/CredentialProviderBeginSignInController.kt
index dcea304..8f5e6b9 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/BeginSignIn/CredentialProviderBeginSignInController.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/BeginSignIn/CredentialProviderBeginSignInController.kt
@@ -16,7 +16,7 @@
package androidx.credentials.playservices.controllers.BeginSignIn
-import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.CancellationSignal
@@ -51,17 +51,15 @@
/**
* A controller to handle the BeginSignIn flow with play services.
- *
- * @hide
*/
@Suppress("deprecation")
-class CredentialProviderBeginSignInController(private val activity: Activity) :
+internal class CredentialProviderBeginSignInController(private val context: Context) :
CredentialProviderController<
GetCredentialRequest,
BeginSignInRequest,
SignInCredential,
GetCredentialResponse,
- GetCredentialException>(activity) {
+ GetCredentialException>(context) {
/**
* The callback object state, used in the protected handleResponse method.
@@ -119,10 +117,10 @@
}
val convertedRequest: BeginSignInRequest = this.convertRequestToPlayServices(request)
- val hiddenIntent = Intent(activity, HiddenActivity::class.java)
+ val hiddenIntent = Intent(context, HiddenActivity::class.java)
hiddenIntent.putExtra(REQUEST_TAG, convertedRequest)
generateHiddenActivityIntent(resultReceiver, hiddenIntent, BEGIN_SIGN_IN_TAG)
- activity.startActivity(hiddenIntent)
+ context.startActivity(hiddenIntent)
}
internal fun handleResponse(uniqueRequestCode: Int, resultCode: Int, data: Intent?) {
@@ -143,7 +141,7 @@
)
) return
try {
- val signInCredential = Identity.getSignInClient(activity)
+ val signInCredential = Identity.getSignInClient(context)
.getSignInCredentialFromIntent(data)
val response = convertResponseToCredentialManager(signInCredential)
cancelOrCallbackExceptionOrResult(cancellationSignal) {
@@ -183,7 +181,7 @@
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
public override fun convertRequestToPlayServices(request: GetCredentialRequest):
BeginSignInRequest {
- return constructBeginSignInRequest(request)
+ return constructBeginSignInRequest(request, context)
}
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
@@ -246,14 +244,14 @@
* This finds a past version of the [CredentialProviderBeginSignInController] if it exists,
* otherwise it generates a new instance.
*
- * @param activity the calling activity for this controller
+ * @param context the calling context for this controller
* @return a credential provider controller for a specific begin sign in credential request
*/
@JvmStatic
- fun getInstance(activity: Activity):
+ fun getInstance(context: Context):
CredentialProviderBeginSignInController {
if (controller == null) {
- controller = CredentialProviderBeginSignInController(activity)
+ controller = CredentialProviderBeginSignInController(context)
}
return controller!!
}
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePassword/CredentialProviderCreatePasswordController.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePassword/CredentialProviderCreatePasswordController.kt
index a7b6746..8f750c7 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePassword/CredentialProviderCreatePasswordController.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePassword/CredentialProviderCreatePasswordController.kt
@@ -16,7 +16,7 @@
package androidx.credentials.playservices.controllers.CreatePassword
-import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.CancellationSignal
@@ -40,17 +40,15 @@
/**
* A controller to handle the CreatePassword flow with play services.
- *
- * @hide
*/
@Suppress("deprecation")
-class CredentialProviderCreatePasswordController(private val activity: Activity) :
+internal class CredentialProviderCreatePasswordController(private val context: Context) :
CredentialProviderController<
CreatePasswordRequest,
SavePasswordRequest,
Unit,
CreateCredentialResponse,
- CreateCredentialException>(activity) {
+ CreateCredentialException>(context) {
/**
* The callback object state, used in the protected handleResponse method.
@@ -101,10 +99,10 @@
}
val convertedRequest: SavePasswordRequest = this.convertRequestToPlayServices(request)
- val hiddenIntent = Intent(activity, HiddenActivity::class.java)
+ val hiddenIntent = Intent(context, HiddenActivity::class.java)
hiddenIntent.putExtra(REQUEST_TAG, convertedRequest)
generateHiddenActivityIntent(resultReceiver, hiddenIntent, CREATE_PASSWORD_TAG)
- activity.startActivity(hiddenIntent)
+ context.startActivity(hiddenIntent)
}
internal fun handleResponse(uniqueRequestCode: Int, resultCode: Int) {
@@ -144,14 +142,14 @@
* [CredentialProviderCreatePasswordController] if it exists, otherwise
* it generates a new instance.
*
- * @param activity the calling activity for this controller
+ * @param context the calling context for this controller
* @return a credential provider controller for CreatePasswordController
*/
@JvmStatic
- fun getInstance(activity: Activity):
+ fun getInstance(context: Context):
CredentialProviderCreatePasswordController {
if (controller == null) {
- controller = CredentialProviderCreatePasswordController(activity)
+ controller = CredentialProviderCreatePasswordController(context)
}
return controller!!
}
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/CredentialProviderCreatePublicKeyCredentialController.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/CredentialProviderCreatePublicKeyCredentialController.kt
index ac236eb..8045667 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/CredentialProviderCreatePublicKeyCredentialController.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/CredentialProviderCreatePublicKeyCredentialController.kt
@@ -16,7 +16,7 @@
package androidx.credentials.playservices.controllers.CreatePublicKeyCredential
-import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.CancellationSignal
@@ -47,16 +47,15 @@
/**
* A controller to handle the CreatePublicKeyCredential flow with play services.
*
- * @hide
*/
@Suppress("deprecation")
-class CredentialProviderCreatePublicKeyCredentialController(private val activity: Activity) :
+internal class CredentialProviderCreatePublicKeyCredentialController(private val context: Context) :
CredentialProviderController<
CreatePublicKeyCredentialRequest,
PublicKeyCredentialCreationOptions,
PublicKeyCredential,
CreateCredentialResponse,
- CreateCredentialException>(activity) {
+ CreateCredentialException>(context) {
/**
* The callback object state, used in the protected handleResponse method.
@@ -121,11 +120,11 @@
if (CredentialProviderPlayServicesImpl.cancellationReviewer(cancellationSignal)) {
return
}
- val hiddenIntent = Intent(activity, HiddenActivity::class.java)
+ val hiddenIntent = Intent(context, HiddenActivity::class.java)
hiddenIntent.putExtra(REQUEST_TAG, fidoRegistrationRequest)
generateHiddenActivityIntent(resultReceiver, hiddenIntent,
CREATE_PUBLIC_KEY_CREDENTIAL_TAG)
- activity.startActivity(hiddenIntent)
+ context.startActivity(hiddenIntent)
}
internal fun handleResponse(uniqueRequestCode: Int, resultCode: Int, data: Intent?) {
@@ -196,14 +195,14 @@
* [CredentialProviderCreatePublicKeyCredentialController] if it exists, otherwise
* it generates a new instance.
*
- * @param activity the calling activity for this controller
+ * @param context the calling context for this controller
* @return a credential provider controller for CreatePublicKeyCredential
*/
@JvmStatic
- fun getInstance(activity: Activity):
+ fun getInstance(context: Context):
CredentialProviderCreatePublicKeyCredentialController {
if (controller == null) {
- controller = CredentialProviderCreatePublicKeyCredentialController(activity)
+ controller = CredentialProviderCreatePublicKeyCredentialController(context)
}
return controller!!
}
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 893b7e6..dcb28fb 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
@@ -67,10 +67,8 @@
/**
* A utility class to handle logic for the begin sign in controller.
- *
- * @hide
*/
-class PublicKeyCredentialControllerUtility {
+internal class PublicKeyCredentialControllerUtility {
companion object {
@@ -241,6 +239,7 @@
* Converts from the Credential Manager public key credential option to the Play Auth
* Module passkey json option.
*
+ * @return the current auth module passkey request
*/
fun convertToPlayAuthPasskeyJsonRequest(option: GetPublicKeyCredentialOption):
BeginSignInRequest.PasskeyJsonRequestOptions {
@@ -250,6 +249,30 @@
.build()
}
+ /**
+ * Converts from the Credential Manager public key credential option to the Play Auth
+ * Module passkey option, used in a backwards compatible flow for the auth dependency.
+ *
+ * @return the backwards compatible auth module passkey request
+ */
+ @Deprecated("Upgrade GMS version so 'convertToPlayAuthPasskeyJsoNRequest' is used")
+ @Suppress("deprecation")
+ fun convertToPlayAuthPasskeyRequest(option: GetPublicKeyCredentialOption):
+ BeginSignInRequest.PasskeysRequestOptions {
+ val json = JSONObject(option.requestJson)
+ val rpId = json.optString("rpId", "")
+ if (rpId.isEmpty()) {
+ throw JSONException("GetPublicKeyCredentialOption - rpId not specified in the " +
+ "request or is unexpectedly empty")
+ }
+ val challenge = getChallenge(json)
+ return BeginSignInRequest.PasskeysRequestOptions.Builder()
+ .setSupported(true)
+ .setRpId(rpId)
+ .setChallenge(challenge)
+ .build()
+ }
+
private fun getChallenge(json: JSONObject): ByteArray {
val challengeB64 = json.optString("challenge", "")
if (challengeB64.isEmpty()) {
@@ -560,7 +583,8 @@
ErrorCode.ATTESTATION_NOT_PRIVATE_ERR to NotReadableError(),
ErrorCode.CONSTRAINT_ERR to ConstraintError(),
ErrorCode.DATA_ERR to DataError(),
- ErrorCode.ENCODING_ERR to InvalidStateError(),
+ ErrorCode.INVALID_STATE_ERR to InvalidStateError(),
+ ErrorCode.ENCODING_ERR to EncodingError(),
ErrorCode.NETWORK_ERR to NetworkError(),
ErrorCode.NOT_ALLOWED_ERR to NotAllowedError(),
ErrorCode.NOT_SUPPORTED_ERR to NotSupportedError(),
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt
index 7e9365d..dfcf223 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt
@@ -16,6 +16,7 @@
package androidx.credentials.playservices.controllers
+import android.content.Context
import android.content.Intent
import android.os.Parcel
import android.os.ResultReceiver
@@ -32,9 +33,8 @@
/**
* Holds all non type specific details shared by the controllers.
- * @hide
*/
-open class CredentialProviderBaseController(private val activity: android.app.Activity) {
+internal open class CredentialProviderBaseController(private val context: Context) {
companion object {
// Common retryable status codes from the play modules found
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderController.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderController.kt
index fafe63a..51c7424 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderController.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderController.kt
@@ -17,6 +17,7 @@
package androidx.credentials.playservices.controllers
import android.app.Activity
+import android.content.Context
import android.os.Bundle
import android.os.CancellationSignal
import androidx.credentials.CredentialManagerCallback
@@ -41,11 +42,10 @@
* @param R1 the credential response type converted back to that used by credential manager
* @param E1 the credential error type to throw
*
- * @hide
*/
@Suppress("deprecation")
-abstract class CredentialProviderController<T1 : Any, T2 : Any, R2 : Any, R1 : Any,
- E1 : Any>(private val activity: Activity) : CredentialProviderBaseController(activity) {
+internal abstract class CredentialProviderController<T1 : Any, T2 : Any, R2 : Any, R1 : Any,
+ E1 : Any>(private val context: Context) : CredentialProviderBaseController(context) {
companion object {
diff --git a/credentials/credentials/lint-baseline.xml b/credentials/credentials/lint-baseline.xml
index f43f80f..7371789 100644
--- a/credentials/credentials/lint-baseline.xml
+++ b/credentials/credentials/lint-baseline.xml
@@ -1,1616 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/AbortError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/ClearCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/ClearCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/ClearCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/ClearCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val errorMessage: CharSequence? = null"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/ClearCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val errorMessage: CharSequence? = null"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/ClearCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val errorMessage: CharSequence? = null"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/ClearCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/ClearCredentialInterruptedException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/ClearCredentialProviderConfigurationException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/ClearCredentialUnknownException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/ClearCredentialUnsupportedException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/ConstraintError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialCancellationException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val errorMessage: CharSequence? = null"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val errorMessage: CharSequence? = null"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val errorMessage: CharSequence? = null"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialInterruptedException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialNoCreateOptionException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialProviderConfigurationException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val credentialData: Bundle,"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val credentialData: Bundle,"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val credentialData: Bundle,"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val candidateQueryData: Bundle,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val candidateQueryData: Bundle,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val candidateQueryData: Bundle,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isSystemProviderRequired: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isSystemProviderRequired: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isSystemProviderRequired: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isAutoSelectAllowed: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isAutoSelectAllowed: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isAutoSelectAllowed: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" val displayInfo: DisplayInfo,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" val displayInfo: DisplayInfo,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" val displayInfo: DisplayInfo,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" class DisplayInfo internal /** @hide */ constructor("
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" val credentialTypeIcon: Icon?,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" val credentialTypeIcon: Icon?,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" val credentialTypeIcon: Icon?,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" val defaultProvider: String?,"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" val defaultProvider: String?,"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" val defaultProvider: String?,"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun toBundle(): Bundle {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" const val BUNDLE_KEY_REQUEST_DISPLAY_INFO ="
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" const val BUNDLE_KEY_CREDENTIAL_TYPE_ICON ="
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" const val BUNDLE_KEY_DEFAULT_PROVIDER ="
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun parseFromCredentialDataBundle(from: Bundle): DisplayInfo? {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun parseFromCredentialDataBundle(from: Bundle): DisplayInfo? {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" const val BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED ="
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun createFrom("
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun createFrom("
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialResponse.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialResponse.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialResponse.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val data: Bundle,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialResponse.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val data: Bundle,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialResponse.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val data: Bundle,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialResponse.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialResponse.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun createFrom(type: String, data: Bundle): CreateCredentialResponse {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialResponse.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun createFrom(type: String, data: Bundle): CreateCredentialResponse {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialResponse.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialUnknownException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialUnsupportedException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreatePasswordRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreatePasswordResponse.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialDomException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreatePublicKeyCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreatePublicKeyCredentialResponse.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/Credential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/Credential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/Credential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val data: Bundle,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/Credential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val data: Bundle,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/Credential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val data: Bundle,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/Credential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/Credential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun createFrom(type: String, data: Bundle): Credential {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/Credential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun createFrom(type: String, data: Bundle): Credential {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/Credential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val requestData: Bundle,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val requestData: Bundle,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val requestData: Bundle,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val candidateQueryData: Bundle,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val candidateQueryData: Bundle,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val candidateQueryData: Bundle,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isSystemProviderRequired: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isSystemProviderRequired: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isSystemProviderRequired: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isAutoSelectAllowed: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isAutoSelectAllowed: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val isAutoSelectAllowed: Boolean,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" const val BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED ="
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun createFrom("
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun createFrom("
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class CredentialProviderFactory {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialProviderFactory.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/DataCloneError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/DataError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/DomError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/DomError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/DomError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/EncodingError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class FederatedCredential private constructor() : Credential("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/FederatedCredential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="internal class FrameworkClassParsingException : Exception()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/internal/FrameworkClassParsingException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class FrameworkImplHelper {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/internal/FrameworkImplHelper.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun getFinalCreateCredentialData("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/internal/FrameworkImplHelper.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun getFinalCreateCredentialData("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/internal/FrameworkImplHelper.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialCancellationException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val errorMessage: CharSequence? = null"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val errorMessage: CharSequence? = null"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open val errorMessage: CharSequence? = null"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialInterruptedException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialProviderConfigurationException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialUnknownException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/GetCredentialUnsupportedException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/GetPasswordOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialDomException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override val type: String,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/GetPublicKeyCredentialOption.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/HierarchyRequestError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/InUseAttributeError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/InvalidCharacterError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/InvalidModificationError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/InvalidNodeTypeError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/InvalidStateError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NamespaceError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NetworkError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/NoCredentialException.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NoModificationAllowedError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NotAllowedError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NotFoundError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NotReadableError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NotSupportedError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/OperationError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/OptOutError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/PasswordCredential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" const val TYPE_PASSWORD_CREDENTIAL: String = "android.credentials.TYPE_PASSWORD_CREDENTIAL""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/PasswordCredential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/PublicKeyCredential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" const val TYPE_PUBLIC_KEY_CREDENTIAL: String ="
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/PublicKeyCredential.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/QuotaExceededError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/ReadOnlyError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/SecurityError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/SyntaxError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/TimeoutError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/TransactionInactiveError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/UnknownError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/VersionError.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" companion object {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/WrongDocumentError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/AbortError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/ConstraintError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/CreateCredentialProviderConfigurationException.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreateCredentialRequest.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreatePasswordRequest.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialDomException.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CreatePublicKeyCredentialResponse.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/CredentialOption.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/DataCloneError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/DataError.kt"/>
- </issue>
+<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">
<issue
id="UsesNonDefaultVisibleForTesting"
@@ -1621,265 +10,4 @@
file="src/main/java/androidx/credentials/exceptions/domerrors/DomError.kt"/>
</issue>
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/EncodingError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialDomException.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/HierarchyRequestError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/InUseAttributeError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/InvalidCharacterError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/InvalidModificationError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/InvalidNodeTypeError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/InvalidStateError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NamespaceError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NetworkError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NoModificationAllowedError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NotAllowedError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NotFoundError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NotReadableError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/NotSupportedError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/OperationError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/OptOutError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/PasswordCredential.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/PasswordCredential.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/PublicKeyCredential.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/QuotaExceededError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/ReadOnlyError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/SecurityError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/SyntaxError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/TimeoutError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/TransactionInactiveError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/UnknownError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/VersionError.kt"/>
- </issue>
-
- <issue
- id="UsesNonDefaultVisibleForTesting"
- message="Found non-default `otherwise` value for @VisibleForTesting"
- errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/credentials/exceptions/domerrors/WrongDocumentError.kt"/>
- </issue>
-
</issues>
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialRequest.kt b/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialRequest.kt
index 10c6a67..c3e25f2 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialRequest.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialRequest.kt
@@ -21,7 +21,6 @@
import android.text.TextUtils
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
-import androidx.annotation.VisibleForTesting
import androidx.credentials.PublicKeyCredential.Companion.BUNDLE_KEY_SUBTYPE
import androidx.credentials.internal.FrameworkClassParsingException
@@ -33,22 +32,17 @@
* register a new user credential.
*/
abstract class CreateCredentialRequest internal constructor(
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val type: String,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val credentialData: Bundle,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val candidateQueryData: Bundle,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val isSystemProviderRequired: Boolean,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val isAutoSelectAllowed: Boolean,
- /** @hide */
+ @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
val displayInfo: DisplayInfo,
val origin: String?,
) {
@@ -69,12 +63,12 @@
* displayed next to the `userId` during the user consent to help your user better understand
* the credential being created
*/
- class DisplayInfo internal /** @hide */ constructor(
+ class DisplayInfo internal constructor(
val userId: CharSequence,
val userDisplayName: CharSequence?,
- /** @hide */
+ @get:RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
val credentialTypeIcon: Icon?,
- /** @hide */
+ @get:RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
val defaultProvider: String?,
) {
@@ -101,9 +95,8 @@
require(userId.isNotEmpty()) { "userId should not be empty" }
}
- /** @hide */
@RequiresApi(23)
- fun toBundle(): Bundle {
+ internal fun toBundle(): Bundle {
val bundle = Bundle()
bundle.putCharSequence(BUNDLE_KEY_USER_ID, userId)
if (!TextUtils.isEmpty(userDisplayName)) {
@@ -118,38 +111,30 @@
return bundle
}
- /** @hide */
- companion object {
- /** @hide */
+ internal companion object {
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
const val BUNDLE_KEY_REQUEST_DISPLAY_INFO =
"androidx.credentials.BUNDLE_KEY_REQUEST_DISPLAY_INFO"
-
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
const val BUNDLE_KEY_USER_ID =
"androidx.credentials.BUNDLE_KEY_USER_ID"
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- /** @hide */
- const val BUNDLE_KEY_USER_DISPLAY_NAME =
+ internal const val BUNDLE_KEY_USER_DISPLAY_NAME =
"androidx.credentials.BUNDLE_KEY_USER_DISPLAY_NAME"
-
- /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
const val BUNDLE_KEY_CREDENTIAL_TYPE_ICON =
"androidx.credentials.BUNDLE_KEY_CREDENTIAL_TYPE_ICON"
- /** @hide */
- const val BUNDLE_KEY_DEFAULT_PROVIDER =
+ internal const val BUNDLE_KEY_DEFAULT_PROVIDER =
"androidx.credentials.BUNDLE_KEY_DEFAULT_PROVIDER"
/**
* Returns a RequestDisplayInfo from a `credentialData` Bundle, or otherwise `null` if
* parsing fails.
- *
- * @hide
*/
@JvmStatic
@RequiresApi(23)
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
@Suppress("DEPRECATION") // bundle.getParcelable(key)
fun parseFromCredentialDataBundle(from: Bundle): DisplayInfo? {
return try {
@@ -169,9 +154,8 @@
}
}
- /** @hide */
- companion object {
- /** @hide */
+ internal companion object {
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
const val BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED =
"androidx.credentials.BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED"
@@ -179,9 +163,8 @@
* Attempts to parse the raw data into one of [CreatePasswordRequest],
* [CreatePublicKeyCredentialRequest], and
* [CreateCustomCredentialRequest]. Otherwise returns null.
- *
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
@JvmStatic
@RequiresApi(23)
fun createFrom(
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialResponse.kt b/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialResponse.kt
index 92bc244..88f20a3 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialResponse.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialResponse.kt
@@ -25,17 +25,14 @@
* [CreateCredentialRequest].
*/
abstract class CreateCredentialResponse internal constructor(
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val type: String,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val data: Bundle,
) {
- /** @hide */
- companion object {
- /** @hide */
+ internal companion object {
@JvmStatic
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
fun createFrom(type: String, data: Bundle): CreateCredentialResponse {
return try {
when (type) {
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordRequest.kt b/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordRequest.kt
index 62b970b..a124749 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordRequest.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordRequest.kt
@@ -18,7 +18,7 @@
import android.os.Bundle
import androidx.annotation.RequiresApi
-import androidx.annotation.VisibleForTesting
+import androidx.annotation.RestrictTo
import androidx.credentials.internal.FrameworkClassParsingException
/**
@@ -67,10 +67,10 @@
require(password.isNotEmpty()) { "password should not be empty" }
}
- /** @hide */
- companion object {
- internal const val BUNDLE_KEY_ID = "androidx.credentials.BUNDLE_KEY_ID"
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal companion object {
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
+ const val BUNDLE_KEY_ID = "androidx.credentials.BUNDLE_KEY_ID"
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
const val BUNDLE_KEY_PASSWORD = "androidx.credentials.BUNDLE_KEY_PASSWORD"
@JvmStatic
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordResponse.kt b/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordResponse.kt
index b862600..f34f0ec 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordResponse.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordResponse.kt
@@ -23,8 +23,7 @@
PasswordCredential.TYPE_PASSWORD_CREDENTIAL,
Bundle(),
) {
- /** @hide */
- companion object {
+ internal companion object {
@Suppress("UNUSED_PARAMETER")
@JvmStatic
internal fun createFrom(data: Bundle): CreatePasswordResponse {
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CreatePublicKeyCredentialRequest.kt b/credentials/credentials/src/main/java/androidx/credentials/CreatePublicKeyCredentialRequest.kt
index 366d9f1..d1d5875 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CreatePublicKeyCredentialRequest.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CreatePublicKeyCredentialRequest.kt
@@ -81,8 +81,7 @@
require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
}
- /** @hide */
- companion object {
+ internal companion object {
internal const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS =
"androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS"
internal const val BUNDLE_KEY_CLIENT_DATA_HASH =
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CreatePublicKeyCredentialResponse.kt b/credentials/credentials/src/main/java/androidx/credentials/CreatePublicKeyCredentialResponse.kt
index 8c97f79..ee01b33 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CreatePublicKeyCredentialResponse.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CreatePublicKeyCredentialResponse.kt
@@ -17,7 +17,6 @@
package androidx.credentials
import android.os.Bundle
-import androidx.annotation.VisibleForTesting
import androidx.credentials.internal.FrameworkClassParsingException
/**
@@ -39,10 +38,8 @@
"empty" }
}
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- const val BUNDLE_KEY_REGISTRATION_RESPONSE_JSON =
+ internal companion object {
+ internal const val BUNDLE_KEY_REGISTRATION_RESPONSE_JSON =
"androidx.credentials.BUNDLE_KEY_REGISTRATION_RESPONSE_JSON"
@JvmStatic
diff --git a/credentials/credentials/src/main/java/androidx/credentials/Credential.kt b/credentials/credentials/src/main/java/androidx/credentials/Credential.kt
index 404ec2f..6488093 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/Credential.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/Credential.kt
@@ -24,17 +24,14 @@
* Base class for a credential with which the user consented to authenticate to the app.
*/
abstract class Credential internal constructor(
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val type: String,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val data: Bundle,
) {
- /** @hide */
- companion object {
- /** @hide */
+ internal companion object {
@JvmStatic
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
fun createFrom(type: String, data: Bundle): Credential {
return try {
when (type) {
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CredentialOption.kt b/credentials/credentials/src/main/java/androidx/credentials/CredentialOption.kt
index 4655ca9..d1fd69b 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CredentialOption.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CredentialOption.kt
@@ -18,7 +18,6 @@
import android.os.Bundle
import androidx.annotation.RestrictTo
-import androidx.annotation.VisibleForTesting
import androidx.credentials.internal.FrameworkClassParsingException
/**
@@ -28,19 +27,14 @@
* the specific credential types and configurations that your app accepts.
*/
abstract class CredentialOption internal constructor(
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val type: String,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val requestData: Bundle,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val candidateQueryData: Bundle,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val isSystemProviderRequired: Boolean,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val isAutoSelectAllowed: Boolean,
) {
@@ -52,15 +46,12 @@
}
}
- /** @hide */
- companion object {
- /** @hide */
- @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
- const val BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED =
+ internal companion object {
+ internal const val BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED =
"androidx.credentials.BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED"
- /** @hide */
@JvmStatic
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
fun createFrom(
type: String,
requestData: Bundle,
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
index cb5b9f9..d230818 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
@@ -22,10 +22,8 @@
/**
* Factory that returns the credential provider to be used by Credential Manager.
- *
- * @hide
*/
-class CredentialProviderFactory {
+internal class CredentialProviderFactory {
companion object {
private const val TAG = "CredProviderFactory"
diff --git a/credentials/credentials/src/main/java/androidx/credentials/FederatedCredential.kt b/credentials/credentials/src/main/java/androidx/credentials/FederatedCredential.kt
index e5c2bbf..e30588e 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/FederatedCredential.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/FederatedCredential.kt
@@ -23,10 +23,8 @@
*
* Note: the FedCM proposal is still under public discussion and its constructor will be exposed
* after the proposal is final.
- *
- * @hide
*/
-class FederatedCredential private constructor() : Credential(
+internal class FederatedCredential private constructor() : Credential(
TYPE_FEDERATED_CREDENTIAL,
Bundle(),
) {
diff --git a/credentials/credentials/src/main/java/androidx/credentials/GetPasswordOption.kt b/credentials/credentials/src/main/java/androidx/credentials/GetPasswordOption.kt
index a65188e..39f4f4d 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/GetPasswordOption.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/GetPasswordOption.kt
@@ -33,8 +33,7 @@
isAutoSelectAllowed = isAutoSelectAllowed,
) {
- /** @hide */
- companion object {
+ internal companion object {
@Suppress("UNUSED_PARAMETER")
@JvmStatic
internal fun createFrom(data: Bundle): GetPasswordOption {
diff --git a/credentials/credentials/src/main/java/androidx/credentials/GetPublicKeyCredentialOption.kt b/credentials/credentials/src/main/java/androidx/credentials/GetPublicKeyCredentialOption.kt
index cdd6e76..586cde4 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/GetPublicKeyCredentialOption.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/GetPublicKeyCredentialOption.kt
@@ -50,8 +50,7 @@
require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
}
- /** @hide */
- companion object {
+ internal companion object {
internal const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS =
"androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS"
internal const val BUNDLE_KEY_CLIENT_DATA_HASH =
diff --git a/credentials/credentials/src/main/java/androidx/credentials/PasswordCredential.kt b/credentials/credentials/src/main/java/androidx/credentials/PasswordCredential.kt
index 6df28d8..3b143ca 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/PasswordCredential.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/PasswordCredential.kt
@@ -17,7 +17,7 @@
package androidx.credentials
import android.os.Bundle
-import androidx.annotation.VisibleForTesting
+import androidx.annotation.RestrictTo
import androidx.credentials.internal.FrameworkClassParsingException
/**
@@ -38,17 +38,15 @@
require(password.isNotEmpty()) { "password should not be empty" }
}
- /** @hide */
- companion object {
+ internal companion object {
// TODO: this type is officially defined in the framework. This definition should be
// removed when the framework type is available in jetpack.
- /** @hide */
- const val TYPE_PASSWORD_CREDENTIAL: String = "android.credentials.TYPE_PASSWORD_CREDENTIAL"
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
+ const val TYPE_PASSWORD_CREDENTIAL: String =
+ "android.credentials.TYPE_PASSWORD_CREDENTIAL"
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- const val BUNDLE_KEY_ID = "androidx.credentials.BUNDLE_KEY_ID"
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- const val BUNDLE_KEY_PASSWORD = "androidx.credentials.BUNDLE_KEY_PASSWORD"
+ internal const val BUNDLE_KEY_ID = "androidx.credentials.BUNDLE_KEY_ID"
+ internal const val BUNDLE_KEY_PASSWORD = "androidx.credentials.BUNDLE_KEY_PASSWORD"
@JvmStatic
internal fun toBundle(id: String, password: String): Bundle {
diff --git a/credentials/credentials/src/main/java/androidx/credentials/PublicKeyCredential.kt b/credentials/credentials/src/main/java/androidx/credentials/PublicKeyCredential.kt
index d0640fe..e90f1d3 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/PublicKeyCredential.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/PublicKeyCredential.kt
@@ -17,7 +17,6 @@
package androidx.credentials
import android.os.Bundle
-import androidx.annotation.VisibleForTesting
import androidx.credentials.internal.FrameworkClassParsingException
/**
@@ -41,18 +40,14 @@
"authentication response JSON must not be empty" }
}
- /** @hide */
- companion object {
+ internal companion object {
/**
* The type value for public key credential related operations.
- *
- * @hide
*/
- const val TYPE_PUBLIC_KEY_CREDENTIAL: String =
+ internal const val TYPE_PUBLIC_KEY_CREDENTIAL: String =
"androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL"
/** The Bundle key value for the public key credential subtype (privileged or regular). */
internal const val BUNDLE_KEY_SUBTYPE = "androidx.credentials.BUNDLE_KEY_SUBTYPE"
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal const val BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON =
"androidx.credentials.BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON"
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialException.kt
index 127f6e7..166e8bf 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialException.kt
@@ -28,10 +28,8 @@
* @see ClearCredentialUnknownException
*/
abstract class ClearCredentialException @JvmOverloads internal constructor(
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val type: String,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val errorMessage: CharSequence? = null
) : Exception(errorMessage?.toString())
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialInterruptedException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialInterruptedException.kt
index 924aae4..40225aa9 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialInterruptedException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialInterruptedException.kt
@@ -26,8 +26,7 @@
class ClearCredentialInterruptedException @JvmOverloads constructor(
errorMessage: CharSequence? = null
) : ClearCredentialException(TYPE_CLEAR_CREDENTIAL_INTERRUPTED_EXCEPTION, errorMessage) {
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_CLEAR_CREDENTIAL_INTERRUPTED_EXCEPTION =
"androidx.credentials.TYPE_CLEAR_CREDENTIAL_INTERRUPTED_EXCEPTION"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialProviderConfigurationException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialProviderConfigurationException.kt
index 1483d33..a85e8aa 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialProviderConfigurationException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialProviderConfigurationException.kt
@@ -26,8 +26,7 @@
class ClearCredentialProviderConfigurationException @JvmOverloads constructor(
errorMessage: CharSequence? = null
) : ClearCredentialException(TYPE_CLEAR_CREDENTIAL_PROVIDER_CONFIGURATION_EXCEPTION, errorMessage) {
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_CLEAR_CREDENTIAL_PROVIDER_CONFIGURATION_EXCEPTION =
"androidx.credentials.TYPE_CLEAR_CREDENTIAL_PROVIDER_CONFIGURATION_EXCEPTION"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialUnknownException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialUnknownException.kt
index e241f6c..a311e17 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialUnknownException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialUnknownException.kt
@@ -24,9 +24,7 @@
class ClearCredentialUnknownException @JvmOverloads constructor(
errorMessage: CharSequence? = null
) : ClearCredentialException(TYPE_CLEAR_CREDENTIAL_UNKNOWN_EXCEPTION, errorMessage) {
-
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_CLEAR_CREDENTIAL_UNKNOWN_EXCEPTION =
"android.credentials.ClearCredentialStateException.TYPE_UNKNOWN"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialUnsupportedException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialUnsupportedException.kt
index 3524914..1c522ad 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialUnsupportedException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/ClearCredentialUnsupportedException.kt
@@ -27,8 +27,7 @@
class ClearCredentialUnsupportedException @JvmOverloads constructor(
errorMessage: CharSequence? = null
) : ClearCredentialException(TYPE_CLEAR_CREDENTIAL_UNSUPPORTED_EXCEPTION, errorMessage) {
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_CLEAR_CREDENTIAL_UNSUPPORTED_EXCEPTION =
"androidx.credentials.TYPE_CLEAR_CREDENTIAL_UNSUPPORTED_EXCEPTION"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialCancellationException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialCancellationException.kt
index 4cd52f6..5bc8f11 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialCancellationException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialCancellationException.kt
@@ -26,9 +26,7 @@
class CreateCredentialCancellationException @JvmOverloads constructor(
errorMessage: CharSequence? = null
) : CreateCredentialException(TYPE_CREATE_CREDENTIAL_CANCELLATION_EXCEPTION, errorMessage) {
-
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_CREATE_CREDENTIAL_CANCELLATION_EXCEPTION =
"android.credentials.CreateCredentialException.TYPE_USER_CANCELED"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialException.kt
index 8faeabc..78a6f26 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialException.kt
@@ -29,10 +29,8 @@
* @see CreateCredentialUnknownException
*/
abstract class CreateCredentialException @JvmOverloads internal constructor(
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val type: String,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val errorMessage: CharSequence? = null
) : Exception(errorMessage?.toString())
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialInterruptedException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialInterruptedException.kt
index cd78998..1e1f176 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialInterruptedException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialInterruptedException.kt
@@ -26,9 +26,7 @@
class CreateCredentialInterruptedException @JvmOverloads constructor(
errorMessage: CharSequence? = null
) : CreateCredentialException(TYPE_CREATE_CREDENTIAL_INTERRUPTED_EXCEPTION, errorMessage) {
-
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_CREATE_CREDENTIAL_INTERRUPTED_EXCEPTION =
"android.credentials.CreateCredentialException.TYPE_INTERRUPTED"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialNoCreateOptionException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialNoCreateOptionException.kt
index de7c996..0382924 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialNoCreateOptionException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialNoCreateOptionException.kt
@@ -25,9 +25,7 @@
class CreateCredentialNoCreateOptionException @JvmOverloads constructor(
errorMessage: CharSequence? = null
) : CreateCredentialException(TYPE_CREATE_CREDENTIAL_NO_CREATE_OPTION, errorMessage) {
-
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_CREATE_CREDENTIAL_NO_CREATE_OPTION =
"android.credentials.CreateCredentialException.TYPE_NO_CREATE_OPTIONS"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialProviderConfigurationException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialProviderConfigurationException.kt
index 7e27323..f371d7e 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialProviderConfigurationException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialProviderConfigurationException.kt
@@ -16,8 +16,6 @@
package androidx.credentials.exceptions
-import androidx.annotation.VisibleForTesting
-
/**
* During the create credential flow, this is thrown when configurations are mismatched for the
* provider, typically indicating the provider dependency is missing in the manifest or some
@@ -29,10 +27,8 @@
errorMessage: CharSequence? = null
) : CreateCredentialException(TYPE_CREATE_CREDENTIAL_PROVIDER_CONFIGURATION_EXCEPTION,
errorMessage) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- internal val TYPE_CREATE_CREDENTIAL_PROVIDER_CONFIGURATION_EXCEPTION =
+ internal companion object {
+ internal const val TYPE_CREATE_CREDENTIAL_PROVIDER_CONFIGURATION_EXCEPTION =
"androidx.credentials.TYPE_CREATE_CREDENTIAL_PROVIDER_CONFIGURATION_EXCEPTION"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialUnknownException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialUnknownException.kt
index 40b2476..cb16a64 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialUnknownException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialUnknownException.kt
@@ -25,8 +25,7 @@
errorMessage: CharSequence? = null
) : CreateCredentialException(TYPE_CREATE_CREDENTIAL_UNKNOWN_EXCEPTION, errorMessage) {
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_CREATE_CREDENTIAL_UNKNOWN_EXCEPTION =
"android.credentials.CreateCredentialException.TYPE_UNKNOWN"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialUnsupportedException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialUnsupportedException.kt
index 393cb34..df0250c 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialUnsupportedException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/CreateCredentialUnsupportedException.kt
@@ -27,8 +27,7 @@
class CreateCredentialUnsupportedException @JvmOverloads constructor(
errorMessage: CharSequence? = null
) : CreateCredentialException(TYPE_CREATE_CREDENTIAL_UNSUPPORTED_EXCEPTION, errorMessage) {
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_CREATE_CREDENTIAL_UNSUPPORTED_EXCEPTION =
"androidx.credentials.TYPE_CREATE_CREDENTIAL_UNSUPPORTED_EXCEPTION"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialCancellationException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialCancellationException.kt
index 044dec8..9cf49be 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialCancellationException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialCancellationException.kt
@@ -27,8 +27,7 @@
errorMessage: CharSequence? = null
) : GetCredentialException(TYPE_GET_CREDENTIAL_CANCELLATION_EXCEPTION, errorMessage) {
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_GET_CREDENTIAL_CANCELLATION_EXCEPTION =
"android.credentials.GetCredentialException.TYPE_USER_CANCELED"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialException.kt
index a126a2e..d6383e9 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialException.kt
@@ -29,10 +29,8 @@
* @see GetCredentialInterruptedException
*/
abstract class GetCredentialException @JvmOverloads internal constructor(
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val type: String,
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val errorMessage: CharSequence? = null
) : Exception(errorMessage?.toString())
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialInterruptedException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialInterruptedException.kt
index 816ca8d..8ed0357 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialInterruptedException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialInterruptedException.kt
@@ -27,8 +27,7 @@
errorMessage: CharSequence? = null
) : GetCredentialException(TYPE_GET_CREDENTIAL_INTERRUPTED_EXCEPTION, errorMessage) {
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_GET_CREDENTIAL_INTERRUPTED_EXCEPTION =
"android.credentials.GetCredentialException.TYPE_INTERRUPTED"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialProviderConfigurationException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialProviderConfigurationException.kt
index 3d3a169..2fceba4 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialProviderConfigurationException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialProviderConfigurationException.kt
@@ -26,8 +26,7 @@
class GetCredentialProviderConfigurationException @JvmOverloads constructor(
errorMessage: CharSequence? = null
) : GetCredentialException(TYPE_GET_CREDENTIAL_PROVIDER_CONFIGURATION_EXCEPTION, errorMessage) {
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_GET_CREDENTIAL_PROVIDER_CONFIGURATION_EXCEPTION =
"androidx.credentials.TYPE_GET_CREDENTIAL_PROVIDER_CONFIGURATION_EXCEPTION"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialUnknownException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialUnknownException.kt
index b75ad50..fca2aa7 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialUnknownException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialUnknownException.kt
@@ -25,8 +25,7 @@
errorMessage: CharSequence? = null
) : GetCredentialException(TYPE_GET_CREDENTIAL_UNKNOWN_EXCEPTION, errorMessage) {
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_GET_CREDENTIAL_UNKNOWN_EXCEPTION =
"android.credentials.GetCredentialException.TYPE_UNKNOWN"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialUnsupportedException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialUnsupportedException.kt
index 2f6e4dc..827050d 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialUnsupportedException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/GetCredentialUnsupportedException.kt
@@ -27,8 +27,7 @@
class GetCredentialUnsupportedException @JvmOverloads constructor(
errorMessage: CharSequence? = null
) : GetCredentialException(TYPE_GET_CREDENTIAL_UNSUPPORTED_EXCEPTION, errorMessage) {
- /** @hide */
- companion object {
+ internal companion object {
internal const val TYPE_GET_CREDENTIAL_UNSUPPORTED_EXCEPTION =
"androidx.credentials.TYPE_GET_CREDENTIAL_UNSUPPORTED_EXCEPTION"
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/NoCredentialException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/NoCredentialException.kt
index e41a684..961dfb2 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/NoCredentialException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/NoCredentialException.kt
@@ -29,8 +29,7 @@
errorMessage: CharSequence? = null
) : GetCredentialException(TYPE_FRAMEWORK_TYPE_NO_CREDENTIAL, errorMessage) {
- /** @hide */
- companion object {
+ internal companion object {
/** Maintain a copy of the framework type so that we aren't restricted by the API level. */
internal const val TYPE_FRAMEWORK_TYPE_NO_CREDENTIAL =
"android.credentials.GetCredentialException.TYPE_NO_CREDENTIAL"
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/AbortError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/AbortError.kt
index fe63bf3..07decbe 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/AbortError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/AbortError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -29,10 +28,8 @@
@Suppress("ExtendsError")
class AbortError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_ABORT_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_ABORT_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_ABORT_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_ABORT_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/ConstraintError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/ConstraintError.kt
index 2a591c3..974d005 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/ConstraintError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/ConstraintError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class ConstraintError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_CONSTRAINT_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_CONSTRAINT_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_CONSTRAINT_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_CONSTRAINT_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DataCloneError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DataCloneError.kt
index 08e09289..2a85a7f 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DataCloneError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DataCloneError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class DataCloneError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DATA_CLONE_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DATA_CLONE_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DATA_CLONE_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DATA_CLONE_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DataError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DataError.kt
index 729c9dc..a64dac5 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DataError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DataError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -28,10 +27,8 @@
*/
@Suppress("ExtendsError")
class DataError : DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DATA_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DATA_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DATA_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DATA_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DomError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DomError.kt
index bc43ef8..e4ed965 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DomError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/DomError.kt
@@ -44,7 +44,6 @@
* This utilization may vary by use case.
*/
abstract class DomError(
- /** @hide */
@get:VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open val type: String
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/EncodingError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/EncodingError.kt
index 5140a54..064393c 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/EncodingError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/EncodingError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class EncodingError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_ENCODING_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_ENCODING_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_ENCODING_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_ENCODING_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/HierarchyRequestError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/HierarchyRequestError.kt
index f260677..2fe4fa1 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/HierarchyRequestError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/HierarchyRequestError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class HierarchyRequestError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_HIERARCHY_REQUEST_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_HIERARCHY_REQUEST_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_HIERARCHY_REQUEST_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_HIERARCHY_REQUEST_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InUseAttributeError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InUseAttributeError.kt
index aa19bbf..a65a88e 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InUseAttributeError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InUseAttributeError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class InUseAttributeError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_IN_USE_ATTRIBUTE_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_IN_USE_ATTRIBUTE_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_IN_USE_ATTRIBUTE_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_IN_USE_ATTRIBUTE_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidCharacterError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidCharacterError.kt
index 7b2c856..7a84d8c 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidCharacterError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidCharacterError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class InvalidCharacterError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_CHARACTER_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_CHARACTER_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_CHARACTER_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_CHARACTER_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidModificationError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidModificationError.kt
index 17479a1..52c19ba 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidModificationError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidModificationError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class InvalidModificationError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_MODIFICATION_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_MODIFICATION_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_MODIFICATION_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_MODIFICATION_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidNodeTypeError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidNodeTypeError.kt
index 6f7525c..6acd286 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidNodeTypeError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidNodeTypeError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class InvalidNodeTypeError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_NODE_TYPE_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_NODE_TYPE_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_NODE_TYPE_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_NODE_TYPE_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidStateError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidStateError.kt
index 4cd4aa8..11385b4 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidStateError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/InvalidStateError.kt
@@ -16,8 +16,8 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
+
/**
* During the create public key credential flow, this is thrown when an authenticator response
* exception contains a invalid_state_err code from the fido spec, indicating the object reached an
@@ -29,10 +29,8 @@
@Suppress("ExtendsError")
class InvalidStateError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_STATE_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_STATE_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_STATE_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_INVALID_STATE_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NamespaceError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NamespaceError.kt
index 42a414f..9e35610 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NamespaceError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NamespaceError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class NamespaceError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NAMESPACE_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NAMESPACE_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NAMESPACE_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NAMESPACE_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NetworkError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NetworkError.kt
index 31e6239..7e94ef7 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NetworkError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NetworkError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -29,10 +28,8 @@
@Suppress("ExtendsError")
class NetworkError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NETWORK_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NETWORK_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NETWORK_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NETWORK_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NoModificationAllowedError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NoModificationAllowedError.kt
index d5bc768..eb505e1 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NoModificationAllowedError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NoModificationAllowedError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class NoModificationAllowedError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NO_MODIFICATION_ALLOWED_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NO_MODIFICATION_ALLOWED_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NO_MODIFICATION_ALLOWED_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NO_MODIFICATION_ALLOWED_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotAllowedError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotAllowedError.kt
index 443bd2d..c5474e7c 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotAllowedError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotAllowedError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -31,10 +30,8 @@
@Suppress("ExtendsError")
class NotAllowedError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_ALLOWED_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_ALLOWED_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_ALLOWED_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_ALLOWED_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotFoundError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotFoundError.kt
index eb07222..16bf573 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotFoundError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotFoundError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class NotFoundError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_FOUND_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_FOUND_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_FOUND_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_FOUND_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotReadableError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotReadableError.kt
index a414169..49be851 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotReadableError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotReadableError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class NotReadableError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_READABLE_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_READABLE_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_READABLE_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_READABLE_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotSupportedError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotSupportedError.kt
index dfe8dbd..ebb99fb 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotSupportedError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/NotSupportedError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class NotSupportedError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_SUPPORTED_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_SUPPORTED_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_SUPPORTED_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_NOT_SUPPORTED_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/OperationError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/OperationError.kt
index 45e6446..1dbb790 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/OperationError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/OperationError.kt
@@ -16,8 +16,8 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
+
/**
* During the create public key credential flow, this is thrown when an authenticator response
* exception contains and operation_err from the fido spec, indicating the operation failed for an
@@ -29,10 +29,8 @@
@Suppress("ExtendsError")
class OperationError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_OPERATION_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_OPERATION_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_OPERATION_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_OPERATION_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/OptOutError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/OptOutError.kt
index 8005407..6930e15 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/OptOutError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/OptOutError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class OptOutError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_OPT_OUT_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_OPT_OUT_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_OPT_OUT_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_OPT_OUT_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/QuotaExceededError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/QuotaExceededError.kt
index fe022b3a..64e26c5 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/QuotaExceededError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/QuotaExceededError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class QuotaExceededError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_QUOTA_EXCEEDED_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_QUOTA_EXCEEDED_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_QUOTA_EXCEEDED_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_QUOTA_EXCEEDED_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/ReadOnlyError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/ReadOnlyError.kt
index 9d621aa..48a257d 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/ReadOnlyError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/ReadOnlyError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class ReadOnlyError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_READ_ONLY_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_READ_ONLY_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_READ_ONLY_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_READ_ONLY_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/SecurityError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/SecurityError.kt
index fc747c8..2243f52b 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/SecurityError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/SecurityError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class SecurityError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_SECURITY_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_SECURITY_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_SECURITY_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_SECURITY_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/SyntaxError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/SyntaxError.kt
index a0d9092..5f57a88 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/SyntaxError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/SyntaxError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class SyntaxError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_SYNTAX_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_SYNTAX_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_SYNTAX_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_SYNTAX_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/TimeoutError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/TimeoutError.kt
index 06b7740..0de2480 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/TimeoutError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/TimeoutError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -29,10 +28,8 @@
@Suppress("ExtendsError")
class TimeoutError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_TIMEOUT_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_TIMEOUT_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_TIMEOUT_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_TIMEOUT_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/TransactionInactiveError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/TransactionInactiveError.kt
index 3685b29..2cfa180 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/TransactionInactiveError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/TransactionInactiveError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class TransactionInactiveError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_TRANSACTION_INACTIVE_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_TRANSACTION_INACTIVE_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_TRANSACTION_INACTIVE_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_TRANSACTION_INACTIVE_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/UnknownError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/UnknownError.kt
index da446e9..3e99a8f 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/UnknownError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/UnknownError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class UnknownError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_UNKNOWN_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_UNKNOWN_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_UNKNOWN_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_UNKNOWN_ERROR"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/VersionError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/VersionError.kt
index a14731d..b160edb 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/VersionError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/VersionError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class VersionError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_VERSION_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_VERSION_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_VERSION_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_VERSION_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/WrongDocumentError.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/WrongDocumentError.kt
index 3a91da9..6a54a25 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/WrongDocumentError.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/domerrors/WrongDocumentError.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.domerrors
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
/**
@@ -30,10 +29,8 @@
@Suppress("ExtendsError")
class WrongDocumentError :
DomError(TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_WRONG_DOCUMENT_ERROR) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_WRONG_DOCUMENT_ERROR: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_WRONG_DOCUMENT_ERROR: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_WRONG_DOCUMENT_ERROR"
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialDomException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialDomException.kt
index 3a5a0f1..c71d09c 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialDomException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialDomException.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.publickeycredential
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.domerrors.DomError
/**
@@ -35,10 +34,8 @@
) : CreatePublicKeyCredentialException(
TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DOM_EXCEPTION + domError.type,
errorMessage) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DOM_EXCEPTION: String =
+ internal companion object {
+ internal const val TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DOM_EXCEPTION: String =
"androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DOM_EXCEPTION"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialException.kt
index bfcc858..9647903 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/CreatePublicKeyCredentialException.kt
@@ -29,7 +29,6 @@
* @throws IllegalArgumentException if [type] is empty
*/
open class CreatePublicKeyCredentialException @JvmOverloads internal constructor(
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
override val type: String,
errorMessage: CharSequence? = null
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialDomException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialDomException.kt
index 08eb797..ba91548 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialDomException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialDomException.kt
@@ -16,7 +16,6 @@
package androidx.credentials.exceptions.publickeycredential
-import androidx.annotation.VisibleForTesting
import androidx.credentials.exceptions.domerrors.DomError
/**
@@ -35,10 +34,8 @@
) : GetPublicKeyCredentialException(
TYPE_GET_PUBLIC_KEY_CREDENTIAL_DOM_EXCEPTION + domError.type,
errorMessage) {
- /** @hide */
- companion object {
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- const val TYPE_GET_PUBLIC_KEY_CREDENTIAL_DOM_EXCEPTION: String =
+ internal companion object {
+ internal const val TYPE_GET_PUBLIC_KEY_CREDENTIAL_DOM_EXCEPTION: String =
"androidx.credentials.TYPE_GET_PUBLIC_KEY_CREDENTIAL_DOM_EXCEPTION"
}
}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialException.kt b/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialException.kt
index ca1eb69..d5b999f 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/exceptions/publickeycredential/GetPublicKeyCredentialException.kt
@@ -29,7 +29,6 @@
* @throws IllegalArgumentException if [type] is empty
*/
open class GetPublicKeyCredentialException @JvmOverloads internal constructor(
- /** @hide */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
override val type: String,
errorMessage: CharSequence? = null
diff --git a/credentials/credentials/src/main/java/androidx/credentials/internal/FrameworkClassParsingException.kt b/credentials/credentials/src/main/java/androidx/credentials/internal/FrameworkClassParsingException.kt
index 8e890c3b..4110de5 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/internal/FrameworkClassParsingException.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/internal/FrameworkClassParsingException.kt
@@ -19,7 +19,5 @@
/**
* Internal exception used to indicate a parsing error while converting from a framework type to
* a jetpack type.
- *
- * @hide
*/
internal class FrameworkClassParsingException : Exception()
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/internal/FrameworkImplHelper.kt b/credentials/credentials/src/main/java/androidx/credentials/internal/FrameworkImplHelper.kt
index ab39cd4..d3bdf01 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/internal/FrameworkImplHelper.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/internal/FrameworkImplHelper.kt
@@ -20,20 +20,19 @@
import android.graphics.drawable.Icon
import android.os.Bundle
import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
import androidx.credentials.CreateCredentialRequest
import androidx.credentials.CreatePasswordRequest
import androidx.credentials.CreatePublicKeyCredentialRequest
import androidx.credentials.R
-/** @hide */
@RequiresApi(23)
-class FrameworkImplHelper {
+internal class FrameworkImplHelper {
companion object {
/**
* Take the create request's `credentialData` and add SDK specific values to it.
- *
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
@JvmStatic
@RequiresApi(23)
fun getFinalCreateCredentialData(
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index 4884c02..b1c05d8 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -50,6 +50,9 @@
\$OUT_DIR/androidx/benchmark/integration\-tests/dry\-run\-benchmark/build/intermediates/tmp/manifest/androidTest/release/tempFile[0-9]+ProcessTestManifest[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
# > Task :compose:runtime:runtime-saveable:processDebugAndroidTestManifest
\$SUPPORT/compose/runtime/runtime\-saveable/src/androidAndroidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# Usage of android.overrideVersionCheck
+Minimum supported Gradle version is [0-9]+\.[0-9]+\. Current version is [0-9]+\.[0-9]+\. If using the gradle wrapper\, try editing the distributionUrl in \$SUPPORT\/gradle\/wrapper\/gradle\-wrapper\.properties to gradle.*
+As android\.overrideVersionCheck is set, continuing anyway\.
# > Task :buildOnServer
[0-9]+ actionable tasks: [0-9]+ executed, [0-9]+ up\-to\-date
Configuration cache entry reused with [0-9]+ problems\.
@@ -113,13 +116,97 @@
WARN: Missing @param tag for parameter `shouldRunMigration` of function androidx\.datastore\.migrations/SharedPreferencesMigration/SharedPreferencesMigration/\#android\.content\.Context\#kotlin\.String\#kotlin\.collections\.Set\[kotlin\.String\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Boolean\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.datastore\.migrations\.SharedPreferencesView,TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `alpha` of function androidx\.compose\.ui\.graphics/Color\.Companion/hsl/\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.colorspace\.Rgb/PointingToDeclaration/
WARN: Missing @param tag for parameter `alpha` of function androidx\.compose\.ui\.graphics/Color\.Companion/hsv/\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.colorspace\.Rgb/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/linearGradient/\#kotlin\.collections\.List\[androidx\.compose\.ui\.graphics\.Color\]\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.LinearGradientSample\. b/[0-9]+
+WARN: Multiple sources exist for OffsetEffect\. Artifact ID metadata will not be displayed
WARN: Missing @param tag for parameter `v` of function androidx\.compose\.ui\.graphics/ColorMatrix/set/\#kotlin\.Int\#kotlin\.Int\#kotlin\.Float/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/ImageBitmap/toPixelMap/androidx\.compose\.ui\.graphics\.ImageBitmap\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int\#kotlin\.IntArray\#kotlin\.Int\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.ImageBitmapToPixelMapSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/horizontalGradient/\#kotlin\.Array\[kotlin\.Pair\[kotlin\.Float,androidx\.compose\.ui\.graphics\.Color\]\]\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.GradientBrushSample\. b/[0-9]+
WARN: Missing @param tag for parameter `operation` of function androidx\.compose\.ui\.graphics/Path/op/\#androidx\.compose\.ui\.graphics\.Path\#androidx\.compose\.ui\.graphics\.Path\#androidx\.compose\.ui\.graphics\.PathOperation/PointingToDeclaration/
+WARN: Multiple sources exist for RenderEffect\. Artifact ID metadata will not be displayed
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics//graphicsLayer/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TransformOrigin\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.RenderEffect\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.CompositingStrategy/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ChangeOpacity\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/linearGradient/\#kotlin\.collections\.List\[androidx\.compose\.ui\.graphics\.Color\]\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.GradientBrushSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics//graphicsLayer/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TransformOrigin\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.RenderEffect\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.CompositingStrategy/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CompositingStrategyModulateAlpha\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/radialGradient/\#kotlin\.Array\[kotlin\.Pair\[kotlin\.Float,androidx\.compose\.ui\.graphics\.Color\]\]\#androidx\.compose\.ui\.geometry\.Offset\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.RadialBrushColorStopSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/radialGradient/\#kotlin\.Array\[kotlin\.Pair\[kotlin\.Float,androidx\.compose\.ui\.graphics\.Color\]\]\#androidx\.compose\.ui\.geometry\.Offset\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.GradientBrushSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/radialGradient/\#kotlin\.collections\.List\[androidx\.compose\.ui\.graphics\.Color\]\#androidx\.compose\.ui\.geometry\.Offset\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.RadialBrushSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics//graphicsLayer/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.GraphicsLayerScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.AnimateFadeIn\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/radialGradient/\#kotlin\.collections\.List\[androidx\.compose\.ui\.graphics\.Color\]\#androidx\.compose\.ui\.geometry\.Offset\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.GradientBrushSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/sweepGradient/\#kotlin\.Array\[kotlin\.Pair\[kotlin\.Float,androidx\.compose\.ui\.graphics\.Color\]\]\#androidx\.compose\.ui\.geometry\.Offset/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.SweepGradientColorStopSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/sweepGradient/\#kotlin\.Array\[kotlin\.Pair\[kotlin\.Float,androidx\.compose\.ui\.graphics\.Color\]\]\#androidx\.compose\.ui\.geometry\.Offset/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.GradientBrushSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/sweepGradient/\#kotlin\.collections\.List\[androidx\.compose\.ui\.graphics\.Color\]\#androidx\.compose\.ui\.geometry\.Offset/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.SweepGradientSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/sweepGradient/\#kotlin\.collections\.List\[androidx\.compose\.ui\.graphics\.Color\]\#androidx\.compose\.ui\.geometry\.Offset/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.GradientBrushSample\. b/[0-9]+
WARN: Missing @param tag for parameter `radians` of function androidx\.compose\.ui\.graphics/Canvas/rotateRad/androidx\.compose\.ui\.graphics\.Canvas\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float/PointingToDeclaration/
WARN: Missing @param tag for parameter `density` of function androidx\.compose\.ui\.graphics\.drawscope/CanvasDrawScope/draw/\#androidx\.compose\.ui\.unit\.Density\#androidx\.compose\.ui\.unit\.LayoutDirection\#androidx\.compose\.ui\.graphics\.Canvas\#androidx\.compose\.ui\.geometry\.Size\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.drawscope\.DrawScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `layoutDirection` of function androidx\.compose\.ui\.graphics\.drawscope/CanvasDrawScope/draw/\#androidx\.compose\.ui\.unit\.Density\#androidx\.compose\.ui\.unit\.LayoutDirection\#androidx\.compose\.ui\.graphics\.Canvas\#androidx\.compose\.ui\.geometry\.Size\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.drawscope\.DrawScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics\.drawscope/DrawScope/drawOval/\#androidx\.compose\.ui\.graphics\.Brush\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.geometry\.Size\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\#androidx\.compose\.ui\.graphics\.ColorFilter\?\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.DrawScopeOvalBrushSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics\.drawscope/DrawScope/withTransform/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.drawscope\.DrawTransform,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.drawscope\.DrawScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.DrawScopeBatchedTransformSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics\.drawscope/DrawScope/drawOval/\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.geometry\.Size\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\#androidx\.compose\.ui\.graphics\.ColorFilter\?\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.DrawScopeOvalColorSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics\.drawscope//withTransform/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.drawscope\.DrawTransform,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.drawscope\.DrawScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.DrawScopeBatchedTransformSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics\.drawscope/DrawScope/drawText/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#androidx\.compose\.ui\.text\.TextMeasurer\#androidx\.compose\.ui\.text\.AnnotatedString\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.collections\.List\[androidx\.compose\.ui\.text\.AnnotatedString\.Range\[androidx\.compose\.ui\.text\.Placeholder\]\]\#androidx\.compose\.ui\.geometry\.Size\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.DrawTextAnnotatedStringSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics\.drawscope/DrawScope/drawText/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#androidx\.compose\.ui\.text\.TextMeasurer\#kotlin\.String\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Boolean\#kotlin\.Int\#androidx\.compose\.ui\.geometry\.Size\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.DrawTextSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics\.drawscope/DrawScope/drawText/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#androidx\.compose\.ui\.text\.TextMeasurer\#kotlin\.String\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Boolean\#kotlin\.Int\#androidx\.compose\.ui\.geometry\.Size\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.DrawTextStyledSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics\.drawscope/DrawScope/drawText/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#androidx\.compose\.ui\.text\.TextLayoutResult\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.geometry\.Offset\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.Shadow\?\#androidx\.compose\.ui\.text\.style\.TextDecoration\?\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\?\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.DrawTextMeasureInLayoutSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics\.drawscope/DrawScope/drawText/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#androidx\.compose\.ui\.text\.TextLayoutResult\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.geometry\.Offset\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.Shadow\?\#androidx\.compose\.ui\.text\.style\.TextDecoration\?\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\?\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.DrawTextDrawWithCacheSample\. b/[0-9]+
WARN: Missing @param tag for parameter `pathFillType` of function androidx\.compose\.ui\.graphics\.vector//path/androidx\.compose\.ui\.graphics\.vector\.ImageVector\.Builder\#kotlin\.String\#androidx\.compose\.ui\.graphics\.Brush\?\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.Brush\?\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.StrokeCap\#androidx\.compose\.ui\.graphics\.StrokeJoin\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.PathFillType\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.vector\.PathBuilder,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `autoMirror` of function androidx\.compose\.ui\.graphics\.vector//rememberVectorPainter/\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Float\#kotlin\.Float\#kotlin\.String\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.BlendMode\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key//isAltPressed/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventIsAltPressedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key//onInterceptKeyBeforeSoftKeyboard/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.key\.KeyEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/KeyEventType\.Companion/KeyDown/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventTypeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/KeyEvent/isAltPressed/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventIsAltPressedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key//isCtrlPressed/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventIsCtrlPressedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/KeyEventType\.Companion/KeyUp/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventTypeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key//onKeyEvent/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.key\.KeyEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/KeyEvent/isCtrlPressed/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventIsCtrlPressedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key//onPreInterceptKeyBeforeSoftKeyboard/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.key\.KeyEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/KeyEventType\.Companion/Unknown/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventTypeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/KeyEvent/isMetaPressed/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventIsMetaPressedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key//isMetaPressed/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventIsMetaPressedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key//onPreviewKeyEvent/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.key\.KeyEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key//isShiftPressed/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventIsShiftPressedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/KeyEvent/isShiftPressed/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventIsShiftPressedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key//key/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventIsAltPressedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/KeyEvent/key/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventIsAltPressedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/KeyEvent/type/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventTypeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key//type/androidx\.compose\.ui\.input\.key\.KeyEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventTypeSample\. b/[0-9]+
+WARN: Multiple sources exist for Key\. Artifact ID metadata will not be displayed
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.nestedscroll//nestedScroll/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollConnection\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollDispatcher\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.NestedScrollConnectionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.nestedscroll//nestedScroll/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollConnection\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollDispatcher\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.NestedScrollDispatcherSample\. b/[0-9]+
+WARN: Multiple sources exist for PointerEvent\. Artifact ID metadata will not be displayed
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/AwaitPointerEventScope/awaitDragOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/PointerEvent/calculateCentroid/androidx\.compose\.ui\.input\.pointer\.PointerEvent\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CalculateCentroidSize\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/PointerInputScope/detectDragGestures/androidx\.compose\.ui\.input\.pointer\.PointerInputScope\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DetectDragGesturesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/PointerEvent/calculateCentroidSize/androidx\.compose\.ui\.input\.pointer\.PointerEvent\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CalculateCentroidSize\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/AwaitPointerEventScope/awaitHorizontalDragOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitHorizontalDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/PointerInputScope/detectDragGesturesAfterLongPress/androidx\.compose\.ui\.input\.pointer\.PointerInputScope\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DetectDragWithLongPressGesturesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/PointerEvent/calculatePan/androidx\.compose\.ui\.input\.pointer\.PointerEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CalculatePan\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/AwaitPointerEventScope/awaitHorizontalTouchSlopOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitHorizontalDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/PointerEvent/calculateRotation/androidx\.compose\.ui\.input\.pointer\.PointerEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CalculateRotation\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer//pointerHoverIcon/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.input\.pointer\.PointerIcon\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PointerIconSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/PointerInputScope/detectHorizontalDragGestures/androidx\.compose\.ui\.input\.pointer\.PointerInputScope\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DetectHorizontalDragGesturesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/PointerEvent/calculateZoom/androidx\.compose\.ui\.input\.pointer\.PointerEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CalculateZoom\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/AwaitPointerEventScope/awaitLongPressOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitLongPressOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer//pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.keyedPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/PointerInputScope/detectVerticalDragGestures/androidx\.compose\.ui\.input\.pointer\.PointerInputScope\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DetectVerticalDragGesturesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer//pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.rememberedUpdatedParameterPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/AwaitPointerEventScope/awaitTouchSlopOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer//pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.keyedPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer//pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.rememberedUpdatedParameterPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/AwaitPointerEventScope/awaitVerticalDragOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitVerticalDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer//pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.keyedPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/PointerInputScope/detectTransformGestures/androidx\.compose\.ui\.input\.pointer\.PointerInputScope\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,androidx\.compose\.ui\.geometry\.Offset,kotlin\.Float,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DetectTransformGestures\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer//pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.rememberedUpdatedParameterPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/AwaitPointerEventScope/awaitVerticalTouchSlopOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitVerticalDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/AwaitPointerEventScope/drag/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DragSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/AwaitPointerEventScope/horizontalDrag/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.HorizontalDragSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.pointer/AwaitPointerEventScope/verticalDrag/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.VerticalDragSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.rotary//onPreRotaryScrollEvent/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.rotary\.RotaryScrollEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PreRotaryEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.rotary//onRotaryScrollEvent/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.rotary\.RotaryScrollEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RotaryEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.rotary//onRotaryScrollEvent/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.rotary\.RotaryScrollEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PreRotaryEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//Layout/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.layout\.MeasurePolicy/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutUsage\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//layoutId/androidx\.compose\.ui\.layout\.Measurable\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutTagChildrenUsage\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/Measurable/layoutId/androidx\.compose\.ui\.layout\.Measurable\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutTagChildrenUsage\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/Placeable\.PlacementScope/coordinates/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PlacementScopeCoordinatesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//intermediateLayout/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.IntermediateMeasureScope,androidx\.compose\.ui\.layout\.Measurable,androidx\.compose\.ui\.unit\.Constraints,androidx\.compose\.ui\.layout\.MeasureResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.IntermediateLayoutSample\. b/[0-9]+
WARN: Missing @param tag for parameter `trimPathEnd` of function androidx\.compose\.ui\.graphics\.vector/ImageVector\.Builder/addPath/\#kotlin\.collections\.List\[androidx\.compose\.ui\.graphics\.vector\.PathNode\]\#androidx\.compose\.ui\.graphics\.PathFillType\#kotlin\.String\#androidx\.compose\.ui\.graphics\.Brush\?\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.Brush\?\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.StrokeCap\#androidx\.compose\.ui\.graphics\.StrokeJoin\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float/PointingToDeclaration/
WARN: Missing @param tag for parameter `pathFillType` of function androidx\.compose\.ui\.graphics\.vector/ImageVector\.Builder/path/androidx\.compose\.ui\.graphics\.vector\.ImageVector\.Builder\#kotlin\.String\#androidx\.compose\.ui\.graphics\.Brush\?\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.Brush\?\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.StrokeCap\#androidx\.compose\.ui\.graphics\.StrokeJoin\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.PathFillType\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.vector\.PathBuilder,kotlin\.Unit\]/PointingToDeclaration/
WARN: Failed to resolve `@see SdkSandboxManager\.startSdkSandboxActivity`!
@@ -131,19 +218,48 @@
WARN: Failed to resolve `@see SdkSandboxController\.unregisterSdkSandboxActivityHandler`!
Did you mean SdkSandboxController\#unregisterSdkSandboxActivityHandler\?
WARN: Missing @param tag for parameter `position` of function androidx\.compose\.ui\.layout/Placeable/placeAt/\#androidx\.compose\.ui\.unit\.IntOffset\#kotlin\.Float\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.GraphicsLayerScope,kotlin\.Unit\]\?/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//layoutId/androidx\.compose\.ui\.Modifier\#kotlin\.Any/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutTagChildrenUsage\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/LookaheadScope/onPlaced/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.LookaheadLayoutCoordinates,androidx\.compose\.ui\.layout\.LookaheadLayoutCoordinates,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LookaheadLayoutCoordinatesSample\. b/[0-9]+
WARN: Missing @param tag for parameter `x` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/place/androidx\.compose\.ui\.layout\.Placeable\#kotlin\.Int\#kotlin\.Int\#kotlin\.Float/PointingToDeclaration/
WARN: Missing @param tag for parameter `y` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/place/androidx\.compose\.ui\.layout\.Placeable\#kotlin\.Int\#kotlin\.Int\#kotlin\.Float/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//layout/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.MeasureScope,androidx\.compose\.ui\.layout\.Measurable,androidx\.compose\.ui\.unit\.Constraints,androidx\.compose\.ui\.layout\.MeasureResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ConvenienceLayoutModifierSample\. b/[0-9]+
WARN: Missing @param tag for parameter `position` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/place/androidx\.compose\.ui\.layout\.Placeable\#androidx\.compose\.ui\.unit\.IntOffset\#kotlin\.Float/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/LookaheadLayoutScope/onPlaced/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.LookaheadLayoutCoordinates,androidx\.compose\.ui\.layout\.LookaheadLayoutCoordinates,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LookaheadLayoutCoordinatesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/LookaheadLayoutScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LookaheadLayoutCoordinatesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/LookaheadScope/intermediateLayout/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.MeasureScope,androidx\.compose\.ui\.layout\.Measurable,androidx\.compose\.ui\.unit\.Constraints,androidx\.compose\.ui\.unit\.IntSize,androidx\.compose\.ui\.layout\.MeasureResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.IntermediateLayoutSample\. b/[0-9]+
WARN: Missing @param tag for parameter `position` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/placeRelative/androidx\.compose\.ui\.layout\.Placeable\#androidx\.compose\.ui\.unit\.IntOffset\#kotlin\.Float/PointingToDeclaration/
WARN: Missing @param tag for parameter `x` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/placeRelative/androidx\.compose\.ui\.layout\.Placeable\#kotlin\.Int\#kotlin\.Int\#kotlin\.Float/PointingToDeclaration/
WARN: Missing @param tag for parameter `y` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/placeRelative/androidx\.compose\.ui\.layout\.Placeable\#kotlin\.Int\#kotlin\.Int\#kotlin\.Float/PointingToDeclaration/
WARN: Missing @param tag for parameter `position` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/placeRelativeWithLayer/androidx\.compose\.ui\.layout\.Placeable\#androidx\.compose\.ui\.unit\.IntOffset\#kotlin\.Float\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.GraphicsLayerScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//onGloballyPositioned/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.LayoutCoordinates,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnGloballyPositioned\. b/[0-9]+
WARN: Missing @param tag for parameter `x` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/placeRelativeWithLayer/androidx\.compose\.ui\.layout\.Placeable\#kotlin\.Int\#kotlin\.Int\#kotlin\.Float\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.GraphicsLayerScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `y` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/placeRelativeWithLayer/androidx\.compose\.ui\.layout\.Placeable\#kotlin\.Int\#kotlin\.Int\#kotlin\.Float\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.GraphicsLayerScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `x` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/placeWithLayer/androidx\.compose\.ui\.layout\.Placeable\#kotlin\.Int\#kotlin\.Int\#kotlin\.Float\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.GraphicsLayerScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//Layout/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.layout\.MeasurePolicy/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutWithProvidedIntrinsicsUsage\. b/[0-9]+
WARN: Missing @param tag for parameter `y` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/placeWithLayer/androidx\.compose\.ui\.layout\.Placeable\#kotlin\.Int\#kotlin\.Int\#kotlin\.Float\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.GraphicsLayerScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//onSizeChanged/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.IntSize,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnSizeChangedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//Layout/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.layout\.MeasurePolicy/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutUsage\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//Layout/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.layout\.MeasurePolicy/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutWithProvidedIntrinsicsUsage\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//Layout/\#kotlin\.collections\.List\[kotlin\.Function[0-9]+\[kotlin\.Unit\]\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.layout\.MultiContentMeasurePolicy/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutWithMultipleContentsUsage\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//LookaheadScope/\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.LookaheadScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LookaheadLayoutCoordinatesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//SubcomposeLayout/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.SubcomposeIntermediateMeasureScope,androidx\.compose\.ui\.unit\.Constraints,androidx\.compose\.ui\.layout\.MeasureResult\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.SubcomposeMeasureScope,androidx\.compose\.ui\.unit\.Constraints,androidx\.compose\.ui\.layout\.MeasureResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.SubcomposeLayoutWithIntermediateMeasurePolicySample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//SubcomposeLayout/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.SubcomposeMeasureScope,androidx\.compose\.ui\.unit\.Constraints,androidx\.compose\.ui\.layout\.MeasureResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.SubcomposeLayoutSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//SubcomposeLayout/\#androidx\.compose\.ui\.layout\.SubcomposeLayoutState\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.SubcomposeMeasureScope,androidx\.compose\.ui\.unit\.Constraints,androidx\.compose\.ui\.layout\.MeasureResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.SubcomposeLayoutSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.modifier//modifierLocalOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierLocalParentChildCommunicationWithinLayoutNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.modifier//modifierLocalOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierLocalChildParentCommunicationWithinLayoutNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.modifier//modifierLocalOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierLocalParentChildCommunicationInterLayoutNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.modifier//modifierLocalOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierLocalChildParentCommunicationInterLayoutNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/CompositionLocalConsumerModifierNode/currentValueOf/androidx\.compose\.ui\.node\.CompositionLocalConsumerModifierNode\#androidx\.compose\.runtime\.CompositionLocal\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CompositionLocalConsumingModifierObserverNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node//currentValueOf/androidx\.compose\.ui\.node\.CompositionLocalConsumerModifierNode\#androidx\.compose\.runtime\.CompositionLocal\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CompositionLocalConsumingModifierObserverNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.platform//debugInspectorInfo/\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectableModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.platform/SoftwareKeyboardController/hide/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.SoftwareKeyboardControllerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.platform//rememberNestedScrollInteropConnection/\#android\.view\.View/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ComposeInCooperatingViewNestedScrollInteropSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.platform//inspectable/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectableModifierSample\. b/[0-9]+
WARN: Missing @param tag for parameter `position` of function androidx\.compose\.ui\.layout/Placeable\.PlacementScope/placeWithLayer/androidx\.compose\.ui\.layout\.Placeable\#androidx\.compose\.ui\.unit\.IntOffset\#kotlin\.Float\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.GraphicsLayerScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout//onPlaced/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.LayoutCoordinates,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnPlaced\. b/[0-9]+
WARN: Missing @param tag for parameter `onSelectAllRequested` of function androidx\.compose\.ui\.platform/TextToolbar/showMenu/\#androidx\.compose\.ui\.geometry\.Rect\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.platform/SoftwareKeyboardController/show/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.SoftwareKeyboardControllerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.res//painterResource/\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PainterResourceSample\. b/[0-9]+
WARN: Missing @param tag for parameter `block` of function androidx\.compose\.ui\.test//runAndroidComposeUiTest/\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.AndroidComposeUiTest\[TypeParam\(bounds=\[androidx\.activity\.ComponentActivity\]\)\],kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `activityClass` of function androidx\.compose\.ui\.test//runAndroidComposeUiTest/\#java\.lang\.Class\[TypeParam\(bounds=\[androidx\.activity\.ComponentActivity\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.AndroidComposeUiTest\[TypeParam\(bounds=\[androidx\.activity\.ComponentActivity\]\)\],kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `block` of function androidx\.compose\.ui\.test//runAndroidComposeUiTest/\#java\.lang\.Class\[TypeParam\(bounds=\[androidx\.activity\.ComponentActivity\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.AndroidComposeUiTest\[TypeParam\(bounds=\[androidx\.activity\.ComponentActivity\]\)\],kotlin\.Unit\]/PointingToDeclaration/
@@ -153,21 +269,61 @@
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.ui\.test//onNodeWithContentDescription/androidx\.compose\.ui\.test\.SemanticsNodeInteractionsProvider\#kotlin\.String\#kotlin\.Boolean\#kotlin\.Boolean\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `testTag` of function androidx\.compose\.ui\.test//onNodeWithTag/androidx\.compose\.ui\.test\.SemanticsNodeInteractionsProvider\#kotlin\.String\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `text` of function androidx\.compose\.ui\.test//onNodeWithText/androidx\.compose\.ui\.test\.SemanticsNodeInteractionsProvider\#kotlin\.String\#kotlin\.Boolean\#kotlin\.Boolean\#kotlin\.Boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.test//performGesture/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.GestureScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.gestureClick\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test//performMouseInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.MouseInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.mouseInputClick\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test//performMouseInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.MouseInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.mouseInputScrollWhileDown\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test//performTouchInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.TouchInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.touchInputSwipeUp\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test//performTouchInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.TouchInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.touchInputClickOffCenter\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test//performTouchInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.TouchInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.touchInputAssertDuringClick\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test//performTouchInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.TouchInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.touchInputClickAndDrag\. b/[0-9]+
+WARNING: no common source set for DParameter androidx\.compose\.ui\.test\.junit[0-9]+//createComposeRule/\#kotlin\.coroutines\.CoroutineContext/PointingToCallableParameters\([0-9]+\)/! Falling back to jvmMain sourceSet! This is only defensible if every sourceSet depends onjvmMain! This is a bug in dackka: b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder/addStringAnnotation/\#kotlin\.String\#kotlin\.String\#kotlin\.Int\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringAddStringAnnotationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString/AnnotatedString/\#kotlin\.String\#kotlin\.collections\.List\[androidx\.compose\.ui\.text\.AnnotatedString\.Range\[androidx\.compose\.ui\.text\.SpanStyle\]\]\#kotlin\.collections\.List\[androidx\.compose\.ui\.text\.AnnotatedString\.Range\[androidx\.compose\.ui\.text\.ParagraphStyle\]\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringConstructorSample\. b/[0-9]+
+WARN: Multiple sources exist for Paragraph\. Artifact ID metadata will not be displayed
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/TextMeasurer/measure/\#kotlin\.String\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Boolean\#kotlin\.Int\#androidx\.compose\.ui\.unit\.Constraints\#androidx\.compose\.ui\.unit\.LayoutDirection\#androidx\.compose\.ui\.unit\.Density\#androidx\.compose\.ui\.text\.font\.FontFamily\.Resolver\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.measureTextStringWithConstraints\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder/withStyle/androidx\.compose\.ui\.text\.AnnotatedString\.Builder\#androidx\.compose\.ui\.text\.SpanStyle\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.AnnotatedString\.Builder,TypeParam\(bounds=\[kotlin\.Any\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderWithStyleSample\. b/[0-9]+
WARN: Missing @param tag for parameter `matcher` of function androidx\.compose\.ui\.test/SemanticsNodeInteractionsProvider/onAllNodes/\#androidx\.compose\.ui\.test\.SemanticsMatcher\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `matcher` of function androidx\.compose\.ui\.test/SemanticsNodeInteractionsProvider/onNode/\#androidx\.compose\.ui\.test\.SemanticsMatcher\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `condition` of function androidx\.compose\.ui\.test/MainTestClock/advanceTimeUntil/\#kotlin\.Long\#kotlin\.Function[0-9]+\[kotlin\.Boolean\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/SemanticsNodeInteraction/performMouseInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.MouseInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.mouseInputClick\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/SemanticsNodeInteraction/performMouseInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.MouseInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.mouseInputScrollWhileDown\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/GestureScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.gestureClick\. b/[0-9]+
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.ui\.test/SemanticsNodeInteractionsProvider/onAllNodesWithContentDescription/androidx\.compose\.ui\.test\.SemanticsNodeInteractionsProvider\#kotlin\.String\#kotlin\.Boolean\#kotlin\.Boolean\#kotlin\.Boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/GestureScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.gestureSwipeUp\. b/[0-9]+
WARN: Missing @param tag for parameter `testTag` of function androidx\.compose\.ui\.test/SemanticsNodeInteractionsProvider/onAllNodesWithTag/androidx\.compose\.ui\.test\.SemanticsNodeInteractionsProvider\#kotlin\.String\#kotlin\.Boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/GestureScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.gestureLShape\. b/[0-9]+
WARN: Missing @param tag for parameter `text` of function androidx\.compose\.ui\.test/SemanticsNodeInteractionsProvider/onAllNodesWithText/androidx\.compose\.ui\.test\.SemanticsNodeInteractionsProvider\#kotlin\.String\#kotlin\.Boolean\#kotlin\.Boolean\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.ui\.test/SemanticsNodeInteractionsProvider/onNodeWithContentDescription/androidx\.compose\.ui\.test\.SemanticsNodeInteractionsProvider\#kotlin\.String\#kotlin\.Boolean\#kotlin\.Boolean\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `testTag` of function androidx\.compose\.ui\.test/SemanticsNodeInteractionsProvider/onNodeWithTag/androidx\.compose\.ui\.test\.SemanticsNodeInteractionsProvider\#kotlin\.String\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `text` of function androidx\.compose\.ui\.test/SemanticsNodeInteractionsProvider/onNodeWithText/androidx\.compose\.ui\.test\.SemanticsNodeInteractionsProvider\#kotlin\.String\#kotlin\.Boolean\#kotlin\.Boolean\#kotlin\.Boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/SemanticsNodeInteraction/performTouchInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.TouchInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.touchInputSwipeUp\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/SemanticsNodeInteraction/performTouchInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.TouchInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.touchInputClickOffCenter\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/SemanticsNodeInteraction/performTouchInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.TouchInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.touchInputAssertDuringClick\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/SemanticsNodeInteraction/performTouchInput/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.TouchInjectionScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.touchInputClickAndDrag\. b/[0-9]+
WARN: Missing @param tag for parameter `matcher` of function androidx\.compose\.ui\.test\.junit[0-9]+/AndroidComposeTestRule/onAllNodes/\#androidx\.compose\.ui\.test\.SemanticsMatcher\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `matcher` of function androidx\.compose\.ui\.test\.junit[0-9]+/AndroidComposeTestRule/onNode/\#androidx\.compose\.ui\.test\.SemanticsMatcher\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `variationSettings` of function androidx\.compose\.ui\.text\.font/AndroidFont/AndroidFont/\#androidx\.compose\.ui\.text\.font\.FontLoadingStrategy\#androidx\.compose\.ui\.text\.font\.AndroidFont\.TypefaceLoader\#androidx\.compose\.ui\.text\.font\.FontVariation\.Settings/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.font/FontFamily\.Companion/Monospace/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.FontFamilyMonospaceSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.font/FontFamily\.Companion/SansSerif/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.FontFamilySansSerifSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.font/FontFamily\.Companion/Serif/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.FontFamilySerifSample\. b/[0-9]+
+WARN: Multiple sources exist for PlatformTextInputPlugin\. Artifact ID metadata will not be displayed
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.input/PasswordVisualTransformation/filter/\#androidx\.compose\.ui\.text\.AnnotatedString/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.passwordFilter\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.input/VisualTransformation/filter/\#androidx\.compose\.ui\.text\.AnnotatedString/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.passwordFilter\. b/[0-9]+
+WARN: Multiple sources exist for PlatformTextInputAdapter\. Artifact ID metadata will not be displayed
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.input/PasswordVisualTransformation/filter/\#androidx\.compose\.ui\.text\.AnnotatedString/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.creditCardFilter\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.input/VisualTransformation/filter/\#androidx\.compose\.ui\.text\.AnnotatedString/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.creditCardFilter\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/TextDecoration\.Companion/LineThrough/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextDecorationLineThroughSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/TextDecoration\.Companion/combine/\#kotlin\.collections\.List\[androidx\.compose\.ui\.text\.style\.TextDecoration\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextDecorationCombinedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/TextOverflow\.Companion/Clip/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextOverflowClipSample\. b/[0-9]+
+WARN: Multiple sources exist for LineBreak\. Artifact ID metadata will not be displayed
+WARN: Multiple sources exist for TextMotion\. Artifact ID metadata will not be displayed
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/TextDecoration/plus/\#androidx\.compose\.ui\.text\.style\.TextDecoration/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextDecorationCombinedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/TextDecoration\.Companion/Underline/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextDecorationUnderlineSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/TextOverflow\.Companion/Ellipsis/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextOverflowEllipsisSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/TextOverflow\.Companion/Visible/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextOverflowVisibleFixedSizeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/TextOverflow\.Companion/Visible/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextOverflowVisibleMinHeightSample\. b/[0-9]+
WARN: Missing @param tag for parameter `motionScene` of function androidx\.constraintlayout\.compose//MotionCarousel/\#androidx\.constraintlayout\.compose\.MotionScene\#kotlin\.Int\#kotlin\.Int\#kotlin\.String\#kotlin\.String\#kotlin\.String\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.constraintlayout\.compose\.MotionCarouselScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.glance\.appwidget//AndroidRemoteViews/\#android\.widget\.RemoteViews\#kotlin\.Int\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
-WARN: Missing @param tag for parameter `rendererName` of function androidx\.media[0-9]+\.exoplayer/ExoPlaybackException/createForRenderer/\#java\.lang\.Throwable\#java\.lang\.String\#int\#androidx\.media[0-9]+\.common\.Format\#int\#boolean\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `output` of function androidx\.glance\.appwidget\.proto/LayoutProtoSerializer/writeTo/\#androidx\.glance\.appwidget\.proto\.LayoutProto\.LayoutConfig\#java\.io\.OutputStream/PointingToDeclaration/
WARN: Missing @param tag for parameter `factory` of function androidx\.lifecycle\.viewmodel\.compose//viewModel/\#java\.lang\.Class\[TypeParam\(bounds=\[androidx\.lifecycle\.ViewModel\]\)\]\#androidx\.lifecycle\.ViewModelStoreOwner\#kotlin\.String\?\#androidx\.lifecycle\.ViewModelProvider\.Factory\?\#androidx\.lifecycle\.viewmodel\.CreationExtras/PointingToDeclaration/
WARN: Failed to resolve `@see PagingSource\.invalidate`!
@@ -191,10 +347,14 @@
WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material//Stepper/\#kotlin\.Float\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Unit\]\#kotlin\.Int\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.BoxScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material//Stepper/\#kotlin\.Int\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Unit\]\#kotlin\.ranges\.IntProgression\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.BoxScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material//TitleCard/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.painter\.Painter\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
+WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material[0-9]+//Button/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.wear\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material[0-9]+//ChildButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.wear\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material[0-9]+//FilledTonalButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.wear\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material[0-9]+//Button/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.wear\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material[0-9]+//ChildButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.wear\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material[0-9]+//FilledTonalButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.wear\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material[0-9]+//MaterialTheme/\#androidx\.wear\.compose\.material[0-9]+\.ColorScheme\#androidx\.wear\.compose\.material[0-9]+\.Typography\#androidx\.wear\.compose\.material[0-9]+\.Shapes\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material[0-9]+//OutlinedButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.wear\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.wear\.compose\.material[0-9]+//OutlinedButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.wear\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `enabled` of function androidx\.wear\.compose\.material[0-9]+/ButtonDefaults/outlinedButtonBorder/\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/
WARN: Missing @param tag for parameter `enabled` of function androidx\.wear\.compose\.material[0-9]+/IconButtonDefaults/outlinedIconButtonBorder/\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/
@@ -219,7 +379,99 @@
Did you make a typo\? Are you trying to refer to something not visible to users\? in declaration of UserStyle in file \$OUT_DIR\/androidx\/docs\-public\/build\/unzippedJvmSources\/androidx\/wear\/watchface\/style\/CurrentUserStyleRepository\.kt at line [0-9]+\.
Did you make a typo\? Are you trying to refer to something not visible to users\? in declaration of UserStyle in file \$OUT_DIR\/androidx\/docs\-tip\-of\-tree\/build\/unzippedJvmSources\/androidx\/wear\/watchface\/style\/CurrentUserStyleRepository\.kt at line [0-9]+\.
WARN: Missing @param tag for parameter `matchHeightConstraintsFirst` of function androidx\.compose\.ui/Modifier/aspectRatio/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.Boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/background/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Brush\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DrawBackgroundShapedBrush\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/basicMarquee/androidx\.compose\.ui\.Modifier\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeAnimationMode\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeSpacing\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BasicMarqueeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/basicMarquee/androidx\.compose\.ui\.Modifier\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeAnimationMode\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeSpacing\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BasicFocusableMarqueeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/basicMarquee/androidx\.compose\.ui\.Modifier\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeAnimationMode\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeSpacing\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BasicMarqueeWithFadedEdgesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/blur/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.draw\.BlurredEdgeTreatment/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.BlurSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/blur/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.draw\.BlurredEdgeTreatment/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ImageBlurSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/blur/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.draw\.BlurredEdgeTreatment/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.BlurSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/blur/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.draw\.BlurredEdgeTreatment/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ImageBlurSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/border/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.BorderStroke\#androidx\.compose\.ui\.graphics\.Shape/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BorderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/border/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Shape/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BorderSampleWithDataClass\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/border/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Brush\#androidx\.compose\.ui\.graphics\.Shape/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BorderSampleWithBrush\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/border/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Brush\#androidx\.compose\.ui\.graphics\.Shape/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BorderSampleWithDynamicData\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/bringIntoViewRequester/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.relocation\.BringIntoViewRequester/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/bringIntoViewResponder/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.relocation\.BringIntoViewResponder/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/clickable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ClickableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/clickable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ClickableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/combinedClickable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.String\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ClickableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/combinedClickable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.String\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ClickableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/composed/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/composed/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierWithArgumentsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierWithArgumentsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierWithArgumentsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierWithArgumentsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierWithArgumentsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/draggable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.gestures\.DraggableState\#androidx\.compose\.foundation\.gestures\.Orientation\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\?\#kotlin\.Boolean\#kotlin\.coroutines\.SuspendFunction[0-9]+\[kotlinx\.coroutines\.CoroutineScope,androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[kotlinx\.coroutines\.CoroutineScope,kotlin\.Float,kotlin\.Unit\]\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DraggableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/drawWithCache/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.draw\.CacheDrawScope,androidx\.compose\.ui\.draw\.DrawResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.DrawWithCacheModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/drawWithCache/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.draw\.CacheDrawScope,androidx\.compose\.ui\.draw\.DrawResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.DrawWithCacheModifierStateParameterSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/drawWithCache/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.draw\.CacheDrawScope,androidx\.compose\.ui\.draw\.DrawResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.DrawWithCacheContentSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onFocusChanged/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.focus\.FocusState,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.FocusableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/focusTarget/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.FocusableSampleUsingLowerLevelFocusTarget\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/focusOrder/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.focus\.FocusOrder,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/focusProperties/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.focus\.FocusProperties,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.FocusPropertiesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/focusRequester/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.focus\.FocusRequester/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RequestFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/focusOrder/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.focus\.FocusRequester/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/focusGroup/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.FocusGroupSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/focusGroup/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.FocusableFocusGroupSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/focusable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.FocusableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/graphicsLayer/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TransformOrigin\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.RenderEffect\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.CompositingStrategy/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ChangeOpacity\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/graphicsLayer/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TransformOrigin\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.RenderEffect\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.CompositingStrategy/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CompositingStrategyModulateAlpha\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/graphicsLayer/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.GraphicsLayerScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.AnimateFadeIn\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/hoverable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.HoverableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/indication/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.interaction\.InteractionSource\#androidx\.compose\.foundation\.Indication\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.IndicationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/inspectable/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectableModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/height/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.IntrinsicSize/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.MatchParentDividerForText\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/height/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.IntrinsicSize/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.MatchParentDividerForAspectRatio\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/width/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.IntrinsicSize/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SameWidthBoxes\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/width/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.IntrinsicSize/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SameWidthTextBoxes\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onKeyEvent/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.key\.KeyEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onPreviewKeyEvent/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.key\.KeyEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/layoutId/androidx\.compose\.ui\.Modifier\#kotlin\.Any/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutTagChildrenUsage\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/layout/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.MeasureScope,androidx\.compose\.ui\.layout\.Measurable,androidx\.compose\.ui\.unit\.Constraints,androidx\.compose\.ui\.layout\.MeasureResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ConvenienceLayoutModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/intermediateLayout/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.IntermediateMeasureScope,androidx\.compose\.ui\.layout\.Measurable,androidx\.compose\.ui\.unit\.Constraints,androidx\.compose\.ui\.layout\.MeasureResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.IntermediateLayoutSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/magnifier/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.Density,androidx\.compose\.ui\.geometry\.Offset\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.Density,androidx\.compose\.ui\.geometry\.Offset\]\#kotlin\.Float\#androidx\.compose\.foundation\.MagnifierStyle\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.DpSize,kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.MagnifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/nestedScroll/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollConnection\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollDispatcher\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.NestedScrollConnectionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/nestedScroll/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollConnection\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollDispatcher\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.NestedScrollDispatcherSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/absoluteOffset/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.AbsoluteOffsetModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/absoluteOffset/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.Density,androidx\.compose\.ui\.unit\.IntOffset\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.AbsoluteOffsetPxModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/offset/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.OffsetModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/offset/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.Density,androidx\.compose\.ui\.unit\.IntOffset\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.OffsetPxModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onGloballyPositioned/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.LayoutCoordinates,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnGloballyPositioned\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onPlaced/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.LayoutCoordinates,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnPlaced\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onSizeChanged/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.IntSize,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnSizeChangedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/overscroll/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.OverscrollEffect/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.OverscrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/absolutePadding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.AbsolutePaddingModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/padding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/padding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SymmetricPaddingModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/padding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingAllModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/padding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.PaddingValues/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingValuesModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/paint/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.painter\.Painter\#kotlin\.Boolean\#androidx\.compose\.ui\.Alignment\#androidx\.compose\.ui\.layout\.ContentScale\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.ColorFilter\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PainterModifierSample\. b/[0-9]+
WARN: Missing @param tag for parameter `painter` of function androidx\.compose\.ui/Modifier/paint/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.painter\.Painter\#kotlin\.Boolean\#androidx\.compose\.ui\.Alignment\#androidx\.compose\.ui\.layout\.ContentScale\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.ColorFilter\?/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/pointerHoverIcon/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.input\.pointer\.PointerIcon\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PointerIconSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/progressSemantics/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DeterminateProgressSemanticsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/progressSemantics/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.IndeterminateProgressSemanticsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/pullRefreshIndicatorTransform/androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.pullrefresh\.PullRefreshState\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.PullRefreshIndicatorTransformSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/pullRefresh/androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.pullrefresh\.PullRefreshState\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.PullRefreshSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/pullRefresh/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Float\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[kotlin\.Float,kotlin\.Float\]\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.CustomPullRefreshSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onPreRotaryScrollEvent/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.rotary\.RotaryScrollEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PreRotaryEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onRotaryScrollEvent/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.rotary\.RotaryScrollEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RotaryEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onRotaryScrollEvent/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.rotary\.RotaryScrollEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PreRotaryEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/rotate/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RotateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/scale/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ScaleNonUniformSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/scale/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ScaleUniformSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/horizontalScroll/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.ScrollState\#kotlin\.Boolean\#androidx\.compose\.foundation\.gestures\.FlingBehavior\?\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.HorizontalScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/verticalScroll/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.ScrollState\#kotlin\.Boolean\#androidx\.compose\.foundation\.gestures\.FlingBehavior\?\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.VerticalScrollExample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/scrollable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.gestures\.ScrollableState\#androidx\.compose\.foundation\.gestures\.Orientation\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.foundation\.gestures\.FlingBehavior\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ScrollableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/scrollable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.gestures\.ScrollableState\#androidx\.compose\.foundation\.gestures\.Orientation\#androidx\.compose\.foundation\.OverscrollEffect\?\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.foundation\.gestures\.FlingBehavior\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ScrollableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/selectable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SelectableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/selectable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SelectableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/shadow/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ShadowSample\. b/[0-9]+
WARN: Missing @param tag for parameter `cookieManager` of function androidx\.webkit/CookieManagerCompat/getCookieInfo/\#android\.webkit\.CookieManager\#java\.lang\.String/PointingToDeclaration/
WARN: Missing @param tag for parameter `settings` of function androidx\.webkit/WebSettingsCompat/setAlgorithmicDarkeningAllowed/\#android\.webkit\.WebSettings\#boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `settings` of function androidx\.webkit/WebSettingsCompat/setDisabledActionModeMenuItems/\#android\.webkit\.WebSettings\#int/PointingToDeclaration/
@@ -232,6 +484,61 @@
WARN: Missing @param tag for parameter `webview` of function androidx\.webkit/WebViewCompat/removeWebMessageListener/\#android\.webkit\.WebView\#java\.lang\.String/PointingToDeclaration/
WARN: Missing @param tag for parameter `ambientColor` of function androidx\.compose\.ui/Modifier/shadow/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/
WARN: Missing @param tag for parameter `spotColor` of function androidx\.compose\.ui/Modifier/shadow/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/defaultMinSize/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.DefaultMinSizeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/fillMaxHeight/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleFillHeightModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/fillMaxHeight/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.FillHalfHeightModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/fillMaxSize/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleFillModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/fillMaxSize/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.FillHalfSizeModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/fillMaxWidth/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleFillWidthModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/fillMaxWidth/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.FillHalfWidthModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/height/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleHeightModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/requiredHeight/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleRequiredHeightModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/requiredSize/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleRequiredSizeModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/requiredWidth/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleRequiredWidthModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/size/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleSizeModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/size/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleSizeModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/size/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpSize/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleSizeModifierWithDpSize\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/width/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleWidthModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/wrapContentHeight/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\.Vertical\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleWrapContentVerticallyAlignedModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/wrapContentSize/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleWrapContentAlignedModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/wrapContentWidth/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\.Horizontal\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleWrapContentHorizontallyAlignedModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onInterceptKeyBeforeSoftKeyboard/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.key\.KeyEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onPreInterceptKeyBeforeSoftKeyboard/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.key\.KeyEvent,kotlin\.Boolean\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.keyedPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.rememberedUpdatedParameterPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.keyedPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.rememberedUpdatedParameterPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.keyedPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/pointerInput/androidx\.compose\.ui\.Modifier\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.rememberedUpdatedParameterPointerInputModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/swipeable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.SwipeableState\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.collections\.Map\[kotlin\.Float,TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.compose\.foundation\.gestures\.Orientation\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\?\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),androidx\.compose\.material\.ThresholdConfig\]\#androidx\.compose\.material\.ResistanceConfig\?\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SwipeableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/toggleable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ToggleableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/toggleable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ToggleableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/triStateToggleable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.state\.ToggleableState\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.TriStateToggleableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/triStateToggleable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.state\.ToggleableState\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.TriStateToggleableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/transformable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.gestures\.TransformableState\#kotlin\.Boolean\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.TransformableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/transformable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.gestures\.TransformableState\#kotlin\.Function[0-9]+\[kotlin\.Boolean\]\#kotlin\.Boolean\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.TransformableSampleInsideScroll\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/imeNestedScroll/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.windowInsetsNestedScrollDemo\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/captionBarPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.captionBarPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/consumeWindowInsets/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.consumedInsetsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/consumeWindowInsets/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.PaddingValues/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.consumedInsetsPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/displayCutoutPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.displayCutoutPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/imePadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.imePaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/mandatorySystemGesturesPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.mandatorySystemGesturesPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/navigationBarsPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.statusBarsAndNavigationBarsPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/onConsumedWindowInsetsChanged/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.WindowInsets,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.withConsumedInsetsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/safeContentPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.safeContentPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/safeDrawingPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.safeDrawingPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/safeGesturesPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.safeGesturesPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/statusBarsPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.statusBarsAndNavigationBarsPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/systemBarsPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.systemBarsPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/systemGesturesPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.systemGesturesPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/waterfallPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.waterfallPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/windowInsetsPadding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/windowInsetsBottomHeight/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsBottomHeightSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/windowInsetsEndWidth/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsEndWidthSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/windowInsetsStartWidth/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsStartWidthSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/windowInsetsTopHeight/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsTopHeightSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/zIndex/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ZIndexModifierSample\. b/[0-9]+
@param copySelectedOptions
in DClass Builder
Did you make a typo\? Are you trying to refer to something not visible to users\? in declaration of Builder in file \$OUT_DIR\/androidx\/docs\-public\/build\/unzippedJvmSources\/androidx\/wear\/watchface\/ComplicationSlot\.kt at line [0-9]+\.
@@ -244,12 +551,109 @@
WARNING: link to @throws type IOException does not resolve\. Is it from a package that the containing file does not import\? Is docs inherited to an un\-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\.`@throws java\.io\.IOException under some conditions\. This was observed in Throws\(root=CustomDocTag\(children=\[P\(children=\[Text\(body=when an exception is encountered when writing data to disk, children=\[\], params=\{\}\)\], params=\{\}\)\], params=\{\}, name=MARKDOWN_FILE\), name=IOException, exceptionAddress=null\)\.`
WARNING: link to @throws type ComposeTimeoutException does not resolve\. Is it from a package that the containing file does not import\? Is docs inherited to an un\-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\.`@throws java\.io\.IOException under some conditions\. This was observed in Throws\(root=CustomDocTag\(children=\[P\(children=\[Text\(body=If the condition is not satisfied after , children=\[\], params=\{\}\), DocumentationLink\(dri=androidx\.compose\.ui\.test\.junit[0-9]+/AndroidComposeTestRule/waitUntil/\#kotlin\.Long\#kotlin\.Function[0-9]+\[kotlin\.Boolean\]/PointingToCallableParameters\([0-9]+\)/, children=\[Text\(body=timeoutMillis, children=\[\], params=\{\}\)\], params=\{href=\[timeoutMillis\]\}\), Text\(body=\., children=\[\], params=\{\}\)\], params=\{\}\)\], params=\{\}, name=MARKDOWN_FILE\), name=ComposeTimeoutException, exceptionAddress=null\)\.`
WARN: Missing @param tag for parameter `text` of function androidx\.compose\.ui\.text//AnnotatedString/\#kotlin\.String\#androidx\.compose\.ui\.text\.SpanStyle\#androidx\.compose\.ui\.text\.ParagraphStyle\?/PointingToDeclaration/
+WARN: Multiple sources exist for PlatformSpanStyle\. Artifact ID metadata will not be displayed
+WARNING: no common sourceSet for androidx\.compose\.ui\.text//drawText/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#androidx\.compose\.ui\.text\.TextLayoutResult\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.geometry\.Offset\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.Shadow\?\#androidx\.compose\.ui\.text\.style\.TextDecoration\?\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\?\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.DrawTextMeasureInLayoutSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/SpanStyle/SpanStyle/\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.font\.FontWeight\?\#androidx\.compose\.ui\.text\.font\.FontStyle\?\#androidx\.compose\.ui\.text\.font\.FontSynthesis\?\#androidx\.compose\.ui\.text\.font\.FontFamily\?\#kotlin\.String\?\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.style\.BaselineShift\?\#androidx\.compose\.ui\.text\.style\.TextGeometricTransform\?\#androidx\.compose\.ui\.text\.intl\.LocaleList\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.text\.style\.TextDecoration\?\#androidx\.compose\.ui\.graphics\.Shadow\?\#androidx\.compose\.ui\.text\.PlatformSpanStyle\?\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.SpanStyleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder/addTtsAnnotation/\#androidx\.compose\.ui\.text\.TtsAnnotation\#kotlin\.Int\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringAddStringAnnotationSample\. b/[0-9]+
+WARN: Multiple sources exist for PlatformTextStyle\. Artifact ID metadata will not be displayed
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/SpanStyle/SpanStyle/\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.font\.FontWeight\?\#androidx\.compose\.ui\.text\.font\.FontStyle\?\#androidx\.compose\.ui\.text\.font\.FontSynthesis\?\#androidx\.compose\.ui\.text\.font\.FontFamily\?\#kotlin\.String\?\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.style\.BaselineShift\?\#androidx\.compose\.ui\.text\.style\.TextGeometricTransform\?\#androidx\.compose\.ui\.text\.intl\.LocaleList\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.text\.style\.TextDecoration\?\#androidx\.compose\.ui\.graphics\.Shadow\?\#androidx\.compose\.ui\.text\.PlatformSpanStyle\?\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text//drawText/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#androidx\.compose\.ui\.text\.TextLayoutResult\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.geometry\.Offset\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.Shadow\?\#androidx\.compose\.ui\.text\.style\.TextDecoration\?\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\?\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.DrawTextDrawWithCacheSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder/addUrlAnnotation/\#androidx\.compose\.ui\.text\.UrlAnnotation\#kotlin\.Int\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringAddStringAnnotationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/TextStyle/TextStyle/\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.font\.FontWeight\?\#androidx\.compose\.ui\.text\.font\.FontStyle\?\#androidx\.compose\.ui\.text\.font\.FontSynthesis\?\#androidx\.compose\.ui\.text\.font\.FontFamily\?\#kotlin\.String\?\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.style\.BaselineShift\?\#androidx\.compose\.ui\.text\.style\.TextGeometricTransform\?\#androidx\.compose\.ui\.text\.intl\.LocaleList\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.text\.style\.TextDecoration\?\#androidx\.compose\.ui\.graphics\.Shadow\?\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\?\#androidx\.compose\.ui\.text\.style\.TextAlign\?\#androidx\.compose\.ui\.text\.style\.TextDirection\?\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.style\.TextIndent\?\#androidx\.compose\.ui\.text\.PlatformTextStyle\?\#androidx\.compose\.ui\.text\.style\.LineHeightStyle\?\#androidx\.compose\.ui\.text\.style\.LineBreak\?\#androidx\.compose\.ui\.text\.style\.Hyphens\?\#androidx\.compose\.ui\.text\.style\.TextMotion\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextStyleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text//drawText/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#androidx\.compose\.ui\.text\.TextMeasurer\#androidx\.compose\.ui\.text\.AnnotatedString\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.collections\.List\[androidx\.compose\.ui\.text\.AnnotatedString\.Range\[androidx\.compose\.ui\.text\.Placeholder\]\]\#androidx\.compose\.ui\.geometry\.Size\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.DrawTextAnnotatedStringSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/SpanStyle/SpanStyle/\#androidx\.compose\.ui\.graphics\.Brush\?\#kotlin\.Float\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.font\.FontWeight\?\#androidx\.compose\.ui\.text\.font\.FontStyle\?\#androidx\.compose\.ui\.text\.font\.FontSynthesis\?\#androidx\.compose\.ui\.text\.font\.FontFamily\?\#kotlin\.String\?\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.style\.BaselineShift\?\#androidx\.compose\.ui\.text\.style\.TextGeometricTransform\?\#androidx\.compose\.ui\.text\.intl\.LocaleList\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.text\.style\.TextDecoration\?\#androidx\.compose\.ui\.graphics\.Shadow\?\#androidx\.compose\.ui\.text\.PlatformSpanStyle\?\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.SpanStyleBrushSample\. b/[0-9]+
+WARN: Multiple sources exist for PlatformParagraphStyle\. Artifact ID metadata will not be displayed
WARN: Missing @param tag for parameter `text` of function androidx\.compose\.ui\.text//AnnotatedString/\#kotlin\.String\#androidx\.compose\.ui\.text\.ParagraphStyle/PointingToDeclaration/
WARN: Missing @param tag for parameter `text` of function androidx\.compose\.ui\.text/AnnotatedString\.Builder/append/\#kotlin\.CharSequence\?\#kotlin\.Int\#kotlin\.Int/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/TextStyle/TextStyle/\#androidx\.compose\.ui\.graphics\.Brush\?\#kotlin\.Float\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.font\.FontWeight\?\#androidx\.compose\.ui\.text\.font\.FontStyle\?\#androidx\.compose\.ui\.text\.font\.FontSynthesis\?\#androidx\.compose\.ui\.text\.font\.FontFamily\?\#kotlin\.String\?\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.style\.BaselineShift\?\#androidx\.compose\.ui\.text\.style\.TextGeometricTransform\?\#androidx\.compose\.ui\.text\.intl\.LocaleList\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.text\.style\.TextDecoration\?\#androidx\.compose\.ui\.graphics\.Shadow\?\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\?\#androidx\.compose\.ui\.text\.style\.TextAlign\?\#androidx\.compose\.ui\.text\.style\.TextDirection\?\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.style\.TextIndent\?\#androidx\.compose\.ui\.text\.PlatformTextStyle\?\#androidx\.compose\.ui\.text\.style\.LineHeightStyle\?\#androidx\.compose\.ui\.text\.style\.LineBreak\?\#androidx\.compose\.ui\.text\.style\.Hyphens\?\#androidx\.compose\.ui\.text\.style\.TextMotion\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextStyleBrushSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/TextMeasurer/measure/\#androidx\.compose\.ui\.text\.AnnotatedString\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.collections\.List\[androidx\.compose\.ui\.text\.AnnotatedString\.Range\[androidx\.compose\.ui\.text\.Placeholder\]\]\#androidx\.compose\.ui\.unit\.Constraints\#androidx\.compose\.ui\.unit\.LayoutDirection\#androidx\.compose\.ui\.unit\.Density\#androidx\.compose\.ui\.text\.font\.FontFamily\.Resolver\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.measureTextAnnotatedString\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text//drawText/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#androidx\.compose\.ui\.text\.TextMeasurer\#kotlin\.String\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Boolean\#kotlin\.Int\#androidx\.compose\.ui\.geometry\.Size\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.DrawTextStyledSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder/pushStringAnnotation/\#kotlin\.String\#kotlin\.String/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderPushStringAnnotationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder/withStyle/androidx\.compose\.ui\.text\.AnnotatedString\.Builder\#androidx\.compose\.ui\.text\.ParagraphStyle\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.AnnotatedString\.Builder,TypeParam\(bounds=\[kotlin\.Any\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderWithStyleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text//buildAnnotatedString/\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.AnnotatedString\.Builder,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderLambdaSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder/appendInlineContent/androidx\.compose\.ui\.text\.AnnotatedString\.Builder\#kotlin\.String\#kotlin\.String/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.InlineTextContentSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/SpanStyle/SpanStyle/\#androidx\.compose\.ui\.graphics\.Brush\?\#kotlin\.Float\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.font\.FontWeight\?\#androidx\.compose\.ui\.text\.font\.FontStyle\?\#androidx\.compose\.ui\.text\.font\.FontSynthesis\?\#androidx\.compose\.ui\.text\.font\.FontFamily\?\#kotlin\.String\?\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.text\.style\.BaselineShift\?\#androidx\.compose\.ui\.text\.style\.TextGeometricTransform\?\#androidx\.compose\.ui\.text\.intl\.LocaleList\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.text\.style\.TextDecoration\?\#androidx\.compose\.ui\.graphics\.Shadow\?\#androidx\.compose\.ui\.text\.PlatformSpanStyle\?\#androidx\.compose\.ui\.graphics\.drawscope\.DrawStyle\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text//withStyle/androidx\.compose\.ui\.text\.AnnotatedString\.Builder\#androidx\.compose\.ui\.text\.ParagraphStyle\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.AnnotatedString\.Builder,TypeParam\(bounds=\[kotlin\.Any\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderWithStyleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder/pushStyle/\#androidx\.compose\.ui\.text\.ParagraphStyle/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderPushParagraphStyleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text//withStyle/androidx\.compose\.ui\.text\.AnnotatedString\.Builder\#androidx\.compose\.ui\.text\.SpanStyle\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.AnnotatedString\.Builder,TypeParam\(bounds=\[kotlin\.Any\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderWithStyleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder/pushStyle/\#androidx\.compose\.ui\.text\.SpanStyle/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderPushSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder/pushTtsAnnotation/\#androidx\.compose\.ui\.text\.TtsAnnotation/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderPushStringAnnotationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder/pushUrlAnnotation/\#androidx\.compose\.ui\.text\.UrlAnnotation/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderPushStringAnnotationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.font/FontFamily\.Companion/Cursive/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.FontFamilyCursiveSample\. b/[0-9]+
WARN: Missing @param tag for parameter `text` of function androidx\.compose\.ui\.text/AnnotatedString\.Builder/append/\#androidx\.compose\.ui\.text\.AnnotatedString\#kotlin\.Int\#kotlin\.Int/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.text//drawText/androidx\.compose\.ui\.graphics\.drawscope\.DrawScope\#androidx\.compose\.ui\.text\.TextMeasurer\#kotlin\.String\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Boolean\#kotlin\.Int\#androidx\.compose\.ui\.geometry\.Size\#androidx\.compose\.ui\.graphics\.BlendMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.DrawTextSample\. b/[0-9]+
WARNING: link to @throws type Renderer\.GlesException does not resolve\. Is it from a package that the containing file does not import\? Is docs inherited to an un\-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\.`@throws java\.io\.IOException under some conditions\. This was observed in Throws\(root=CustomDocTag\(children=\[P\(children=\[Text\(body=If any GL calls fail during initialization\., children=\[\], params=\{\}\)\], params=\{\}\)\], params=\{\}, name=MARKDOWN_FILE\), name=Renderer\.GlesException, exceptionAddress=null\)\.`
WARNING: link to @throws type ServiceStartFailureException does not resolve\. Is it from a package that the containing file does not import\? Is docs inherited to an un\-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\.`@throws java\.io\.IOException under some conditions\. This was observed in Throws\(root=CustomDocTag\(children=\[P\(children=\[Text\(body=if the watchface dies during startup\., children=\[\], params=\{\}\)\], params=\{\}\)\], params=\{\}, name=MARKDOWN_FILE\), name=ServiceStartFailureException, exceptionAddress=null\)\.`
WARN: Sources for .+ is empty
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy/LazyListState/canScrollBackward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy/LazyItemScope/animateItemPlacement/androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntOffset\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ItemPlacementAnimationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy//LazyColumn/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.lazy\.LazyListState\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Boolean\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#androidx\.compose\.ui\.Alignment\.Horizontal\#androidx\.compose\.foundation\.gestures\.FlingBehavior\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.LazyListScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LazyColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy/LazyListState/canScrollForward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy/LazyListScope/stickyHeader/\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.LazyItemScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.StickyHeaderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy/LazyListState/firstVisibleItemIndex/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.UsingListScrollPositionForSideEffectSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy//LazyRow/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.lazy\.LazyListState\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Boolean\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#androidx\.compose\.ui\.Alignment\.Vertical\#androidx\.compose\.foundation\.gestures\.FlingBehavior\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.LazyListScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LazyRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy/LazyListState/firstVisibleItemIndex/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.UsingListScrollPositionInCompositionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy/LazyListState/layoutInfo/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.UsingListLayoutInfoForSideEffectSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/IntrinsicMeasureScope/isLookingAhead/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.animateContentSizeAfterLookaheadPass\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager//HorizontalPager/\#androidx\.compose\.foundation\.pager\.PagerState\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.pager\.PageSize\#kotlin\.Int\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.Alignment\.Vertical\#androidx\.compose\.foundation\.gestures\.snapping\.SnapFlingBehavior\#kotlin\.Boolean\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Any\]\?\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollConnection\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.pager\.PagerScope,kotlin\.Int,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.HorizontalPagerWithScrollableContent\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.relocation//BringIntoViewRequester/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.relocation/BringIntoViewRequester/bringIntoView/\#androidx\.compose\.ui\.geometry\.Rect\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.relocation//bringIntoViewRequester/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.relocation\.BringIntoViewRequester/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.relocation//BringIntoViewRequester/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringPartOfComposableIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.relocation/BringIntoViewRequester/bringIntoView/\#androidx\.compose\.ui\.geometry\.Rect\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringPartOfComposableIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.relocation//bringIntoViewResponder/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.relocation\.BringIntoViewResponder/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.selection//selectable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SelectableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.selection//selectable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SelectableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.selection//toggleable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ToggleableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.selection//toggleable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ToggleableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.selection//triStateToggleable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.state\.ToggleableState\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.TriStateToggleableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.selection//triStateToggleable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.state\.ToggleableState\#kotlin\.Boolean\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.TriStateToggleableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//BasicTextField/\#androidx\.compose\.ui\.text\.input\.TextFieldValue\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.input\.TextFieldValue,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.TextLayoutResult,kotlin\.Unit\]\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Brush\#kotlin\.Function[0-9]+\[kotlin\.Function[0-9]+\[kotlin\.Unit\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BasicTextFieldSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//BasicTextField/\#androidx\.compose\.ui\.text\.input\.TextFieldValue\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.input\.TextFieldValue,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.TextLayoutResult,kotlin\.Unit\]\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Brush\#kotlin\.Function[0-9]+\[kotlin\.Function[0-9]+\[kotlin\.Unit\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.PlaceholderBasicTextFieldSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//BasicTextField/\#androidx\.compose\.ui\.text\.input\.TextFieldValue\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.input\.TextFieldValue,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.TextLayoutResult,kotlin\.Unit\]\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Brush\#kotlin\.Function[0-9]+\[kotlin\.Function[0-9]+\[kotlin\.Unit\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.TextFieldWithIconSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//BasicTextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.TextLayoutResult,kotlin\.Unit\]\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Brush\#kotlin\.Function[0-9]+\[kotlin\.Function[0-9]+\[kotlin\.Unit\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BasicTextFieldWithStringSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//BasicTextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.TextLayoutResult,kotlin\.Unit\]\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Brush\#kotlin\.Function[0-9]+\[kotlin\.Function[0-9]+\[kotlin\.Unit\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.PlaceholderBasicTextFieldSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//BasicTextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.TextLayoutResult,kotlin\.Unit\]\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Brush\#kotlin\.Function[0-9]+\[kotlin\.Function[0-9]+\[kotlin\.Unit\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.TextFieldWithIconSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//BasicTextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.TextLayoutResult,kotlin\.Unit\]\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Brush\#kotlin\.Function[0-9]+\[kotlin\.Function[0-9]+\[kotlin\.Unit\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CreditCardSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//ClickableText/\#androidx\.compose\.ui\.text\.AnnotatedString\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.TextLayoutResult,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ClickableText\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//ClickableText/\#androidx\.compose\.ui\.text\.AnnotatedString\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.TextLayoutResult,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LongClickableText\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material/MaterialTheme/typography/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ThemeTextStyleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material/ButtonDefaults/IconSpacing/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ButtonWithIconSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material/TextFieldDefaults/TextFieldDecorationBox/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.interaction\.InteractionSource\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material\.TextFieldColors\#androidx\.compose\.foundation\.layout\.PaddingValues/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.CustomTextFieldBasedOnDecorationBox\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//BackdropScaffold/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.BackdropScaffoldState\#kotlin\.Boolean\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.SnackbarHostState,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.BackdropScaffoldSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//BadgedBox/\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.BoxScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.BoxScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.BottomNavigationItemWithBadge\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//BottomAppBar/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Shape\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SimpleBottomAppBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//BottomDrawer/\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.BottomDrawerState\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.BottomDrawerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//BottomNavigation/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.BottomNavigationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Checkbox/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.CheckboxColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.CheckboxSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Card/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ClickableCardSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Chip/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ChipColors\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ChipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//IconToggleButton/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.IconToggleButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//DatePicker/\#androidx\.compose\.material[0-9]+\.DatePickerState\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.DatePickerFormatter\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.DatePickerColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.DatePickerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//DatePicker/\#androidx\.compose\.material[0-9]+\.DatePickerState\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.DatePickerFormatter\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.DatePickerColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.DateInputSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//DatePicker/\#androidx\.compose\.material[0-9]+\.DatePickerState\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.DatePickerFormatter\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.DatePickerColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.DatePickerWithDateSelectableDatesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//DatePickerDialog/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.material[0-9]+\.DatePickerColors\#androidx\.compose\.ui\.window\.DialogProperties\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.DatePickerDialogSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//DateRangePicker/\#androidx\.compose\.material[0-9]+\.DateRangePickerState\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.DatePickerFormatter\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.DatePickerColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.DateRangePickerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//DismissibleNavigationDrawer/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.DrawerState\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.DismissibleNavigationDrawerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//DockedSearchBar/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.SearchBarColors\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.DockedSearchBarSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//produceState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.runtime\.ProduceStateScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.ProduceState\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//produceState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.runtime\.ProduceStateScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.ProduceStateAwaitDispose\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//produceState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.runtime\.ProduceStateScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.ProduceState\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//produceState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.runtime\.ProduceStateScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.ProduceStateAwaitDispose\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//produceState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.runtime\.ProduceStateScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.ProduceState\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//produceState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.Any\?\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.runtime\.ProduceStateScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.ProduceStateAwaitDispose\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//produceState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.runtime\.ProduceStateScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.ProduceState\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//produceState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.runtime\.ProduceStateScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.ProduceStateAwaitDispose\. b/[0-9]+
+WARN: Multiple sources exist for ComposableLambda\. Artifact ID metadata will not be displayed
+WARNING: no common sourceSet for androidx\.compose\.ui\.viewinterop//AndroidView/\#kotlin\.Function[0-9]+\[android\.content\.Context,TypeParam\(bounds=\[android\.view\.View\]\)\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ViewInComposeNestedScrollInteropSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.viewinterop//AndroidView/\#kotlin\.Function[0-9]+\[android\.content\.Context,TypeParam\(bounds=\[android\.view\.View\]\)\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.AndroidViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.viewinterop//AndroidView/\#kotlin\.Function[0-9]+\[android\.content\.Context,TypeParam\(bounds=\[android\.view\.View\]\)\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ViewInComposeNestedScrollInteropSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.viewinterop//AndroidView/\#kotlin\.Function[0-9]+\[android\.content\.Context,TypeParam\(bounds=\[android\.view\.View\]\)\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.AndroidViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.viewinterop//AndroidView/\#kotlin\.Function[0-9]+\[android\.content\.Context,TypeParam\(bounds=\[android\.view\.View\]\)\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ReusableAndroidViewInLazyColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.viewinterop//AndroidView/\#kotlin\.Function[0-9]+\[android\.content\.Context,TypeParam\(bounds=\[android\.view\.View\]\)\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[android\.view\.View\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.AndroidViewWithReleaseSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.window//Dialog/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.window\.DialogProperties\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.DialogSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.window//Popup/\#androidx\.compose\.ui\.Alignment\#androidx\.compose\.ui\.unit\.IntOffset\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PopupSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.window//Popup/\#androidx\.compose\.ui\.window\.PopupPositionProvider\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PopupSample\. b/[0-9]+
WARNING: link to @throws type UnsupportedDeviceOperationException does not resolve\. Is it from a package that the containing file does not import\? Is docs inherited to an un\-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\.`@throws java\.io\.IOException under some conditions\. This was observed in Throws\(root=CustomDocTag\(children=\[P\(children=\[Text\(body=if used on a real device\., children=\[\], params=\{\}\)\], params=\{\}\)\], params=\{\}, name=MARKDOWN_FILE\), name=UnsupportedDeviceOperationException, exceptionAddress=null\)\.`
WARNING: link to @throws type DeviceControllerOperationException does not resolve\. Is it from a package that the containing file does not import\? Is docs inherited to an un\-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\.`@throws java\.io\.IOException under some conditions\. This was observed in Throws\(root=CustomDocTag\(children=\[P\(children=\[Text\(body=when called on a non\-foldable Emulator\., children=\[\], params=\{\}\)\], params=\{\}\)\], params=\{\}, name=MARKDOWN_FILE\), name=DeviceControllerOperationException, exceptionAddress=null\)\.`
WARN\: Multiple sources exist for IOException\. Artifact ID metadata will not be displayed
@@ -289,23 +693,70 @@
WARN: Missing @param tag for parameter `toJSON` of function androidx\.constraintlayout\.core\.state/CoreMotionScene/setTransitionContent/\#java\.lang\.String\#java\.lang\.String/PointingToDeclaration/
WARN: Missing @param tag for parameter `currentProgress` of function androidx\.constraintlayout\.core\.state/Transition/dragToProgress/\#float\#int\#int\#float\#float/PointingToDeclaration/
WARN: Missing @param tag for parameter `flags` of function androidx\.constraintlayout\.core\.widgets/ConstraintWidgetContainer/updateChildrenFromSolver/\#androidx\.constraintlayout\.core\.LinearSystem\#boolean\[\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation/EnterTransition/togetherWith/androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatedContentTransitionSpecSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/EnterTransition/plus/\#androidx\.compose\.animation\.EnterTransition/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.FullyLoadedTransition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/AnimatedVisibilityScope/animateEnterExit/androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimateEnterExitPartialContent\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/AnimatedContentTransitionScope/slideIntoContainer/\#androidx\.compose\.animation\.AnimatedContentTransitionScope\.SlideDirection\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntOffset\]\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.SlideIntoContainerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//Animatable/\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatableColor\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/ExitTransition\.Companion/None/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AVScopeAnimateEnterExit\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/ExitTransition/plus/\#androidx\.compose\.animation\.ExitTransition/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.FullyLoadedTransition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//AnimatedContent/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedContentTransitionScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],androidx\.compose\.animation\.ContentTransform\]\#androidx\.compose\.ui\.Alignment\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedContentScope,TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.TransitionExtensionAnimatedContentSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//AnimatedContent/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedContentTransitionScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],androidx\.compose\.animation\.ContentTransform\]\#androidx\.compose\.ui\.Alignment\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedContentScope,TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.SimpleAnimatedContentSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/AnimatedContentTransitionScope/slideOutOfContainer/\#androidx\.compose\.animation\.AnimatedContentTransitionScope\.SlideDirection\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntOffset\]\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.SlideIntoContainerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/AnimatedContentTransitionScope/using/androidx\.compose\.animation\.ContentTransform\#androidx\.compose\.animation\.SizeTransform\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatedContentTransitionSpecSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//AnimatedContent/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedContentTransitionScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],androidx\.compose\.animation\.ContentTransform\]\#androidx\.compose\.ui\.Alignment\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedContentScope,TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimateIncrementDecrementSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//AnimatedVisibility/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Boolean\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AddAnimatedVisibilityToGenericTransitionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//AnimatedVisibility/\#androidx\.compose\.animation\.core\.MutableTransitionState\[kotlin\.Boolean\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatedVisibilityLazyColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//AnimatedVisibility/androidx\.compose\.foundation\.layout\.ColumnScope\#androidx\.compose\.animation\.core\.MutableTransitionState\[kotlin\.Boolean\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AVColumnScopeWithMutableTransitionState\. b/[0-9]+
WARN: Missing @param tag for parameter `widgets` of function androidx\.constraintlayout\.core\.widgets/Chain/applyChainConstraints/\#androidx\.constraintlayout\.core\.widgets\.ConstraintWidgetContainer\#androidx\.constraintlayout\.core\.LinearSystem\#java\.util\.ArrayList<androidx\.constraintlayout\.core\.widgets\.ConstraintWidget>\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `len` of function androidx\.constraintlayout\.motion\.widget/DesignTool/getAnimationPath/\#java\.lang\.Object\#float\[\]\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `type` of function androidx\.constraintlayout\.motion\.widget/DesignTool/getKeyFrameInfo/\#java\.lang\.Object\#int\#int\[\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `type` of function androidx\.constraintlayout\.motion\.widget/MotionController/getKeyFrameInfo/\#int\#int\[\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//updateTransition/\#androidx\.compose\.animation\.core\.MutableTransitionState\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.String\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.DoubleTapToLikeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.graphics\.res//animatedVectorResource/androidx\.compose\.animation\.graphics\.vector\.AnimatedImageVector\.Companion\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.graphics\.samples\.AnimatedVectorSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.graphics\.res//rememberAnimatedVectorPainter/\#androidx\.compose\.animation\.graphics\.vector\.AnimatedImageVector\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.graphics\.samples\.AnimatedVectorSample\. b/[0-9]+
WARN: Missing @param tag for parameter `margin` of function androidx\.constraintlayout\.widget/ConstraintSet/createBarrier/\#int\#int\#int\#int\.\.\./PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//draggable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.gestures\.DraggableState\#androidx\.compose\.foundation\.gestures\.Orientation\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\?\#kotlin\.Boolean\#kotlin\.coroutines\.SuspendFunction[0-9]+\[kotlinx\.coroutines\.CoroutineScope,androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[kotlinx\.coroutines\.CoroutineScope,kotlin\.Float,kotlin\.Unit\]\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DraggableSample\. b/[0-9]+
WARN: Missing @param tag for parameter `viewId` of function androidx\.constraintlayout\.widget/ConstraintSet/setApplyElevation/\#int\#boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//horizontalDrag/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.HorizontalDragSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//scrollable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.gestures\.ScrollableState\#androidx\.compose\.foundation\.gestures\.Orientation\#androidx\.compose\.foundation\.OverscrollEffect\?\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.foundation\.gestures\.FlingBehavior\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ScrollableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//scrollable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.gestures\.ScrollableState\#androidx\.compose\.foundation\.gestures\.Orientation\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.foundation\.gestures\.FlingBehavior\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ScrollableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//transformable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.gestures\.TransformableState\#kotlin\.Boolean\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.TransformableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//transformable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.gestures\.TransformableState\#kotlin\.Function[0-9]+\[kotlin\.Boolean\]\#kotlin\.Boolean\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.TransformableSampleInsideScroll\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//verticalDrag/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.VerticalDragSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.interaction/InteractionSource/interactions/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.InteractionSourceFlowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//Box/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.BoxScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleBox\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/ColumnScope/align/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\.Horizontal/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleAlignInColumn\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/RowScope/align/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\.Vertical/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleAlignInRow\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/RowScope/AnimatedVisibility/androidx\.compose\.foundation\.layout\.RowScope\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatedFloatingActionButton\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/WindowInsets/asPaddingValues/androidx\.compose\.foundation\.layout\.WindowInsets\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.paddingValuesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/ColumnScope/AnimatedVisibility/androidx\.compose\.foundation\.layout\.ColumnScope\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.ColumnAnimatedVisibilitySample\. b/[0-9]+
WARN: Missing @param tag for parameter `activity` of function androidx\.core\.app/ActivityCompat/requestDragAndDropPermissions/\#android\.app\.Activity\#android\.view\.DragEvent/PointingToDeclaration/
WARN: Missing @param tag for parameter `activity` of function androidx\.core\.app/ActivityCompat/requireViewById/\#android\.app\.Activity\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `activity` of function androidx\.core\.app/ActivityCompat/setEnterSharedElementCallback/\#android\.app\.Activity\#androidx\.core\.app\.SharedElementCallback/PointingToDeclaration/
WARN: Missing @param tag for parameter `activity` of function androidx\.core\.app/ActivityCompat/setExitSharedElementCallback/\#android\.app\.Activity\#androidx\.core\.app\.SharedElementCallback/PointingToDeclaration/
WARN: Missing @param tag for parameter `activity` of function androidx\.core\.app/ActivityCompat/setLocusContext/\#android\.app\.Activity\#androidx\.core\.content\.LocusIdCompat\#android\.os\.Bundle/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.grid/LazyGridState/canScrollBackward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.grid//LazyHorizontalGrid/\#androidx\.compose\.foundation\.lazy\.grid\.GridCells\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.lazy\.grid\.LazyGridState\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Boolean\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#androidx\.compose\.foundation\.gestures\.FlingBehavior\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.grid\.LazyGridScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LazyHorizontalGridSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.grid/LazyGridState/canScrollForward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.grid/LazyGridState/firstVisibleItemIndex/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.UsingGridScrollPositionForSideEffectSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.grid/LazyGridState/firstVisibleItemIndex/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.UsingGridScrollPositionInCompositionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.grid//LazyHorizontalGrid/\#androidx\.compose\.foundation\.lazy\.grid\.GridCells\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.lazy\.grid\.LazyGridState\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Boolean\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#androidx\.compose\.foundation\.gestures\.FlingBehavior\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.grid\.LazyGridScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LazyHorizontalGridSpanSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.grid//LazyVerticalGrid/\#androidx\.compose\.foundation\.lazy\.grid\.GridCells\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.lazy\.grid\.LazyGridState\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Boolean\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#androidx\.compose\.foundation\.gestures\.FlingBehavior\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.grid\.LazyGridScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LazyVerticalGridSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.grid/LazyGridState/layoutInfo/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.UsingGridLayoutInfoForSideEffectSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.grid//LazyVerticalGrid/\#androidx\.compose\.foundation\.lazy\.grid\.GridCells\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.lazy\.grid\.LazyGridState\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Boolean\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#androidx\.compose\.foundation\.gestures\.FlingBehavior\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.grid\.LazyGridScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LazyVerticalGridSpanSample\. b/[0-9]+
WARN: Missing @param tag for parameter `service` of function androidx\.core\.app/ServiceCompat/stopForeground/\#android\.app\.Service\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `block` of function androidx\.core\.content//withStyledAttributes/android\.content\.Context\#android\.util\.AttributeSet\?\#kotlin\.IntArray\#kotlin\.Int\#kotlin\.Int\#kotlin\.Function[0-9]+\[android\.content\.res\.TypedArray,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.core\.content/ContextCompat/checkSelfPermission/\#android\.content\.Context\#java\.lang\.String/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.core\.content/ContextCompat/getColor/\#android\.content\.Context\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.core\.content/ContextCompat/getColorStateList/\#android\.content\.Context\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.core\.content/ContextCompat/getDrawable/\#android\.content\.Context\#int/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.staggeredgrid/LazyStaggeredGridState/canScrollBackward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.staggeredgrid//LazyHorizontalStaggeredGrid/\#androidx\.compose\.foundation\.lazy\.staggeredgrid\.StaggeredGridCells\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.lazy\.staggeredgrid\.LazyStaggeredGridState\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Boolean\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.gestures\.FlingBehavior\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.staggeredgrid\.LazyStaggeredGridScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LazyHorizontalStaggeredGridSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.staggeredgrid/LazyStaggeredGridState/canScrollForward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.staggeredgrid//LazyHorizontalStaggeredGrid/\#androidx\.compose\.foundation\.lazy\.staggeredgrid\.StaggeredGridCells\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.lazy\.staggeredgrid\.LazyStaggeredGridState\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Boolean\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.gestures\.FlingBehavior\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.staggeredgrid\.LazyStaggeredGridScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LazyHorizontalStaggeredGridSpanSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.staggeredgrid//LazyVerticalStaggeredGrid/\#androidx\.compose\.foundation\.lazy\.staggeredgrid\.StaggeredGridCells\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.lazy\.staggeredgrid\.LazyStaggeredGridState\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Boolean\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#androidx\.compose\.foundation\.gestures\.FlingBehavior\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.staggeredgrid\.LazyStaggeredGridScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LazyVerticalStaggeredGridSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.lazy\.staggeredgrid//LazyVerticalStaggeredGrid/\#androidx\.compose\.foundation\.lazy\.staggeredgrid\.StaggeredGridCells\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.lazy\.staggeredgrid\.LazyStaggeredGridState\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Boolean\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#androidx\.compose\.foundation\.gestures\.FlingBehavior\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.staggeredgrid\.LazyStaggeredGridScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LazyVerticalStaggeredGridSpanSample\. b/[0-9]+
WARN: Missing @param tag for parameter `block` of function androidx\.core\.content/ContextKt/withStyledAttributes/android\.content\.Context\#android\.util\.AttributeSet\?\#kotlin\.IntArray\#kotlin\.Int\#kotlin\.Int\#kotlin\.Function[0-9]+\[android\.content\.res\.TypedArray,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `resourceId` of function androidx\.core\.content/ContextKt/withStyledAttributes/android\.content\.Context\#kotlin\.Int\#kotlin\.IntArray\#kotlin\.Function[0-9]+\[android\.content\.res\.TypedArray,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `block` of function androidx\.core\.content/ContextKt/withStyledAttributes/android\.content\.Context\#kotlin\.Int\#kotlin\.IntArray\#kotlin\.Function[0-9]+\[android\.content\.res\.TypedArray,kotlin\.Unit\]/PointingToDeclaration/
@@ -315,11 +766,25 @@
WARN: Missing @param tag for parameter `context` of function androidx\.core\.content\.pm/ShortcutManagerCompat/createShortcutResultIntent/\#android\.content\.Context\#androidx\.core\.content\.pm\.ShortcutInfoCompat/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.core\.content\.pm/ShortcutManagerCompat/getShortcuts/\#android\.content\.Context\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.core\.content\.pm/ShortcutManagerCompat/requestPinShortcut/\#android\.content\.Context\#androidx\.core\.content\.pm\.ShortcutInfoCompat\#android\.content\.IntentSender/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager/PagerState/canScrollBackward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager/PagerState/animateScrollToPage/\#kotlin\.Int\#kotlin\.Float\#androidx\.compose\.animation\.core\.AnimationSpec\[kotlin\.Float\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AnimateScrollPageSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager//HorizontalPager/\#androidx\.compose\.foundation\.pager\.PagerState\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.pager\.PageSize\#kotlin\.Int\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.Alignment\.Vertical\#androidx\.compose\.foundation\.gestures\.snapping\.SnapFlingBehavior\#kotlin\.Boolean\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Any\]\?\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollConnection\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.pager\.PagerScope,kotlin\.Int,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SimpleHorizontalPagerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager/PagerState/canScrollForward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager/PagerState/currentPage/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ObservingStateChangesInPagerStateSample\. b/[0-9]+
WARN: Missing @param tag for parameter `res` of function androidx\.core\.content\.res/ResourcesCompat/getColor/\#android\.content\.res\.Resources\#int\#android\.content\.res\.Resources\.Theme/PointingToDeclaration/
WARN: Missing @param tag for parameter `res` of function androidx\.core\.content\.res/ResourcesCompat/getColorStateList/\#android\.content\.res\.Resources\#int\#android\.content\.res\.Resources\.Theme/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager/PagerState/scrollToPage/\#kotlin\.Int\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ScrollToPageSample\. b/[0-9]+
WARN: Missing @param tag for parameter `res` of function androidx\.core\.content\.res/ResourcesCompat/getDrawable/\#android\.content\.res\.Resources\#int\#android\.content\.res\.Resources\.Theme/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager/PagerState/currentPageOffsetFraction/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ObservingStateChangesInPagerStateSample\. b/[0-9]+
WARN: Missing @param tag for parameter `res` of function androidx\.core\.content\.res/ResourcesCompat/getDrawableForDensity/\#android\.content\.res\.Resources\#int\#int\#android\.content\.res\.Resources\.Theme/PointingToDeclaration/
WARN: Missing @param tag for parameter `res` of function androidx\.core\.content\.res/ResourcesCompat/getFloat/\#android\.content\.res\.Resources\#int/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager/PagerState/settledPage/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ObservingStateChangesInPagerStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager/PagerState/targetPage/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ObservingStateChangesInPagerStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager//HorizontalPager/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.pager\.PagerState\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.pager\.PageSize\#kotlin\.Int\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.Alignment\.Vertical\#androidx\.compose\.foundation\.gestures\.snapping\.SnapFlingBehavior\#kotlin\.Boolean\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Any\]\?\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollConnection\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.pager\.PagerScope,kotlin\.Int,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SimpleHorizontalPagerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager//VerticalPager/\#androidx\.compose\.foundation\.pager\.PagerState\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.pager\.PageSize\#kotlin\.Int\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.Alignment\.Horizontal\#androidx\.compose\.foundation\.gestures\.snapping\.SnapFlingBehavior\#kotlin\.Boolean\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Any\]\?\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollConnection\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.pager\.PagerScope,kotlin\.Int,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SimpleVerticalPagerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager//VerticalPager/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.pager\.PagerState\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.pager\.PageSize\#kotlin\.Int\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.Alignment\.Horizontal\#androidx\.compose\.foundation\.gestures\.snapping\.SnapFlingBehavior\#kotlin\.Boolean\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Any\]\?\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollConnection\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.pager\.PagerScope,kotlin\.Int,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SimpleVerticalPagerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager//rememberPagerState/\#kotlin\.Int\#kotlin\.Float\#kotlin\.Function[0-9]+\[kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.PagerWithStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager//rememberPagerState/\#kotlin\.Int\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.PagerWithStateSample\. b/[0-9]+
WARN: Missing @param tag for parameter `body` of function androidx\.core\.database\.sqlite//transaction/android\.database\.sqlite\.SQLiteDatabase\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[android\.database\.sqlite\.SQLiteDatabase,TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `body` of function androidx\.core\.database\.sqlite/SQLiteDatabaseKt/transaction/android\.database\.sqlite\.SQLiteDatabase\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[android\.database\.sqlite\.SQLiteDatabase,TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.core\.graphics/TypefaceCompat/create/\#android\.content\.Context\#android\.graphics\.Typeface\#int\#boolean/PointingToDeclaration/
@@ -331,6 +796,7 @@
WARN: Missing @param tag for parameter `right` of function androidx\.core\.graphics\.drawable/DrawableCompat/setHotspotBounds/\#android\.graphics\.drawable\.Drawable\#int\#int\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `bottom` of function androidx\.core\.graphics\.drawable/DrawableCompat/setHotspotBounds/\#android\.graphics\.drawable\.Drawable\#int\#int\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `drawable` of function androidx\.core\.graphics\.drawable/DrawableCompat/setLayoutDirection/\#android\.graphics\.drawable\.Drawable\#int/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//appendInlineContent/androidx\.compose\.ui\.text\.AnnotatedString\.Builder\#kotlin\.String\#kotlin\.String/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.InlineTextContentSample\. b/[0-9]+
WARN: Missing @param tag for parameter `uptimeMillis` of function androidx\.core\.os//postAtTime/android\.os\.Handler\#kotlin\.Long\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `action` of function androidx\.core\.os//postAtTime/android\.os\.Handler\#kotlin\.Long\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `callback` of function androidx\.core\.os/HandlerCompat/createAsync/\#android\.os\.Looper\#android\.os\.Handler\.Callback/PointingToDeclaration/
@@ -338,10 +804,20 @@
WARN: Missing @param tag for parameter `action` of function androidx\.core\.os/HandlerKt/postAtTime/android\.os\.Handler\#kotlin\.Long\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `handler` of function androidx\.core\.os/HandlerCompat/postDelayed/\#android\.os\.Handler\#java\.lang\.Runnable\#java\.lang\.Object\#long/PointingToDeclaration/
WARN: Missing @param tag for parameter `message` of function androidx\.core\.os/MessageCompat/setAsynchronous/\#android\.os\.Message\#boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//ClickableText/\#androidx\.compose\.ui\.text\.AnnotatedString\#kotlin\.Function[0-9]+\[kotlin\.Int\?,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.TextLayoutResult,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ClickableText\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text//ClickableText/\#androidx\.compose\.ui\.text\.AnnotatedString\#kotlin\.Function[0-9]+\[kotlin\.Int\?,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.style\.TextOverflow\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.TextLayoutResult,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.LongClickableText\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.core\.provider/DocumentsContractCompat/createDocument/\#android\.content\.ContentResolver\#android\.net\.Uri\#java\.lang\.String\#java\.lang\.String/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.core\.provider/DocumentsContractCompat/removeDocument/\#android\.content\.ContentResolver\#android\.net\.Uri\#android\.net\.Uri/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text\.selection//DisableSelection/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DisableSelectionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text\.selection//SelectionContainer/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SelectionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material/ButtonDefaults/IconSize/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ButtonWithIconSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//LocalAbsoluteElevation/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.AbsoluteElevationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//swipeable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.SwipeableState\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.collections\.Map\[kotlin\.Float,TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.compose\.foundation\.gestures\.Orientation\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\?\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),androidx\.compose\.material\.ThresholdConfig\]\#androidx\.compose\.material\.ResistanceConfig\?\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SwipeableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material/SnackbarHostState/showSnackbar/\#kotlin\.String\#kotlin\.String\?\#androidx\.compose\.material\.SnackbarDuration/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ScaffoldWithCoroutinesSnackbar\. b/[0-9]+
WARN: Missing @param tag for parameter `transformFilter` of function androidx\.core\.text\.util/LinkifyCompat/addLinks/\#android\.widget\.TextView\#java\.util\.regex\.Pattern\#java\.lang\.String\#android\.text\.util\.Linkify\.MatchFilter\#android\.text\.util\.Linkify\.TransformFilter/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//BottomSheetScaffold/\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.BottomSheetScaffoldState\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.SnackbarHostState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material\.FabPosition\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.PaddingValues,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.BottomSheetScaffoldSample\. b/[0-9]+
WARN: Missing @param tag for parameter `listener` of function androidx\.core\.view/DragStartHelper/DragStartHelper/\#android\.view\.View\#androidx\.core\.view\.DragStartHelper\.OnDragStartListener/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//LinearProgressIndicator/\#kotlin\.Float\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.StrokeCap/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.LinearProgressIndicatorSample\. b/[0-9]+
WARN: Missing @param tag for parameter `payload` of function androidx\.core\.view/ContentInfoCompat/partition/\#android\.view\.ContentInfo\#java\.util\.function\.Predicate<android\.content\.ClipData\.Item>/PointingToDeclaration/
WARN: Missing @param tag for parameter `lp` of function androidx\.core\.view/MarginLayoutParamsCompat/setLayoutDirection/\#android\.view\.ViewGroup\.MarginLayoutParams\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `item` of function androidx\.core\.view/MenuItemCompat/setAlphabeticShortcut/\#android\.view\.MenuItem\#char\#int/PointingToDeclaration/
@@ -353,6 +829,7 @@
WARN: Missing @param tag for parameter `type` of function androidx\.core\.view/NestedScrollingChildHelper/startNestedScroll/\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `event` of function androidx\.core\.view/MotionEventCompat/getAxisValue/\#android\.view\.MotionEvent\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `event` of function androidx\.core\.view/MotionEventCompat/getAxisValue/\#android\.view\.MotionEvent\#int\#int/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//ListItem/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.OneLineListItems\. b/[0-9]+
WARN: Missing @param tag for parameter `event` of function androidx\.core\.view/MotionEventCompat/isFromSource/\#android\.view\.MotionEvent\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `scaleGestureDetector` of function androidx\.core\.view/ScaleGestureDetectorCompat/setQuickScaleEnabled/\#java\.lang\.Object\#boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `scaleGestureDetector` of function androidx\.core\.view/ScaleGestureDetectorCompat/setQuickScaleEnabled/\#android\.view\.ScaleGestureDetector\#boolean/PointingToDeclaration/
@@ -361,6 +838,7 @@
WARN: Missing @param tag for parameter `parent` of function androidx\.core\.view/ViewParentCompat/onNestedPreFling/\#android\.view\.ViewParent\#android\.view\.View\#float\#float/PointingToDeclaration/
WARN: Missing @param tag for parameter `parent` of function androidx\.core\.view/ViewParentCompat/onNestedPreScroll/\#android\.view\.ViewParent\#android\.view\.View\#int\#int\#int\[\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `parent` of function androidx\.core\.view/ViewParentCompat/onNestedPreScroll/\#android\.view\.ViewParent\#android\.view\.View\#int\#int\#int\[\]\#int/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//ListItem/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.TwoLineListItems\. b/[0-9]+
WARN: Missing @param tag for parameter `parent` of function androidx\.core\.view/ViewParentCompat/onNestedScroll/\#android\.view\.ViewParent\#android\.view\.View\#int\#int\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `parent` of function androidx\.core\.view/ViewParentCompat/onNestedScroll/\#android\.view\.ViewParent\#android\.view\.View\#int\#int\#int\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `parent` of function androidx\.core\.view/ViewParentCompat/onNestedScroll/\#android\.view\.ViewParent\#android\.view\.View\#int\#int\#int\#int\#int\#int\[\]/PointingToDeclaration/
@@ -378,31 +856,38 @@
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/computeSystemWindowInsets/\#android\.view\.View\#androidx\.core\.view\.WindowInsetsCompat\#android\.graphics\.Rect/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/dispatchApplyWindowInsets/\#android\.view\.View\#androidx\.core\.view\.WindowInsetsCompat/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/dispatchNestedFling/\#android\.view\.View\#float\#float\#boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//ListItem/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ThreeLineListItems\. b/[0-9]+
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/dispatchNestedPreFling/\#android\.view\.View\#float\#float/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/dispatchNestedPreScroll/\#android\.view\.View\#int\#int\#int\[\]\#int\[\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/dispatchNestedPreScroll/\#android\.view\.View\#int\#int\#int\[\]\#int\[\]\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/dispatchNestedScroll/\#android\.view\.View\#int\#int\#int\#int\#int\[\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/dispatchNestedScroll/\#android\.view\.View\#int\#int\#int\#int\#int\[\]\#int\#int\[\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//ListItem/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ClickableListItems\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//MaterialTheme/\#androidx\.compose\.material\.Colors\#androidx\.compose\.material\.Typography\#androidx\.compose\.material\.Shapes\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.MaterialThemeSample\. b/[0-9]+
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/dispatchNestedScroll/\#android\.view\.View\#int\#int\#int\#int\#int\[\]\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/hasNestedScrollingParent/\#android\.view\.View\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/keyboardNavigationClusterSearch/\#android\.view\.View\#android\.view\.View\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/offsetLeftAndRight/\#android\.view\.View\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/offsetTopAndBottom/\#android\.view\.View\#int/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//ModalDrawer/\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.DrawerState\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ModalDrawerSample\. b/[0-9]+
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/performAccessibilityAction/\#android\.view\.View\#int\#android\.os\.Bundle/PointingToDeclaration/
WARN: Missing @param tag for parameter `v` of function androidx\.core\.view/ViewCompat/removeOnUnhandledKeyEventListener/\#android\.view\.View\#androidx\.core\.view\.ViewCompat\.OnUnhandledKeyEventListenerCompat/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/requireViewById/\#android\.view\.View\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `childMeasuredState` of function androidx\.core\.view/ViewCompat/resolveSizeAndState/\#int\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/saveAttributeDataForStyleable/\#android\.view\.View\#android\.content\.Context\#int\[\]\#android\.util\.AttributeSet\#android\.content\.res\.TypedArray\#int\#int/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//NavigationRail/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.NavigationRailSample\. b/[0-9]+
WARN: Missing @param tag for parameter `v` of function androidx\.core\.view/ViewCompat/setAccessibilityDelegate/\#android\.view\.View\#androidx\.core\.view\.AccessibilityDelegateCompat/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setActivated/\#android\.view\.View\#boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setAlpha/\#android\.view\.View\#float/PointingToDeclaration/
WARN: Missing @param tag for parameter `v` of function androidx\.core\.view/ViewCompat/setAutofillHints/\#android\.view\.View\#java\.lang\.String\.\.\./PointingToDeclaration/
WARN: Missing @param tag for parameter `viewGroup` of function androidx\.core\.view/ViewCompat/setChildrenDrawingOrderEnabled/\#android\.view\.ViewGroup\#boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setFocusedByDefault/\#android\.view\.View\#boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//OutlinedButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.ButtonElevation\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ButtonColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.OutlinedButtonSample\. b/[0-9]+
WARN: Missing @param tag for parameter `v` of function androidx\.core\.view/ViewCompat/setImportantForAutofill/\#android\.view\.View\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setKeyboardNavigationCluster/\#android\.view\.View\#boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setNestedScrollingEnabled/\#android\.view\.View\#boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setNextClusterForwardId/\#android\.view\.View\#int/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//OutlinedTextField/\#androidx\.compose\.ui\.text\.input\.TextFieldValue\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.input\.TextFieldValue,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.OutlinedTextFieldSample\. b/[0-9]+
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setPivotX/\#android\.view\.View\#float/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setPivotY/\#android\.view\.View\#float/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setPointerIcon/\#android\.view\.View\#androidx\.core\.view\.PointerIconCompat/PointingToDeclaration/
@@ -420,6 +905,7 @@
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setTooltipText/\#android\.view\.View\#java\.lang\.CharSequence/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setTranslationX/\#android\.view\.View\#float/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setTranslationY/\#android\.view\.View\#float/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//OutlinedTextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SimpleOutlinedTextFieldSample\. b/[0-9]+
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setWindowInsetsAnimationCallback/\#android\.view\.View\#androidx\.core\.view\.WindowInsetsAnimationCompat\.Callback/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setX/\#android\.view\.View\#float/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/setY/\#android\.view\.View\#float/PointingToDeclaration/
@@ -427,6 +913,22 @@
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/startNestedScroll/\#android\.view\.View\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/startNestedScroll/\#android\.view\.View\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `view` of function androidx\.core\.view/ViewCompat/stopNestedScroll/\#android\.view\.View\#int/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//RadioButton/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.RadioButtonColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.RadioButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//RadioButton/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.RadioButtonColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.RadioGroupSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//RangeSlider/\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\],kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Int\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material\.SliderColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.RangeSliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//RangeSlider/\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\],kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Int\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material\.SliderColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.StepRangeSliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Scaffold/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.ScaffoldState\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.SnackbarHostState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.material\.FabPosition\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.PaddingValues,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SimpleScaffoldWithTopBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Scaffold/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.ScaffoldState\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.SnackbarHostState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.material\.FabPosition\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.PaddingValues,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ScaffoldWithBottomBarAndCutout\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Scaffold/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.ScaffoldState\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.SnackbarHostState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.material\.FabPosition\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.PaddingValues,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ScaffoldWithSimpleSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Slider/\#kotlin\.Float\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Int\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.SliderColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Slider/\#kotlin\.Float\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Int\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.SliderColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.StepsSliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Snackbar/\#androidx\.compose\.material\.SnackbarData\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ScaffoldWithSimpleSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Snackbar/\#androidx\.compose\.material\.SnackbarData\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ScaffoldWithCustomSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Snackbar/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ScaffoldWithSimpleSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Snackbar/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ScaffoldWithCustomSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//SnackbarHost/\#androidx\.compose\.material\.SnackbarHostState\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.SnackbarData,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ScaffoldWithSimpleSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//SnackbarHost/\#androidx\.compose\.material\.SnackbarHostState\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.SnackbarData,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ScaffoldWithCustomSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Surface/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SurfaceSample\. b/[0-9]+
WARN: Missing @param tag for parameter `manager` of function androidx\.core\.view\.accessibility/AccessibilityManagerCompat/addTouchExplorationStateChangeListener/\#android\.view\.accessibility\.AccessibilityManager\#androidx\.core\.view\.accessibility\.AccessibilityManagerCompat\.TouchExplorationStateChangeListener/PointingToDeclaration/
WARN: Missing @param tag for parameter `manager` of function androidx\.core\.view\.accessibility/AccessibilityManagerCompat/removeTouchExplorationStateChangeListener/\#android\.view\.accessibility\.AccessibilityManager\#androidx\.core\.view\.accessibility\.AccessibilityManagerCompat\.TouchExplorationStateChangeListener/PointingToDeclaration/
WARN: Missing @param tag for parameter `event` of function androidx\.core\.view\.accessibility/AccessibilityEventCompat/appendRecord/\#android\.view\.accessibility\.AccessibilityEvent\#androidx\.core\.view\.accessibility\.AccessibilityRecordCompat/PointingToDeclaration/
@@ -466,11 +968,12 @@
WARN: Missing @param tag for parameter `horizontalGravity` of function androidx\.core\.widget/RemoteViewsCompat/setRelativeLayoutHorizontalGravity/android\.widget\.RemoteViews\#kotlin\.Int\#kotlin\.Int/PointingToDeclaration/
WARN: Missing @param tag for parameter `verticalGravity` of function androidx\.core\.widget/RemoteViewsCompat/setRelativeLayoutVerticalGravity/android\.widget\.RemoteViews\#kotlin\.Int\#kotlin\.Int/PointingToDeclaration/
WARN: Missing @param tag for parameter `night` of function androidx\.core\.widget/RemoteViewsCompat/setSwitchThumbIcon/android\.widget\.RemoteViews\#kotlin\.Int\#android\.graphics\.drawable\.Icon\?\#android\.graphics\.drawable\.Icon\?/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.FancyIndicatorContainerTabs\. b/[0-9]+
WARN: Missing @param tag for parameter `night` of function androidx\.core\.widget/RemoteViewsCompat/setSwitchTrackIcon/android\.widget\.RemoteViews\#kotlin\.Int\#android\.graphics\.drawable\.Icon\?\#android\.graphics\.drawable\.Icon\?/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//TextButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.ButtonElevation\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ButtonColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.TextButtonSample\. b/[0-9]+
WARN: Missing @param tag for parameter `c` of function androidx\.cursoradapter\.widget/ResourceCursorAdapter/ResourceCursorAdapter/\#android\.content\.Context\#int\#android\.database\.Cursor/PointingToDeclaration/
WARN: Missing @param tag for parameter `listener` of function androidx\.customview\.poolingcontainer/PoolingContainer/addPoolingContainerListener/android\.view\.View\#androidx\.customview\.poolingcontainer\.PoolingContainerListener/PointingToDeclaration/
WARN: Missing @param tag for parameter `listener` of function androidx\.customview\.poolingcontainer//addPoolingContainerListener/android\.view\.View\#androidx\.customview\.poolingcontainer\.PoolingContainerListener/PointingToDeclaration/
-WARN: Failed to resolve `@see <a href="https://www\.w[0-9]+\.org/TR/ttml[0-9]+/">Timed Text Markup Language [0-9]+ \(TTML[0-9]+\) \- [0-9]+\.[0-9]+\.[0-9]+</a>`!
WARN: Missing @param tag for parameter `pointerId` of function androidx\.customview\.widget/ViewDragHelper/isEdgeTouched/\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `serializer` of function androidx\.datastore//dataStore/\#kotlin\.String\#androidx\.datastore\.core\.Serializer\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.datastore\.core\.handlers\.ReplaceFileCorruptionHandler\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\?\#kotlin\.Function[0-9]+\[android\.content\.Context,kotlin\.collections\.List\[androidx\.datastore\.core\.DataMigration\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\]\]\#kotlinx\.coroutines\.CoroutineScope/PointingToDeclaration/
WARN: Missing @param tag for parameter `serializer` of function androidx\.datastore/DataStoreDelegateKt/dataStore/\#kotlin\.String\#androidx\.datastore\.core\.Serializer\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.datastore\.core\.handlers\.ReplaceFileCorruptionHandler\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\?\#kotlin\.Function[0-9]+\[android\.content\.Context,kotlin\.collections\.List\[androidx\.datastore\.core\.DataMigration\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\]\]\#kotlinx\.coroutines\.CoroutineScope/PointingToDeclaration/
@@ -484,14 +987,38 @@
WARN: Missing @param tag for parameter `context` of function androidx\.documentfile\.provider/DocumentFile/fromTreeUri/\#android\.content\.Context\#android\.net\.Uri/PointingToDeclaration/
WARNING\: link to \@throws type kotlin\.IllegalArgumentException does not resolve\. Is it from a package that the containing file does not import\? Is docs inherited to an un\-documented override function\, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name\, e\.g\.\`\@throws java\.io\.IOException under some conditions\. This was observed in Throws\(root\=CustomDocTag\(children\=\[P\(children\=\[Text\(body\=if this enum type has no constant with the specified name\, children\=\[\]\, params\=\{\}\)\]\, params\=\{\}\)\]\, params\=\{\}\, name\=MARKDOWN_FILE\)\, name\=kotlin\.IllegalArgumentException\, exceptionAddress\=null\)\.\`
WARN: Failed to resolve `@see <a href="https://developer\.android\.com/guide/topics/ui/drag\-drop">Drag and drop</a>`!
+WARNING: no common sourceSet for androidx\.compose\.material\.pullrefresh//pullRefresh/androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.pullrefresh\.PullRefreshState\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.PullRefreshSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material\.pullrefresh//PullRefreshIndicator/\#kotlin\.Boolean\#androidx\.compose\.material\.pullrefresh\.PullRefreshState\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.PullRefreshSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material\.pullrefresh//rememberPullRefreshState/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.PullRefreshSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material\.pullrefresh//pullRefresh/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Float\]\#kotlin\.coroutines\.SuspendFunction[0-9]+\[kotlin\.Float,kotlin\.Float\]\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.CustomPullRefreshSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material\.pullrefresh//pullRefreshIndicatorTransform/androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.pullrefresh\.PullRefreshState\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.PullRefreshIndicatorTransformSample\. b/[0-9]+
WARN: Missing @param tag for parameter `useEmojiAsDefaultStyle` of function androidx\.emoji\.text/EmojiCompat\.Config/setUseEmojiAsDefaultStyle/\#boolean\#java\.util\.List<java\.lang\.Integer>/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//DropdownMenu/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpOffset\#androidx\.compose\.foundation\.ScrollState\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.MenuSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//DropdownMenu/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpOffset\#androidx\.compose\.foundation\.ScrollState\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.MenuWithScrollStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//DropdownMenuItem/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.MenuItemColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.MenuSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ElevatedAssistChip/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ChipColors\#androidx\.compose\.material[0-9]+\.ChipElevation\?\#androidx\.compose\.material[0-9]+\.ChipBorder\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ElevatedAssistChipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ElevatedButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.material[0-9]+\.ButtonElevation\?\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ElevatedButtonSample\. b/[0-9]+
WARN: Missing @param tag for parameter `useEmojiAsDefaultStyle` of function androidx\.emoji[0-9]+\.text/EmojiCompat\.Config/setUseEmojiAsDefaultStyle/\#boolean\#java\.util\.List<java\.lang\.Integer>/PointingToDeclaration/
-WARN: Missing @param tag for parameter `speed` of function androidx\.media[0-9]+\.common\.util/Util/getPlayoutDurationForMediaDuration/\#long\#float/PointingToDeclaration/
-WARN: Missing @param tag for parameter `length` of function androidx\.media[0-9]+\.datasource/DataSourceUtil/readExactly/\#androidx\.media[0-9]+\.datasource\.DataSource\#int/PointingToDeclaration/
-WARN: Missing @param tag for parameter `allowCrossProtocolRedirects` of function androidx\.media[0-9]+\.datasource/DefaultDataSource/DefaultDataSource/\#android\.content\.Context\#boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+\.windowsizeclass//calculateWindowSizeClass/\#android\.app\.Activity/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.windowsizeclass\.samples\.AndroidWindowSizeClassSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/CompositionLocal/current/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.consumeCompositionLocal\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/MutableState/setValue/androidx\.compose\.runtime\.MutableState\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Any\?\#kotlin\.reflect\.KProperty\[\*\]\#TypeParam\(bounds=\[kotlin\.Any\?\]\)/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.DelegatedStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/ProduceStateScope/awaitDispose/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.ProduceStateAwaitDispose\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/SnapshotMutationPolicy/merge/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#TypeParam\(bounds=\[kotlin\.Any\?\]\)/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.counterSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//ComposeNode/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.Updater\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.CustomTreeComposition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/State/getValue/androidx\.compose\.runtime\.State\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Any\?\#kotlin\.reflect\.KProperty\[\*\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.DelegatedReadOnlyStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//ComposeNode/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.Updater\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.SkippableUpdater\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.CustomTreeComposition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//collectAsState/kotlinx\.coroutines\.flow\.Flow\[TypeParam\(bounds=\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\)\]\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.coroutines\.CoroutineContext/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.FlowWithInitialSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//ComposeNode/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.Updater\[TypeParam\(bounds=\[kotlin\.Any\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.CustomTreeComposition\. b/[0-9]+
WARN: Missing @param tag for parameter `inflater` of function androidx\.fragment\.app/Fragment/onCreateOptionsMenu/\#android\.view\.Menu\#android\.view\.MenuInflater/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.runtime//produceState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.runtime\.ProduceStateScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.ProduceState\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//produceState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.runtime\.ProduceStateScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.ProduceStateAwaitDispose\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//rememberUpdatedState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.rememberUpdatedStateSampleWithDisposableEffect\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//rememberUpdatedState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.rememberUpdatedStateSampleWithLaunchedEffect\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//snapshotFlow/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.snapshotFlowSample\. b/[0-9]+
WARN: Missing @param tag for parameter `hardwareBuffer` of function androidx\.graphics\.lowlatency/FrameBuffer/FrameBuffer/\#androidx\.graphics\.opengl\.egl\.EGLSpec\#android\.hardware\.HardwareBuffer/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.graphics\.opengl\.egl/EGLSpec/eglMakeCurrent/\#android\.opengl\.EGLContext\#android\.opengl\.EGLSurface\#android\.opengl\.EGLSurface/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.runtime\.snapshots/Snapshot/asContextElement/androidx\.compose\.runtime\.snapshots\.Snapshot\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.snapshotAsContextElementSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime\.snapshots//asContextElement/androidx\.compose\.runtime\.snapshots\.Snapshot\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.snapshotAsContextElementSample\. b/[0-9]+
WARN: Missing @param tag for parameter `context` of function androidx\.health\.connect\.client/HealthConnectClient\.Companion/getOrCreate/\#android\.content\.Context\#kotlin\.collections\.List\[kotlin\.String\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.health\.connect\.client/HealthConnectClient\.Companion/isAvailable/\#android\.content\.Context\#kotlin\.collections\.List\[kotlin\.String\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.health\.connect\.client/HealthConnectClient\.Companion/isProviderAvailable/\#android\.content\.Context\#kotlin\.collections\.List\[kotlin\.String\]/PointingToDeclaration/
@@ -499,18 +1026,27 @@
Did you mean androidx\.health\.data\.client\.HealthDataClient\#getChanges\?
WARN: Missing @param tag for parameter `query` of function androidx\.leanback\.app/SearchFragment/createArgs/\#android\.os\.Bundle\#java\.lang\.String/PointingToDeclaration/
WARN: Missing @param tag for parameter `query` of function androidx\.leanback\.app/SearchSupportFragment/createArgs/\#android\.os\.Bundle\#java\.lang\.String/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//alpha/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.AlphaSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//blur/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.draw\.BlurredEdgeTreatment/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.BlurSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//blur/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.draw\.BlurredEdgeTreatment/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ImageBlurSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//blur/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.draw\.BlurredEdgeTreatment/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.BlurSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//blur/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.draw\.BlurredEdgeTreatment/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ImageBlurSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//drawWithCache/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.draw\.CacheDrawScope,androidx\.compose\.ui\.draw\.DrawResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.DrawWithCacheModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//drawWithCache/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.draw\.CacheDrawScope,androidx\.compose\.ui\.draw\.DrawResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.DrawWithCacheModifierStateParameterSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//drawWithCache/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.draw\.CacheDrawScope,androidx\.compose\.ui\.draw\.DrawResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.DrawWithCacheContentSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//paint/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.painter\.Painter\#kotlin\.Boolean\#androidx\.compose\.ui\.Alignment\#androidx\.compose\.ui\.layout\.ContentScale\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.ColorFilter\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PainterModifierSample\. b/[0-9]+
WARN: Missing @param tag for parameter `detailsPresenter` of function androidx\.leanback\.widget/DetailsOverviewRowPresenter\.ViewHolder/ViewHolder/\#android\.view\.View\#androidx\.leanback\.widget\.Presenter/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.res//painterResource/\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.AndroidDrawableInDrawScopeSample\. b/[0-9]+
WARN: Missing @param tag for parameter `detailsPresenter` of function androidx\.leanback\.widget/FullWidthDetailsOverviewRowPresenter\.ViewHolder/ViewHolder/\#android\.view\.View\#androidx\.leanback\.widget\.Presenter\#androidx\.leanback\.widget\.DetailsOverviewLogoPresenter/PointingToDeclaration/
WARN: Missing @param tag for parameter `logoPresenter` of function androidx\.leanback\.widget/FullWidthDetailsOverviewRowPresenter\.ViewHolder/ViewHolder/\#android\.view\.View\#androidx\.leanback\.widget\.Presenter\#androidx\.leanback\.widget\.DetailsOverviewLogoPresenter/PointingToDeclaration/
WARN: Missing @param tag for parameter `parent` of function androidx\.leanback\.widget/GridLayoutManager/requestChildRectangleOnScreen/\#androidx\.recyclerview\.widget\.RecyclerView\#android\.view\.View\#android\.graphics\.Rect\#boolean/PointingToDeclaration/
-WARN: Missing @param tag for parameter `playerEmsgHandler` of function androidx\.media[0-9]+\.exoplayer\.dash/DashChunkSource\.Factory/createDashChunkSource/\#androidx\.media[0-9]+\.exoplayer\.upstream\.LoaderErrorThrower\#androidx\.media[0-9]+\.exoplayer\.dash\.manifest\.DashManifest\#androidx\.media[0-9]+\.exoplayer\.dash\.BaseUrlExclusionList\#int\#int\[\]\#androidx\.media[0-9]+\.exoplayer\.trackselection\.ExoTrackSelection\#int\#long\#boolean\#java\.util\.List<androidx\.media[0-9]+\.common\.Format>\#androidx\.media[0-9]+\.exoplayer\.dash\.PlayerEmsgHandler\.PlayerTrackEmsgHandler\#androidx\.media[0-9]+\.datasource\.TransferListener\#androidx\.media[0-9]+\.exoplayer\.analytics\.PlayerId/PointingToDeclaration/
-WARN: Missing @param tag for parameter `periodIndex` of function androidx\.media[0-9]+\.exoplayer\.dash/DashChunkSource/updateManifest/\#androidx\.media[0-9]+\.exoplayer\.dash\.manifest\.DashManifest\#int/PointingToDeclaration/
-WARN: Missing @param tag for parameter `playerEmsgHandler` of function androidx\.media[0-9]+\.exoplayer\.dash/DefaultDashChunkSource\.Factory/createDashChunkSource/\#androidx\.media[0-9]+\.exoplayer\.upstream\.LoaderErrorThrower\#androidx\.media[0-9]+\.exoplayer\.dash\.manifest\.DashManifest\#androidx\.media[0-9]+\.exoplayer\.dash\.BaseUrlExclusionList\#int\#int\[\]\#androidx\.media[0-9]+\.exoplayer\.trackselection\.ExoTrackSelection\#int\#long\#boolean\#java\.util\.List<androidx\.media[0-9]+\.common\.Format>\#androidx\.media[0-9]+\.exoplayer\.dash\.PlayerEmsgHandler\.PlayerTrackEmsgHandler\#androidx\.media[0-9]+\.datasource\.TransferListener\#androidx\.media[0-9]+\.exoplayer\.analytics\.PlayerId/PointingToDeclaration/
-WARN: Missing @param tag for parameter `newPeriodIndex` of function androidx\.media[0-9]+\.exoplayer\.dash/DefaultDashChunkSource/updateManifest/\#androidx\.media[0-9]+\.exoplayer\.dash\.manifest\.DashManifest\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `name` of function androidx\.leanback\.widget/Parallax/createProperty/\#java\.lang\.String\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `id` of function androidx\.leanback\.widget/PlaybackControlsRow\.ThumbsAction/ThumbsAction/\#int\#android\.content\.Context\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `solidIconIndex` of function androidx\.leanback\.widget/PlaybackControlsRow\.ThumbsAction/ThumbsAction/\#int\#android\.content\.Context\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `outlineIconIndex` of function androidx\.leanback\.widget/PlaybackControlsRow\.ThumbsAction/ThumbsAction/\#int\#android\.content\.Context\#int\#int/PointingToDeclaration/
+WARN: Multiple sources exist for MouseButton\. Artifact ID metadata will not be displayed
+WARN: Multiple sources exist for ComposeUiTest\. Artifact ID metadata will not be displayed
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/SemanticsNodeInteraction/performGesture/androidx\.compose\.ui\.test\.SemanticsNodeInteraction\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.test\.GestureScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.gestureClick\. b/[0-9]+
WARN: Missing @param tag for parameter `name` of function androidx\.leanback\.widget/RecyclerViewParallax/createProperty/\#java\.lang\.String\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `publisher` of function androidx\.lifecycle/LiveDataReactiveStreams/fromPublisher/\#org\.reactivestreams\.Publisher<T>/PointingToDeclaration/
WARN: Missing @param tag for parameter `coroutineDispatcher` of function androidx\.lifecycle\.testing/TestLifecycleOwner/TestLifecycleOwner/\#androidx\.lifecycle\.Lifecycle\.State\#kotlinx\.coroutines\.CoroutineDispatcher/PointingToDeclaration/
@@ -522,50 +1058,13 @@
WARN: Use @androidx\.annotation\.Nullable, not @javax\.annotation/Nullable///PointingToDeclaration/
WARN: Missing @param tag for parameter `metadata` of function androidx\.media[0-9]+\.player/MediaPlayer/setPlaylist/\#java\.util\.List<androidx\.media[0-9]+\.common\.MediaItem>\#androidx\.media[0-9]+\.common\.MediaMetadata/PointingToDeclaration/
WARN: Missing @param tag for parameter `controller` of function androidx\.media[0-9]+\.session/MediaSession/sendCustomCommand/\#androidx\.media[0-9]+\.session\.MediaSession\.ControllerInfo\#androidx\.media[0-9]+\.session\.SessionCommand\#android\.os\.Bundle/PointingToDeclaration/
-WARN: Missing @param tag for parameter `runnable` of function androidx\.media[0-9]+\.test\.utils/Action\.ExecuteRunnable/ExecuteRunnable/\#java\.lang\.String\#java\.lang\.Runnable/PointingToDeclaration/
-WARN: Missing @param tag for parameter `drmSessionManager` of function androidx\.media[0-9]+\.test\.utils/FakeAdaptiveMediaSource/createMediaPeriod/\#androidx\.media[0-9]+\.exoplayer\.source\.MediaSource\.MediaPeriodId\#androidx\.media[0-9]+\.exoplayer\.source\.TrackGroupArray\#androidx\.media[0-9]+\.exoplayer\.upstream\.Allocator\#androidx\.media[0-9]+\.exoplayer\.source\.MediaSourceEventListener\.EventDispatcher\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionManager\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionEventListener\.EventDispatcher\#androidx\.media[0-9]+\.datasource\.TransferListener/PointingToDeclaration/
-WARN: Missing @param tag for parameter `params` of function androidx\.media[0-9]+\.test\.utils/FakeTrackSelector/selectAllTracks/\#androidx\.media[0-9]+\.exoplayer\.trackselection\.MappingTrackSelector\.MappedTrackInfo\#int\[\]\[\]\[\]\#int\[\]\#androidx\.media[0-9]+\.exoplayer\.trackselection\.DefaultTrackSelector\.Parameters/PointingToDeclaration/
-WARN: Missing @param tag for parameter `startPositionUs` of function androidx\.media[0-9]+\.test\.utils/MediaSourceTestRunner/createPeriod/\#androidx\.media[0-9]+\.exoplayer\.source\.MediaSource\.MediaPeriodId\#long/PointingToDeclaration/
-WARN: Missing @param tag for parameter `factory` of function androidx\.media[0-9]+\.test\.utils/ExtractorAsserts/assertBehavior/\#androidx\.media[0-9]+\.test\.utils\.ExtractorAsserts\.ExtractorFactory\#java\.lang\.String\#androidx\.media[0-9]+\.test\.utils\.ExtractorAsserts\.AssertionConfig\#androidx\.media[0-9]+\.test\.utils\.ExtractorAsserts\.SimulationConfig/PointingToDeclaration/
-WARN: Missing @param tag for parameter `file` of function androidx\.media[0-9]+\.test\.utils/ExtractorAsserts/assertBehavior/\#androidx\.media[0-9]+\.test\.utils\.ExtractorAsserts\.ExtractorFactory\#java\.lang\.String\#androidx\.media[0-9]+\.test\.utils\.ExtractorAsserts\.AssertionConfig\#androidx\.media[0-9]+\.test\.utils\.ExtractorAsserts\.SimulationConfig/PointingToDeclaration/
-WARN: Missing @param tag for parameter `drmSessionManager` of function androidx\.media[0-9]+\.test\.utils/FakeMediaSource/createMediaPeriod/\#androidx\.media[0-9]+\.exoplayer\.source\.MediaSource\.MediaPeriodId\#androidx\.media[0-9]+\.exoplayer\.source\.TrackGroupArray\#androidx\.media[0-9]+\.exoplayer\.upstream\.Allocator\#androidx\.media[0-9]+\.exoplayer\.source\.MediaSourceEventListener\.EventDispatcher\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionManager\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionEventListener\.EventDispatcher\#androidx\.media[0-9]+\.datasource\.TransferListener/PointingToDeclaration/
-WARN: Missing @param tag for parameter `manifests` of function androidx\.media[0-9]+\.test\.utils/FakeTimeline/FakeTimeline/\#java\.lang\.Object\[\]\#androidx\.media[0-9]+\.test\.utils\.FakeTimeline\.TimelineWindowDefinition\.\.\./PointingToDeclaration/
-WARN: Missing @param tag for parameter `manifests` of function androidx\.media[0-9]+\.test\.utils/FakeTimeline/FakeTimeline/\#java\.lang\.Object\[\]\#androidx\.media[0-9]+\.exoplayer\.source\.ShuffleOrder\#androidx\.media[0-9]+\.test\.utils\.FakeTimeline\.TimelineWindowDefinition\.\.\./PointingToDeclaration/
-WARN: Missing @param tag for parameter `shuffleOrder` of function androidx\.media[0-9]+\.test\.utils/FakeTimeline/FakeTimeline/\#java\.lang\.Object\[\]\#androidx\.media[0-9]+\.exoplayer\.source\.ShuffleOrder\#androidx\.media[0-9]+\.test\.utils\.FakeTimeline\.TimelineWindowDefinition\.\.\./PointingToDeclaration/
-WARN: Missing @param tag for parameter `allocator` of function androidx\.media[0-9]+\.test\.utils/FakeMediaPeriod/createSampleStream/\#androidx\.media[0-9]+\.exoplayer\.upstream\.Allocator\#androidx\.media[0-9]+\.exoplayer\.source\.MediaSourceEventListener\.EventDispatcher\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionManager\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionEventListener\.EventDispatcher\#androidx\.media[0-9]+\.common\.Format\#java\.util\.List<androidx\.media[0-9]+\.test\.utils\.FakeSampleStream\.FakeSampleStreamItem>/PointingToDeclaration/
-WARN: Missing @param tag for parameter `timeline` of function androidx\.media[0-9]+\.test\.utils/TimelineAsserts/assertWindowTags/\#androidx\.media[0-9]+\.common\.Timeline\#java\.lang\.Object\.\.\./PointingToDeclaration/
-WARN: Missing @param tag for parameter `target` of function androidx\.media[0-9]+\.test\.utils/ActionSchedule\.Builder/sendMessage/\#androidx\.media[0-9]+\.exoplayer\.PlayerMessage\.Target\#long/PointingToDeclaration/
-WARN: Missing @param tag for parameter `sources` of function androidx\.media[0-9]+\.test\.utils/ActionSchedule\.Builder/setMediaSources/\#boolean\#androidx\.media[0-9]+\.exoplayer\.source\.MediaSource\.\.\./PointingToDeclaration/
-WARN: Missing @param tag for parameter `sources` of function androidx\.media[0-9]+\.test\.utils/ActionSchedule\.Builder/setMediaSources/\#int\#long\#androidx\.media[0-9]+\.exoplayer\.source\.MediaSource\.\.\./PointingToDeclaration/
WARN: Failed to resolve `@see <a href="http://developer\.android\.com/guide/topics/ui/controls/pickers\.html">Pickers API`!
WARN: Failed to resolve `@see <a href="http://developer\.android\.com/design/patterns/navigation\-drawer\.html">Navigation`!
WARN: Missing @param tag for parameter `verificationMode` of function androidx\.test\.espresso\.intent/Intents/intended/\#org\.hamcrest\.Matcher<android\.content\.Intent>\#androidx\.test\.espresso\.intent\.VerificationMode/PointingToDeclaration/
WARNING: link to @throws type AssertionFailedError does not resolve\. Is it from a package that the containing file does not import\? Is docs inherited to an un\-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\.`@throws java\.io\.IOException under some conditions\. This was observed in Throws\(root=CustomDocTag\(children=\[P\(children=\[Text\(body=if the given , children=\[\], params=\{\}\), DocumentationLink\(dri=org\.hamcrest/Matcher///PointingToDeclaration/, children=\[Text\(body=Matcher, children=\[\], params=\{\}\)\], params=\{\}\), Text\(body= did not match the expected number of recorded intents, children=\[\], params=\{\}\)\], params=\{\}\)\], params=\{\}, name=MARKDOWN_FILE\), name=AssertionFailedError, exceptionAddress=null\)\.`
WARNING: link to @throws type AssertionFailedError does not resolve\. Is it from a package that the containing file does not import\? Is docs inherited to an un\-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\.`@throws java\.io\.IOException under some conditions\. This was observed in Throws\(root=CustomDocTag\(children=\[P\(children=\[Text\(body=if the given , children=\[\], params=\{\}\), DocumentationLink\(dri=org\.hamcrest/Matcher///PointingToDeclaration/, children=\[Text\(body=Matcher, children=\[\], params=\{\}\)\], params=\{\}\), Text\(body= did not match any or matched more than one of the recorded intents, children=\[\], params=\{\}\)\], params=\{\}\)\], params=\{\}, name=MARKDOWN_FILE\), name=AssertionFailedError, exceptionAddress=null\)\.`
WARN: Missing @param tag for parameter `extras` of function androidx\.media[0-9]+\.session/MediaController/setMediaUri/\#android\.net\.Uri\#android\.os\.Bundle/PointingToDeclaration/
-WARN: Missing @param tag for parameter `trackType` of function androidx\.media[0-9]+\.common/Tracks/isTypeSupported/\#int\#boolean/PointingToDeclaration/
-WARN: Missing @param tag for parameter `adIndexInAdGroup` of function androidx\.media[0-9]+\.common/Timeline\.Period/getAdState/\#int\#int/PointingToDeclaration/
-WARN: Missing @param tag for parameter `dataSourceFactory` of function androidx\.media[0-9]+\.exoplayer\.drm/OfflineLicenseHelper/newWidevineInstance/\#java\.lang\.String\#boolean\#androidx\.media[0-9]+\.datasource\.DataSource\.Factory\#java\.util\.Map<java\.lang\.String,java\.lang\.String>\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionEventListener\.EventDispatcher/PointingToDeclaration/
-WARN: Missing @param tag for parameter `drmEventDispatcher` of function androidx\.media[0-9]+\.exoplayer\.hls/HlsMediaPeriod/HlsMediaPeriod/\#androidx\.media[0-9]+\.exoplayer\.hls\.HlsExtractorFactory\#androidx\.media[0-9]+\.exoplayer\.hls\.playlist\.HlsPlaylistTracker\#androidx\.media[0-9]+\.exoplayer\.hls\.HlsDataSourceFactory\#androidx\.media[0-9]+\.datasource\.TransferListener\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionManager\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionEventListener\.EventDispatcher\#androidx\.media[0-9]+\.exoplayer\.upstream\.LoadErrorHandlingPolicy\#androidx\.media[0-9]+\.exoplayer\.source\.MediaSourceEventListener\.EventDispatcher\#androidx\.media[0-9]+\.exoplayer\.upstream\.Allocator\#androidx\.media[0-9]+\.exoplayer\.source\.CompositeSequenceableLoaderFactory\#boolean\#int\#boolean\#androidx\.media[0-9]+\.exoplayer\.analytics\.PlayerId/PointingToDeclaration/
-WARN: Missing @param tag for parameter `metadataType` of function androidx\.media[0-9]+\.exoplayer\.hls/HlsMediaPeriod/HlsMediaPeriod/\#androidx\.media[0-9]+\.exoplayer\.hls\.HlsExtractorFactory\#androidx\.media[0-9]+\.exoplayer\.hls\.playlist\.HlsPlaylistTracker\#androidx\.media[0-9]+\.exoplayer\.hls\.HlsDataSourceFactory\#androidx\.media[0-9]+\.datasource\.TransferListener\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionManager\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionEventListener\.EventDispatcher\#androidx\.media[0-9]+\.exoplayer\.upstream\.LoadErrorHandlingPolicy\#androidx\.media[0-9]+\.exoplayer\.source\.MediaSourceEventListener\.EventDispatcher\#androidx\.media[0-9]+\.exoplayer\.upstream\.Allocator\#androidx\.media[0-9]+\.exoplayer\.source\.CompositeSequenceableLoaderFactory\#boolean\#int\#boolean\#androidx\.media[0-9]+\.exoplayer\.analytics\.PlayerId/PointingToDeclaration/
-WARN: Missing @param tag for parameter `playerId` of function androidx\.media[0-9]+\.exoplayer\.hls/HlsMediaPeriod/HlsMediaPeriod/\#androidx\.media[0-9]+\.exoplayer\.hls\.HlsExtractorFactory\#androidx\.media[0-9]+\.exoplayer\.hls\.playlist\.HlsPlaylistTracker\#androidx\.media[0-9]+\.exoplayer\.hls\.HlsDataSourceFactory\#androidx\.media[0-9]+\.datasource\.TransferListener\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionManager\#androidx\.media[0-9]+\.exoplayer\.drm\.DrmSessionEventListener\.EventDispatcher\#androidx\.media[0-9]+\.exoplayer\.upstream\.LoadErrorHandlingPolicy\#androidx\.media[0-9]+\.exoplayer\.source\.MediaSourceEventListener\.EventDispatcher\#androidx\.media[0-9]+\.exoplayer\.upstream\.Allocator\#androidx\.media[0-9]+\.exoplayer\.source\.CompositeSequenceableLoaderFactory\#boolean\#int\#boolean\#androidx\.media[0-9]+\.exoplayer\.analytics\.PlayerId/PointingToDeclaration/
-WARN: Missing @param tag for parameter `preciseStart` of function androidx\.media[0-9]+\.exoplayer\.hls\.playlist/HlsMediaPlaylist/HlsMediaPlaylist/\#int\#java\.lang\.String\#java\.util\.List<java\.lang\.String>\#long\#boolean\#long\#boolean\#int\#long\#int\#long\#long\#boolean\#boolean\#boolean\#androidx\.media[0-9]+\.common\.DrmInitData\#java\.util\.List<androidx\.media[0-9]+\.exoplayer\.hls\.playlist\.HlsMediaPlaylist\.Segment>\#java\.util\.List<androidx\.media[0-9]+\.exoplayer\.hls\.playlist\.HlsMediaPlaylist\.Part>\#androidx\.media[0-9]+\.exoplayer\.hls\.playlist\.HlsMediaPlaylist\.ServerControl\#java\.util\.Map<android\.net\.Uri,androidx\.media[0-9]+\.exoplayer\.hls\.playlist\.HlsMediaPlaylist\.RenditionReport>/PointingToDeclaration/
-WARN: Missing @param tag for parameter `partTargetDurationUs` of function androidx\.media[0-9]+\.exoplayer\.hls\.playlist/HlsMediaPlaylist/HlsMediaPlaylist/\#int\#java\.lang\.String\#java\.util\.List<java\.lang\.String>\#long\#boolean\#long\#boolean\#int\#long\#int\#long\#long\#boolean\#boolean\#boolean\#androidx\.media[0-9]+\.common\.DrmInitData\#java\.util\.List<androidx\.media[0-9]+\.exoplayer\.hls\.playlist\.HlsMediaPlaylist\.Segment>\#java\.util\.List<androidx\.media[0-9]+\.exoplayer\.hls\.playlist\.HlsMediaPlaylist\.Part>\#androidx\.media[0-9]+\.exoplayer\.hls\.playlist\.HlsMediaPlaylist\.ServerControl\#java\.util\.Map<android\.net\.Uri,androidx\.media[0-9]+\.exoplayer\.hls\.playlist\.HlsMediaPlaylist\.RenditionReport>/PointingToDeclaration/
-WARN: Missing @param tag for parameter `codecAdapterFactory` of function androidx\.media[0-9]+\.exoplayer\.mediacodec/MediaCodecRenderer/MediaCodecRenderer/\#int\#androidx\.media[0-9]+\.exoplayer\.mediacodec\.MediaCodecAdapter\.Factory\#androidx\.media[0-9]+\.exoplayer\.mediacodec\.MediaCodecSelector\#boolean\#float/PointingToDeclaration/
-WARN: Missing @param tag for parameter `dataSource` of function androidx\.media[0-9]+\.exoplayer\.offline/SegmentDownloader/getManifest/\#androidx\.media[0-9]+\.datasource\.DataSource\#androidx\.media[0-9]+\.datasource\.DataSpec\#boolean/PointingToDeclaration/
WARN: Use @androidx\.annotation\.Nullable, not @org\.checkerframework\.checker\.nullness\.qual/Nullable///PointingToDeclaration/
-WARN: Failed to resolve `@see <a href="http://msdn\.microsoft\.com/en\-us/library/ee[0-9]+\(v=vs\.[0-9]+\)\.aspx">IIS Smooth`!
-WARN: Missing @param tag for parameter `type` of function androidx\.media[0-9]+\.exoplayer\.trackselection/RandomTrackSelection/RandomTrackSelection/\#androidx\.media[0-9]+\.common\.TrackGroup\#int\[\]\#int\#java\.util\.Random/PointingToDeclaration/
-WARN: Missing @param tag for parameter `trackIndices` of function androidx\.media[0-9]+\.exoplayer\.trackselection/MappingTrackSelector\.MappedTrackInfo/getAdaptiveSupport/\#int\#int\#int\[\]/PointingToDeclaration/
-WARN: Missing @param tag for parameter `params` of function androidx\.media[0-9]+\.exoplayer\.trackselection/DefaultTrackSelector/selectAllTracks/\#androidx\.media[0-9]+\.exoplayer\.trackselection\.MappingTrackSelector\.MappedTrackInfo\#int\[\]\[\]\[\]\#int\[\]\#androidx\.media[0-9]+\.exoplayer\.trackselection\.DefaultTrackSelector\.Parameters/PointingToDeclaration/
-WARN: Failed to resolve `@see <a href="http://en\.wikipedia\.org/wiki/Moving_average">Wiki: Moving average</a>`!
-WARN: Failed to resolve `@see <a href="http://en\.wikipedia\.org/wiki/Selection_algorithm">Wiki: Selection algorithm</a>`!
-WARN: Missing @param tag for parameter `decoderName` of function androidx\.media[0-9]+\.exoplayer\.video/DecoderVideoRenderer/canReuseDecoder/\#java\.lang\.String\#androidx\.media[0-9]+\.common\.Format\#androidx\.media[0-9]+\.common\.Format/PointingToDeclaration/
-WARN: Missing @param tag for parameter `flacStreamMetadata` of function androidx\.media[0-9]+\.extractor/FlacFrameReader/getFirstSampleNumber/\#androidx\.media[0-9]+\.extractor\.ExtractorInput\#androidx\.media[0-9]+\.extractor\.FlacStreamMetadata/PointingToDeclaration/
-WARN: Failed to resolve `@see <a href="http://www\.w[0-9]+\.org/TR/ttaf[0-9]+\-dfxp/">TTML specification</a>`!
-WARN: Failed to resolve `@see <a href="http://dev\.w[0-9]+\.org/html[0-9]+/webvtt">WebVTT specification</a>`!
-WARN: Failed to resolve `@see <a href="https://www\.w[0-9]+\.org/TR/CSS[0-9]+/cascade\.html">CSS Cascading</a>`!
-Did you mean <a href="https://www\.w[0-9]+\.org/TR/CSS[0-9]+/cascade\#html">CSS Cascading</a>\?
WARN: Failed to resolve `@see <a href="https://developer\.android\.com/guide/topics/media/media\-routing">Media Routing</a>`!
WARN: Missing @param tag for parameter `context` of function androidx\.mediarouter\.media/RemotePlaybackClient/RemotePlaybackClient/\#android\.content\.Context\#androidx\.mediarouter\.media\.MediaRouter\.RouteInfo/PointingToDeclaration/
WARN: Failed to resolve `@see NavAction\.getDefaultArguments`!
@@ -595,23 +1094,139 @@
WARN: Missing @param tag for parameter `builder` of function androidx\.navigation\.dynamicfeatures\.fragment/DynamicFragmentNavigatorDestinationBuilderKt/fragment/androidx\.navigation\.dynamicfeatures\.DynamicNavGraphBuilder\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.navigation\.dynamicfeatures\.fragment\.DynamicFragmentNavigatorDestinationBuilder,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `builder` of function androidx\.navigation\.dynamicfeatures\.fragment/DynamicFragmentNavigatorDestinationBuilderKt/fragment/androidx\.navigation\.dynamicfeatures\.DynamicNavGraphBuilder\#kotlin\.String\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.navigation\.dynamicfeatures\.fragment\.DynamicFragmentNavigatorDestinationBuilder,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.animation//AnimatedVisibility/androidx\.compose\.foundation\.layout\.RowScope\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation//expandHorizontally/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntSize\]\#androidx\.compose\.ui\.Alignment\.Horizontal\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.HorizontalTransitionSample\. b/[0-9]+
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.animation//AnimatedVisibility/androidx\.compose\.foundation\.layout\.ColumnScope\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation//SizeTransform/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.IntSize,androidx\.compose\.ui\.unit\.IntSize,androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntSize\]\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatedContentTransitionSpecSample\. b/[0-9]+
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.animation//AnimatedVisibility/androidx\.compose\.foundation\.layout\.RowScope\#androidx\.compose\.animation\.core\.MutableTransitionState\[kotlin\.Boolean\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation//AnimatedVisibility/androidx\.compose\.foundation\.layout\.RowScope\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatedFloatingActionButton\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//animateColorAsState/\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.animation\.core\.AnimationSpec\[androidx\.compose\.ui\.graphics\.Color\]\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.Color,kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.ColorAnimationSample\. b/[0-9]+
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.animation//AnimatedVisibility/androidx\.compose\.foundation\.layout\.ColumnScope\#androidx\.compose\.animation\.core\.MutableTransitionState\[kotlin\.Boolean\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation//AnimatedVisibility/androidx\.compose\.foundation\.layout\.ColumnScope\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.ColumnAnimatedVisibilitySample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//Crossfade/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.CrossfadeSample\. b/[0-9]+
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.animation//AnimatedVisibility/\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `contentKey` of function androidx\.compose\.animation//Crossfade/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation//animateColor/androidx\.compose\.animation\.core\.InfiniteTransition\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.animation\.core\.InfiniteRepeatableSpec\[androidx\.compose\.ui\.graphics\.Color\]\#kotlin\.String/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.InfiniteTransitionSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.animation//Crossfade/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation//expandIn/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntSize\]\#androidx\.compose\.ui\.Alignment\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.IntSize,androidx\.compose\.ui\.unit\.IntSize\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.ExpandInShrinkOutSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//animateColor/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.core\.Transition\.Segment\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.graphics\.Color\]\]\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),androidx\.compose\.ui\.graphics\.Color\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.GestureAnimationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//expandVertically/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntSize\]\#androidx\.compose\.ui\.Alignment\.Vertical\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.ExpandShrinkVerticallySample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//fadeIn/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.FadeTransition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//animateContentSize/androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntSize\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.IntSize,androidx\.compose\.ui\.unit\.IntSize,kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimateContent\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//fadeOut/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.FadeTransition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//togetherWith/androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatedContentTransitionSpecSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//scaleIn/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TransformOrigin/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.ScaledEnterExit\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//scaleOut/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TransformOrigin/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.ScaledEnterExit\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//shrinkHorizontally/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntSize\]\#androidx\.compose\.ui\.Alignment\.Horizontal\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.HorizontalTransitionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//shrinkOut/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntSize\]\#androidx\.compose\.ui\.Alignment\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.IntSize,androidx\.compose\.ui\.unit\.IntSize\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.ExpandInShrinkOutSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//shrinkVertically/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntSize\]\#androidx\.compose\.ui\.Alignment\.Vertical\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.ExpandShrinkVerticallySample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//slideIn/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntOffset\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.IntSize,androidx\.compose\.ui\.unit\.IntOffset\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.SlideInOutSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//slideInHorizontally/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntOffset\]\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.SlideTransition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//slideInVertically/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntOffset\]\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.FullyLoadedTransition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//slideOut/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntOffset\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.IntSize,androidx\.compose\.ui\.unit\.IntOffset\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.SlideInOutSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//slideOutHorizontally/\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntOffset\]\#kotlin\.Function[0-9]+\[kotlin\.Int,kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.SlideTransition\. b/[0-9]+
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.animation//AnimatedVisibility/\#androidx\.compose\.animation\.core\.MutableTransitionState\[kotlin\.Boolean\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation//AnimatedVisibility/\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.FullyLoadedTransition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation//AnimatedVisibility/\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatedVisibilityWithBooleanVisibleParamNoReceiver\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.animation//Crossfade/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `initialValue` of function androidx\.compose\.animation\.core//animate/\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.animation\.core\.AnimationSpec\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//animateTo/androidx\.compose\.animation\.core\.AnimationState\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[androidx\.compose\.animation\.core\.AnimationVector\]\)\]\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.animation\.core\.AnimationSpec\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.core\.AnimationScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[androidx\.compose\.animation\.core\.AnimationVector\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.animateToOnAnimationState\. b/[0-9]+
WARN: Missing @param tag for parameter `targetValue` of function androidx\.compose\.animation\.core//animate/\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.animation\.core\.AnimationSpec\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//animateDpAsState/\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.animation\.core\.AnimationSpec\[androidx\.compose\.ui\.unit\.Dp\]\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.Dp,kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.DpAnimationSample\. b/[0-9]+
WARN: Missing @param tag for parameter `initialValue` of function androidx\.compose\.animation\.core//animateDecay/\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.animation\.core\.FloatDecayAnimationSpec\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `initialVelocity` of function androidx\.compose\.animation\.core//animateDecay/\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.animation\.core\.FloatDecayAnimationSpec\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//animateValue/androidx\.compose\.animation\.core\.InfiniteTransition\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.animation\.core\.TwoWayConverter\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[androidx\.compose\.animation\.core\.AnimationVector\]\)\]\#androidx\.compose\.animation\.core\.InfiniteRepeatableSpec\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.String/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.InfiniteTransitionAnimateValueSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//animateFloatAsState/\#kotlin\.Float\#androidx\.compose\.animation\.core\.AnimationSpec\[kotlin\.Float\]\#kotlin\.Float\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.AlphaAnimationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//animateIntOffsetAsState/\#androidx\.compose\.ui\.unit\.IntOffset\#androidx\.compose\.animation\.core\.AnimationSpec\[androidx\.compose\.ui\.unit\.IntOffset\]\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.IntOffset,kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.AnimateOffsetSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//createChildTransition/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.CreateChildTransitionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//animateOffsetAsState/\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.animation\.core\.AnimationSpec\[androidx\.compose\.ui\.geometry\.Offset\]\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.AnimateOffsetSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/Transition/createChildTransition/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.CreateChildTransitionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//animateValueAsState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.animation\.core\.TwoWayConverter\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[androidx\.compose\.animation\.core\.AnimationVector\]\)\]\#androidx\.compose\.animation\.core\.AnimationSpec\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\?\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.ArbitraryValueTypeTransitionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//infiniteRepeatable/\#androidx\.compose\.animation\.core\.DurationBasedAnimationSpec\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.compose\.animation\.core\.RepeatMode\#androidx\.compose\.animation\.core\.StartOffset/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.InfiniteProgressIndicator\. b/[0-9]+
WARN: Missing @param tag for parameter `typeConverter` of function androidx\.compose\.animation\.core//animateValueAsState/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.animation\.core\.TwoWayConverter\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[androidx\.compose\.animation\.core\.AnimationVector\]\)\]\#androidx\.compose\.animation\.core\.AnimationSpec\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\?\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]\?/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//keyframes/\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.core\.KeyframesSpec\.KeyframesSpecConfig\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.FloatKeyframesBuilderInline\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//keyframes/\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.core\.KeyframesSpec\.KeyframesSpecConfig\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.KeyframesBuilderWithEasing\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//rememberInfiniteTransition/\#kotlin\.String/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.InfiniteTransitionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//updateTransition/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.String\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.GestureAnimationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//updateTransition/\#androidx\.compose\.animation\.core\.MutableTransitionState\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.String\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.InitialStateSample\. b/[0-9]+
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.animation\.core/Animatable/Animatable/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.animation\.core\.TwoWayConverter\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[androidx\.compose\.animation\.core\.AnimationVector\]\)\]\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\?\#kotlin\.String/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/Animatable/animateDecay/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.animation\.core\.DecayAnimationSpec\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.core\.Animatable\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[androidx\.compose\.animation\.core\.AnimationVector\]\)\],kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.AnimatableDecayAndAnimateToSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/MutableTransitionState/isIdle/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.TransitionStateIsIdleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//Animatable/\#kotlin\.Float\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.AnimatableFadeIn\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/InfiniteTransition/animateFloat/androidx\.compose\.animation\.core\.InfiniteTransition\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.animation\.core\.InfiniteRepeatableSpec\[kotlin\.Float\]\#kotlin\.String/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.InfiniteTransitionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//animateFloat/androidx\.compose\.animation\.core\.InfiniteTransition\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.animation\.core\.InfiniteRepeatableSpec\[kotlin\.Float\]\#kotlin\.String/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.InfiniteTransitionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/InfiniteTransition/animateValue/androidx\.compose\.animation\.core\.InfiniteTransition\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.animation\.core\.TwoWayConverter\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[androidx\.compose\.animation\.core\.AnimationVector\]\)\]\#androidx\.compose\.animation\.core\.InfiniteRepeatableSpec\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.String/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.InfiniteTransitionAnimateValueSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/Animatable/animateTo/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.animation\.core\.AnimationSpec\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.core\.Animatable\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[androidx\.compose\.animation\.core\.AnimationVector\]\)\],kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.AnimatableFadeIn\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//animateFloat/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.core\.Transition\.Segment\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\]\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Float\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.AnimateFloatSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/Transition/AnimatedContent/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedContentTransitionScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],androidx\.compose\.animation\.ContentTransform\]\#androidx\.compose\.ui\.Alignment\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedContentScope,TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.TransitionExtensionAnimatedContentSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/KeyframesSpec\.KeyframesSpecConfig/with/androidx\.compose\.animation\.core\.KeyframesSpec\.KeyframeEntity\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.compose\.animation\.core\.Easing/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.KeyframesBuilderWithEasing\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/InfiniteTransition/animateColor/androidx\.compose\.animation\.core\.InfiniteTransition\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.animation\.core\.InfiniteRepeatableSpec\[androidx\.compose\.ui\.graphics\.Color\]\#kotlin\.String/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.InfiniteTransitionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/AnimationState/animateTo/androidx\.compose\.animation\.core\.AnimationState\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[androidx\.compose\.animation\.core\.AnimationVector\]\)\]\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.animation\.core\.AnimationSpec\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.core\.AnimationScope\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[androidx\.compose\.animation\.core\.AnimationVector\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.animateToOnAnimationState\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/Transition/AnimatedVisibility/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Boolean\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AddAnimatedVisibilityToGenericTransitionSample\. b/[0-9]+
WARN: Missing @param tag for parameter `contentKey` of function androidx\.compose\.animation\.core/Transition/Crossfade/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.animation\.core/Transition/Crossfade/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/Transition/animateColor/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.core\.Transition\.Segment\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.graphics\.Color\]\]\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),androidx\.compose\.ui\.graphics\.Color\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.GestureAnimationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core//animate/\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.animation\.core\.AnimationSpec\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.suspendAnimateFloatVariant\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/Transition/animateFloat/androidx\.compose\.animation\.core\.Transition\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.core\.Transition\.Segment\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],androidx\.compose\.animation\.core\.FiniteAnimationSpec\[kotlin\.Float\]\]\#kotlin\.String\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Float\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.AnimateFloatSample\. b/[0-9]+
WARN: Missing @param tag for parameter `animatedImageVector` of function androidx\.compose\.animation\.graphics\.res//rememberAnimatedVectorPainter/\#androidx\.compose\.animation\.graphics\.vector\.AnimatedImageVector\#kotlin\.Boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.animation\.graphics\.vector/AnimatedImageVector\.Companion/animatedVectorResource/androidx\.compose\.animation\.graphics\.vector\.AnimatedImageVector\.Companion\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.graphics\.samples\.AnimatedVectorSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation/ScrollState/canScrollBackward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation/MutatorMutex/mutateWith/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.foundation\.MutatePriority\#kotlin\.coroutines\.SuspendFunction[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.mutatorMutexStateObjectWithReceiver\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation/OverscrollEffect/applyToFling/\#androidx\.compose\.ui\.unit\.Velocity\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.unit\.Velocity,androidx\.compose\.ui\.unit\.Velocity\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.OverscrollWithDraggable_Before\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//background/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Brush\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DrawBackgroundShapedBrush\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//Canvas/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.drawscope\.DrawScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanvasSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation/ScrollState/canScrollForward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation/OverscrollEffect/applyToFling/\#androidx\.compose\.ui\.unit\.Velocity\#kotlin\.coroutines\.SuspendFunction[0-9]+\[androidx\.compose\.ui\.unit\.Velocity,androidx\.compose\.ui\.unit\.Velocity\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.OverscrollWithDraggable_After\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//background/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Shape/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DrawBackgroundColor\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//basicMarquee/androidx\.compose\.ui\.Modifier\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeAnimationMode\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeSpacing\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BasicMarqueeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation/OverscrollEffect/applyToScroll/\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollSource\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,androidx\.compose\.ui\.geometry\.Offset\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.OverscrollWithDraggable_Before\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//Canvas/\#androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.graphics\.drawscope\.DrawScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanvasPieChartSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation/OverscrollEffect/applyToScroll/\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.input\.nestedscroll\.NestedScrollSource\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,androidx\.compose\.ui\.geometry\.Offset\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.OverscrollWithDraggable_After\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//basicMarquee/androidx\.compose\.ui\.Modifier\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeAnimationMode\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeSpacing\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BasicFocusableMarqueeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//Image/\#androidx\.compose\.ui\.graphics\.ImageBitmap\#kotlin\.String\?\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\#androidx\.compose\.ui\.layout\.ContentScale\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.ColorFilter\?\#androidx\.compose\.ui\.graphics\.FilterQuality/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ImageSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//basicMarquee/androidx\.compose\.ui\.Modifier\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeAnimationMode\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.MarqueeSpacing\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BasicMarqueeWithFadedEdgesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//Image/\#androidx\.compose\.ui\.graphics\.ImageBitmap\#kotlin\.String\?\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\#androidx\.compose\.ui\.layout\.ContentScale\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.ColorFilter\?\#androidx\.compose\.ui\.graphics\.FilterQuality/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BitmapPainterSubsectionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//border/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.BorderStroke\#androidx\.compose\.ui\.graphics\.Shape/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BorderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//Image/\#androidx\.compose\.ui\.graphics\.painter\.Painter\#kotlin\.String\?\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\#androidx\.compose\.ui\.layout\.ContentScale\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.ColorFilter\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BitmapPainterSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//border/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Brush\#androidx\.compose\.ui\.graphics\.Shape/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BorderSampleWithBrush\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//border/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Brush\#androidx\.compose\.ui\.graphics\.Shape/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BorderSampleWithDynamicData\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//isSystemInDarkTheme/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DarkThemeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//rememberScrollState/\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ControlledScrollableRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//border/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Shape/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BorderSampleWithDataClass\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//clickable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ClickableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//clickable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ClickableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//combinedClickable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.String\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ClickableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//combinedClickable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.String\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ClickableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//focusGroup/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.FocusGroupSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//focusGroup/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.FocusableFocusGroupSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//focusable/androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.FocusableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//horizontalScroll/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.ScrollState\#kotlin\.Boolean\#androidx\.compose\.foundation\.gestures\.FlingBehavior\?\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.HorizontalScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//hoverable/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.HoverableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//indication/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.interaction\.InteractionSource\#androidx\.compose\.foundation\.Indication\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.IndicationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//magnifier/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.Density,androidx\.compose\.ui\.geometry\.Offset\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.Density,androidx\.compose\.ui\.geometry\.Offset\]\#kotlin\.Float\#androidx\.compose\.foundation\.MagnifierStyle\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.DpSize,kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.MagnifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//overscroll/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.OverscrollEffect/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.OverscrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//progressSemantics/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.IndeterminateProgressSemanticsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//progressSemantics/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DeterminateProgressSemanticsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation//verticalScroll/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.ScrollState\#kotlin\.Boolean\#androidx\.compose\.foundation\.gestures\.FlingBehavior\?\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.VerticalScrollExample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures/ScrollableState/canScrollBackward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures/ScrollableState/canScrollForward/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CanScrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//awaitDragOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//awaitHorizontalDragOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitHorizontalDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//awaitHorizontalTouchSlopOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitHorizontalDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//awaitLongPressOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitLongPressOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//awaitTouchSlopOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//awaitVerticalDragOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitVerticalDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//awaitVerticalTouchSlopOrCancellation/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.AwaitVerticalDragOrCancellationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//calculateCentroid/androidx\.compose\.ui\.input\.pointer\.PointerEvent\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CalculateCentroidSize\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//calculateCentroidSize/androidx\.compose\.ui\.input\.pointer\.PointerEvent\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CalculateCentroidSize\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//calculatePan/androidx\.compose\.ui\.input\.pointer\.PointerEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CalculatePan\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//calculateRotation/androidx\.compose\.ui\.input\.pointer\.PointerEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CalculateRotation\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//calculateZoom/androidx\.compose\.ui\.input\.pointer\.PointerEvent\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CalculateZoom\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//detectDragGestures/androidx\.compose\.ui\.input\.pointer\.PointerInputScope\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DetectDragGesturesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//detectDragGesturesAfterLongPress/androidx\.compose\.ui\.input\.pointer\.PointerInputScope\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DetectDragWithLongPressGesturesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//detectHorizontalDragGestures/androidx\.compose\.ui\.input\.pointer\.PointerInputScope\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DetectHorizontalDragGesturesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//detectTransformGestures/androidx\.compose\.ui\.input\.pointer\.PointerInputScope\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,androidx\.compose\.ui\.geometry\.Offset,kotlin\.Float,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DetectTransformGestures\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//detectVerticalDragGestures/androidx\.compose\.ui\.input\.pointer\.PointerInputScope\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.geometry\.Offset,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Float,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DetectVerticalDragGesturesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures//drag/androidx\.compose\.ui\.input\.pointer\.AwaitPointerEventScope\#androidx\.compose\.ui\.input\.pointer\.PointerId\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.input\.pointer\.PointerInputChange,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DragSample\. b/[0-9]+
WARN: Missing @param tag for parameter `requestedInitialKey` of function androidx\.paging/ItemKeyedDataSource\.LoadInitialParams/LoadInitialParams/\#TypeParam\(bounds=\[kotlin\.Any\]\)\?\#kotlin\.Int\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `requestedLoadSize` of function androidx\.paging/ItemKeyedDataSource\.LoadInitialParams/LoadInitialParams/\#TypeParam\(bounds=\[kotlin\.Any\]\)\?\#kotlin\.Int\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `placeholdersEnabled` of function androidx\.paging/ItemKeyedDataSource\.LoadInitialParams/LoadInitialParams/\#TypeParam\(bounds=\[kotlin\.Any\]\)\?\#kotlin\.Int\#kotlin\.Boolean/PointingToDeclaration/
@@ -625,13 +1240,91 @@
WARN: Missing @param tag for parameter `requestedLoadSize` of function androidx\.paging/PageKeyedDataSource\.LoadInitialParams/LoadInitialParams/\#kotlin\.Int\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `placeholdersEnabled` of function androidx\.paging/PageKeyedDataSource\.LoadInitialParams/LoadInitialParams/\#kotlin\.Int\#kotlin\.Boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.foundation\.layout//Column/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#androidx\.compose\.ui\.Alignment\.Horizontal\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//FlowColumn/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.FlowColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleFlowColumn\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/ColumnScope/weight/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleColumn\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//asPaddingValues/androidx\.compose\.foundation\.layout\.WindowInsets\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.paddingValuesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//asPaddingValues/androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.ui\.unit\.Density/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.paddingValuesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//FlowColumn/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.FlowColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleFlowColumnWithWeights\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//aspectRatio/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleAspectRatio\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//FlowRow/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.FlowRowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleFlowRow\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.foundation\.layout//Row/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#androidx\.compose\.ui\.Alignment\.Vertical\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//defaultMinSize/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.DefaultMinSizeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//Spacer/\#androidx\.compose\.ui\.Modifier/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SpacerExample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//displayCutoutPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.displayCutoutPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//WindowInsets/\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsDp\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//fillMaxHeight/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleFillHeightModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//WindowInsets/\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsInt\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//fillMaxHeight/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.FillHalfHeightModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//fillMaxSize/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleFillModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//fillMaxSize/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.FillHalfSizeModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//fillMaxWidth/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleFillWidthModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//fillMaxWidth/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.FillHalfWidthModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//height/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.IntrinsicSize/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.MatchParentDividerForText\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//height/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.IntrinsicSize/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.MatchParentDividerForAspectRatio\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//height/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleHeightModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//imeNestedScroll/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.windowInsetsNestedScrollDemo\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//imePadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.imePaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//mandatorySystemGesturesPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.mandatorySystemGesturesPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//navigationBarsPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.statusBarsAndNavigationBarsPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//offset/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.OffsetModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//offset/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.Density,androidx\.compose\.ui\.unit\.IntOffset\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.OffsetPxModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//onConsumedWindowInsetsChanged/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.WindowInsets,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.withConsumedInsetsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//padding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.PaddingValues/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingValuesModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//padding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//padding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SymmetricPaddingModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//padding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingAllModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//paddingFrom/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.layout\.AlignmentLine\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingFromSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//paddingFrom/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.layout\.AlignmentLine\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.unit\.TextUnit/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingFromSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//paddingFromBaseline/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingFromBaselineSampleDp\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//paddingFromBaseline/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.unit\.TextUnit/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingFromBaselineSampleTextUnit\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//requiredHeight/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleRequiredHeightModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//requiredSize/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleRequiredSizeModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//requiredWidth/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleRequiredWidthModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//safeContentPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.safeContentPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//safeDrawingPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.safeDrawingPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//safeGesturesPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.safeGesturesPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//size/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleSizeModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//size/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleSizeModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//size/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpSize/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleSizeModifierWithDpSize\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//statusBarsPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.statusBarsAndNavigationBarsPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//systemBarsPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.systemBarsPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//systemGesturesPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.systemGesturesPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//waterfallPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.waterfallPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//width/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.IntrinsicSize/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SameWidthBoxes\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//width/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.IntrinsicSize/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SameWidthTextBoxes\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//width/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleWidthModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//windowInsetsBottomHeight/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsBottomHeightSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//windowInsetsEndWidth/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsEndWidthSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//windowInsetsPadding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//windowInsetsStartWidth/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsStartWidthSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//windowInsetsTopHeight/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.insetsTopHeightSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//wrapContentHeight/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\.Vertical\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleWrapContentVerticallyAlignedModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//wrapContentSize/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleWrapContentAlignedModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//wrapContentWidth/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\.Horizontal\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleWrapContentHorizontallyAlignedModifier\. b/[0-9]+
WARN: Missing @param tag for parameter `matchHeightConstraintsFirst` of function androidx\.compose\.foundation\.layout//aspectRatio/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.Boolean/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//captionBarPadding/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.captionBarPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//FlowRow/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.FlowRowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleFlowRowWithWeights\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//consumeWindowInsets/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.PaddingValues/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.consumedInsetsPaddingSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//consumeWindowInsets/androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.consumedInsetsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//Row/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.Arrangement\.Horizontal\#androidx\.compose\.ui\.Alignment\.Vertical\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleRow\. b/[0-9]+
WARN: Missing @param tag for parameter `target` of function androidx\.palette\.graphics/Palette/getColorForTarget/\#androidx\.palette\.graphics\.Target\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.foundation\.layout/ColumnScope/AnimatedVisibility/androidx\.compose\.foundation\.layout\.ColumnScope\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.foundation\.layout/ColumnScope/AnimatedVisibility/androidx\.compose\.foundation\.layout\.ColumnScope\#androidx\.compose\.animation\.core\.MutableTransitionState\[kotlin\.Boolean\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//BoxWithConstraints/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.Alignment\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.BoxWithConstraintsScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.BoxWithConstraintsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/RowScope/alignBy/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.layout\.HorizontalAlignmentLine/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleAlignByInRow\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//absoluteOffset/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.Density,androidx\.compose\.ui\.unit\.IntOffset\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.AbsoluteOffsetPxModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/ColumnScope/alignBy/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.Measured,kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleRelativeToSiblings\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/RowScope/alignBy/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.layout\.Measured,kotlin\.Int\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleAlignByInRow\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/RowScope/alignByBaseline/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleAlignByInRow\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//Column/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.layout\.Arrangement\.Vertical\#androidx\.compose\.ui\.Alignment\.Horizontal\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleColumn\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//absolutePadding/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.AbsolutePaddingModifier\. b/[0-9]+
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.foundation\.layout/RowScope/AnimatedVisibility/androidx\.compose\.foundation\.layout\.RowScope\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `label` of function androidx\.compose\.foundation\.layout/RowScope/AnimatedVisibility/androidx\.compose\.foundation\.layout\.RowScope\#androidx\.compose\.animation\.core\.MutableTransitionState\[kotlin\.Boolean\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/ColumnScope/AnimatedVisibility/androidx\.compose\.foundation\.layout\.ColumnScope\#androidx\.compose\.animation\.core\.MutableTransitionState\[kotlin\.Boolean\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AVColumnScopeWithMutableTransitionState\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//absoluteOffset/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.AbsoluteOffsetModifier\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/ColumnScope/alignBy/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.layout\.VerticalAlignmentLine/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleRelativeToSiblingsInColumn\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/WindowInsets/asPaddingValues/androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.ui\.unit\.Density/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.paddingValuesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout//Box/\#androidx\.compose\.ui\.Modifier/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleBox\. b/[0-9]+
WARN: Missing @param tag for parameter `block` of function androidx\.compose\.foundation\.lazy\.layout/MutableIntervalList/forEach/\#kotlin\.Int\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.layout\.IntervalList\.Interval\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `block` of function androidx\.compose\.foundation\.lazy\.layout/IntervalList/forEach/\#kotlin\.Int\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.lazy\.layout\.IntervalList\.Interval\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `properties` of function androidx\.privacysandbox\.tools\.core\.generator/KotlinPoetSpecsKt/primaryConstructor/com\.squareup\.kotlinpoet\.TypeSpec\.Builder\#kotlin\.collections\.List\[com\.squareup\.kotlinpoet\.PropertySpec\]\#kotlin\.Array\[com\.squareup\.kotlinpoet\.KModifier\]/PointingToDeclaration/
@@ -657,30 +1350,79 @@
WARN: Missing @param tag for parameter `payload` of function androidx\.recyclerview\.widget/SortedListAdapterCallback/onChanged/\#int\#int\#java\.lang\.Object/PointingToDeclaration/
WARN: Missing @param tag for parameter `backgroundColor` of function androidx\.compose\.material//BottomSheetScaffold/\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.BottomSheetScaffoldState\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.SnackbarHostState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material\.FabPosition\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.PaddingValues,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `contentColor` of function androidx\.compose\.material//BottomSheetScaffold/\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.BottomSheetScaffoldState\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.SnackbarHostState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material\.FabPosition\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.PaddingValues,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//Button/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.ButtonElevation\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ButtonColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Button/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.ButtonElevation\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ButtonColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ButtonWithIconSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Card/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.CardSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//Button/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.ButtonElevation\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ButtonColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//Card/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ClickableCardSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//Card/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//Card/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//Chip/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ChipColors\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.OutlinedChipWithIconSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Chip/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ChipColors\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ChipGroupSingleLineSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Chip/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ChipColors\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ChipGroupReflowSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//Card/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `shape` of function androidx\.compose\.material//Chip/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ChipColors\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//CircularProgressIndicator/\#kotlin\.Float\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.StrokeCap/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.CircularProgressIndicatorSample\. b/[0-9]+
WARN: Missing @param tag for parameter `modifier` of function androidx\.compose\.material//CircularProgressIndicator/\#kotlin\.Float\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/
WARN: Missing @param tag for parameter `modifier` of function androidx\.compose\.material//CircularProgressIndicator/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/
WARN: Missing @param tag for parameter `modifier` of function androidx\.compose\.material//Divider/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//DropdownMenu/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpOffset\#androidx\.compose\.foundation\.ScrollState\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.MenuSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//DropdownMenu/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpOffset\#androidx\.compose\.foundation\.ScrollState\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.MenuWithScrollStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//DropdownMenuItem/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.MenuSample\. b/[0-9]+
WARN: Missing @param tag for parameter `modifier` of function androidx\.compose\.material//DropdownMenu/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpOffset\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `properties` of function androidx\.compose\.material//DropdownMenu/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpOffset\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//DropdownMenu/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpOffset\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//DropdownMenuItem/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//ExposedDropdownMenuBox/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.ExposedDropdownMenuBoxScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ExposedDropdownMenuSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//ExposedDropdownMenuBox/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.ExposedDropdownMenuBoxScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.EditableExposedDropdownMenuSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//ExtendedFloatingActionButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.material\.FloatingActionButtonElevation/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SimpleExtendedFabWithIcon\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//ExtendedFloatingActionButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.material\.FloatingActionButtonElevation/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.FluidExtendedFab\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//FilterChip/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.SelectableChipColors\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.FilterChipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//FilterChip/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.SelectableChipColors\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.FilterChipWithLeadingIconSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//FilterChip/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.SelectableChipColors\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.OutlinedFilterChipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//FloatingActionButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.material\.FloatingActionButtonElevation\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SimpleFab\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//IconButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.IconButtonSample\. b/[0-9]+
WARN: Missing @param tag for parameter `modifier` of function androidx\.compose\.material//LinearProgressIndicator/\#kotlin\.Float\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/
WARN: Missing @param tag for parameter `modifier` of function androidx\.compose\.material//LinearProgressIndicator/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//MaterialTheme/\#androidx\.compose\.material\.Colors\#androidx\.compose\.material\.Typography\#androidx\.compose\.material\.Shapes\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//ModalBottomSheetLayout/\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material\.ModalBottomSheetState\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ModalBottomSheetSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//OutlinedButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.ButtonElevation\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ButtonColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//Surface/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//Surface/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SelectableSurfaceSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//Surface/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//Switch/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.SwitchColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SwitchSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Tab/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.FancyTab\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.TextTabs\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.FancyTabs\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.FancyTab\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.FancyIndicator\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.FancyIndicatorTabs\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.FancyAnimatedIndicator\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//Surface/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//Surface/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ToggleableSurfaceSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//Surface/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//Surface/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ClickableSurfaceSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//Surface/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ClickableSurfaceSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//Surface/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.Indication\?\#kotlin\.Boolean\#kotlin\.String\?\#androidx\.compose\.ui\.semantics\.Role\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//SwipeToDismiss/\#androidx\.compose\.material\.DismissState\#androidx\.compose\.ui\.Modifier\#kotlin\.collections\.Set\[androidx\.compose\.material\.DismissDirection\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material\.DismissDirection,androidx\.compose\.material\.ThresholdConfig\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SwipeToDismissListItems\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material//TextButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.ButtonElevation\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.material\.ButtonColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//TextField/\#androidx\.compose\.ui\.text\.input\.TextFieldValue\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.input\.TextFieldValue,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.TextFieldSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SimpleTextFieldSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.TextFieldWithPlaceholder\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.TextFieldWithIcons\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.TextFieldWithErrorState\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.TextFieldWithHelperMessage\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.PasswordTextField\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.TextFieldWithHideKeyboardOnImeAction\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TopAppBar/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.SimpleTopAppBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//TriStateCheckbox/\#androidx\.compose\.ui\.state\.ToggleableState\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.material\.CheckboxColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.TriStateCheckboxSample\. b/[0-9]+
WARN: Missing @param tag for parameter `leadingIconContentColor` of function androidx\.compose\.material/ChipDefaults/outlinedChipColors/\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material//LocalContentAlpha/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ContentAlphaSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//AlertDialog/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.window\.DialogProperties/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.AlertDialogSample\. b/[0-9]+
WARN: Missing @param tag for parameter `shape` of function androidx\.compose\.material/TextFieldDefaults/BorderBox/\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.InteractionSource\#androidx\.compose\.material\.TextFieldColors\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material/MaterialTheme/colors/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.ThemeColorSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material/TextFieldDefaults/OutlinedTextFieldDecorationBox/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.interaction\.InteractionSource\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material\.TextFieldColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.CustomOutlinedTextFieldBasedOnDecorationBox\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material//AlertDialog/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.window\.DialogProperties/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.samples\.CustomAlertDialogSample\. b/[0-9]+
WARN: Missing @param tag for parameter `context` of function androidx\.security\.crypto//EncryptedSharedPreferences/\#android\.content\.Context\#kotlin\.String\#androidx\.security\.crypto\.MasterKey\#androidx\.security\.crypto\.EncryptedSharedPreferences\.PrefKeyEncryptionScheme\#androidx\.security\.crypto\.EncryptedSharedPreferences\.PrefValueEncryptionScheme/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.security\.crypto/EncryptedSharedPreferences/create/\#android\.content\.Context\#java\.lang\.String\#androidx\.security\.crypto\.MasterKey\#androidx\.security\.crypto\.EncryptedSharedPreferences\.PrefKeyEncryptionScheme\#androidx\.security\.crypto\.EncryptedSharedPreferences\.PrefValueEncryptionScheme/PointingToDeclaration/
WARN: Missing @param tag for parameter `keyAlias` of function androidx\.security\.crypto/MasterKey\.Builder/Builder/\#android\.content\.Context\#java\.lang\.String/PointingToDeclaration/
@@ -702,32 +1444,153 @@
WARN: Missing @param tag for parameter `action` of function androidx\.slice\.builders/ListBuilder\.RowBuilder/setTitleItem/\#androidx\.slice\.builders\.SliceAction\#boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `color` of function androidx\.slice\.widget/GridRowView/addImageItem/\#androidx\.slice\.SliceItem\#androidx\.slice\.SliceItem\#int\#android\.view\.ViewGroup\#boolean/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//Button/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.material[0-9]+\.ButtonElevation\?\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Card/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#androidx\.compose\.foundation\.BorderStroke\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.CardSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//Card/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#androidx\.compose\.foundation\.BorderStroke\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Card/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ClickableCardSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//Card/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//CenterAlignedTopAppBar/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.material[0-9]+\.TopAppBarColors\#androidx\.compose\.material[0-9]+\.TopAppBarScrollBehavior\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SimpleCenterAlignedTopAppBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Checkbox/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.CheckboxColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.CheckboxSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Checkbox/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.CheckboxColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.CheckboxWithTextSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//CircularProgressIndicator/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.StrokeCap/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.IndeterminateCircularProgressIndicatorSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//CircularProgressIndicator/\#kotlin\.Float\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.StrokeCap/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.CircularProgressIndicatorSample\. b/[0-9]+
WARN: Missing @param tag for parameter `modifier` of function androidx\.compose\.material[0-9]+//DropdownMenu/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpOffset\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `properties` of function androidx\.compose\.material[0-9]+//DropdownMenu/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpOffset\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//DropdownMenu/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.DpOffset\#androidx\.compose\.ui\.window\.PopupProperties\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//ElevatedButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.material[0-9]+\.ButtonElevation\?\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ElevatedCard/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ElevatedCardSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//ElevatedCard/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ElevatedCard/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ClickableElevatedCardSample\. b/[0-9]+
WARN: Missing @param tag for parameter `body` of function androidx\.sqlite\.db//transaction/androidx\.sqlite\.db\.SupportSQLiteDatabase\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.sqlite\.db\.SupportSQLiteDatabase,TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//ElevatedCard/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ElevatedFilterChip/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.SelectableChipColors\#androidx\.compose\.material[0-9]+\.SelectableChipElevation\?\#androidx\.compose\.material[0-9]+\.SelectableChipBorder\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ElevatedFilterChipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ElevatedSuggestionChip/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ChipColors\#androidx\.compose\.material[0-9]+\.ChipElevation\?\#androidx\.compose\.material[0-9]+\.ChipBorder\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ElevatedSuggestionChipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ExposedDropdownMenuBox/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.ExposedDropdownMenuBoxScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ExposedDropdownMenuSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ExposedDropdownMenuBox/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.ExposedDropdownMenuBoxScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.EditableExposedDropdownMenuSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ExtendedFloatingActionButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.material[0-9]+\.FloatingActionButtonElevation\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ExtendedFloatingActionButtonTextSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ExtendedFloatingActionButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.material[0-9]+\.FloatingActionButtonElevation\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ExtendedFloatingActionButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ExtendedFloatingActionButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.material[0-9]+\.FloatingActionButtonElevation\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.AnimatedExtendedFloatingActionButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//FilledIconButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.IconButtonColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FilledIconButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//FilledIconToggleButton/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.IconToggleButtonColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FilledIconToggleButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//FilledTonalButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.material[0-9]+\.ButtonElevation\?\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FilledTonalButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//FilledTonalIconButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.IconButtonColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FilledTonalIconButtonSample\. b/[0-9]+
WARN: Missing @param tag for parameter `body` of function androidx\.sqlite\.db/SupportSQLiteDatabaseKt/transaction/androidx\.sqlite\.db\.SupportSQLiteDatabase\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.sqlite\.db\.SupportSQLiteDatabase,TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `body` of function androidx\.sqlite\.db/SupportSQLiteDatabase/transaction/androidx\.sqlite\.db\.SupportSQLiteDatabase\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[androidx\.sqlite\.db\.SupportSQLiteDatabase,TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//FilledTonalButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.material[0-9]+\.ButtonElevation\?\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//FilledTonalIconToggleButton/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.IconToggleButtonColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FilledTonalIconToggleButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//FilterChip/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.SelectableChipColors\#androidx\.compose\.material[0-9]+\.SelectableChipElevation\?\#androidx\.compose\.material[0-9]+\.SelectableChipBorder\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FilterChipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//FilterChip/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.SelectableChipColors\#androidx\.compose\.material[0-9]+\.SelectableChipElevation\?\#androidx\.compose\.material[0-9]+\.SelectableChipBorder\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FilterChipWithLeadingIconSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//FloatingActionButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.material[0-9]+\.FloatingActionButtonElevation\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FloatingActionButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//IconButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.IconButtonColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.IconButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//IconToggleButton/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.IconToggleButtonColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.IconToggleButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//InputChip/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.SelectableChipColors\#androidx\.compose\.material[0-9]+\.SelectableChipElevation\?\#androidx\.compose\.material[0-9]+\.SelectableChipBorder\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.InputChipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//InputChip/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.SelectableChipColors\#androidx\.compose\.material[0-9]+\.SelectableChipElevation\?\#androidx\.compose\.material[0-9]+\.SelectableChipBorder\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.InputChipWithAvatarSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//InputChip/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.SelectableChipColors\#androidx\.compose\.material[0-9]+\.SelectableChipElevation\?\#androidx\.compose\.material[0-9]+\.SelectableChipBorder\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ChipGroupSingleLineSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//InputChip/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.SelectableChipColors\#androidx\.compose\.material[0-9]+\.SelectableChipElevation\?\#androidx\.compose\.material[0-9]+\.SelectableChipBorder\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ChipGroupReflowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//LargeFloatingActionButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.material[0-9]+\.FloatingActionButtonElevation\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.LargeFloatingActionButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//LargeTopAppBar/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.material[0-9]+\.TopAppBarColors\#androidx\.compose\.material[0-9]+\.TopAppBarScrollBehavior\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ExitUntilCollapsedLargeTopAppBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ModalBottomSheet/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.SheetState\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ModalBottomSheetSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//LinearProgressIndicator/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.StrokeCap/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.IndeterminateLinearProgressIndicatorSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//LinearProgressIndicator/\#kotlin\.Float\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.StrokeCap/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.LinearProgressIndicatorSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ListItem/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.ListItemColors\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.OneLineListItem\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ListItem/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.ListItemColors\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TwoLineListItem\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ListItem/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.ListItemColors\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ThreeLineListItem\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//MediumTopAppBar/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.material[0-9]+\.TopAppBarColors\#androidx\.compose\.material[0-9]+\.TopAppBarScrollBehavior\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ExitUntilCollapsedMediumTopAppBar\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//MaterialTheme/\#androidx\.compose\.material[0-9]+\.ColorScheme\#androidx\.compose\.material[0-9]+\.Shapes\#androidx\.compose\.material[0-9]+\.Typography\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ModalBottomSheet/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.SheetState\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.foundation\.layout\.WindowInsets\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ModalBottomSheetSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//ModalNavigationDrawer/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.DrawerState\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ModalNavigationDrawerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//NavigationBar/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.layout\.WindowInsets\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.NavigationBarSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//NavigationDrawerItem/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.NavigationDrawerItemColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ModalNavigationDrawerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//NavigationRail/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\?\#androidx\.compose\.foundation\.layout\.WindowInsets\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.NavigationRailSample\. b/[0-9]+
WARN: Missing @param tag for parameter `shape` of function androidx\.compose\.material[0-9]+//NavigationDrawerItem/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.NavigationDrawerItemColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//OutlinedButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.material[0-9]+\.ButtonElevation\?\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.OutlinedButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//OutlinedCard/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#androidx\.compose\.foundation\.BorderStroke\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.OutlinedCardSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//OutlinedButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.material[0-9]+\.ButtonElevation\?\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//OutlinedCard/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#androidx\.compose\.foundation\.BorderStroke\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ClickableOutlinedCardSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//OutlinedCard/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#androidx\.compose\.foundation\.BorderStroke\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//OutlinedIconButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.IconButtonColors\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.OutlinedIconButtonSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//OutlinedCard/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.CardColors\#androidx\.compose\.material[0-9]+\.CardElevation\#androidx\.compose\.foundation\.BorderStroke\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//OutlinedIconToggleButton/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.IconToggleButtonColors\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.OutlinedIconToggleButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//OutlinedTextField/\#androidx\.compose\.ui\.text\.input\.TextFieldValue\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.input\.TextFieldValue,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.OutlinedTextFieldSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//OutlinedTextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SimpleOutlinedTextFieldSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//PermanentNavigationDrawer/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.PermanentNavigationDrawerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//PlainTooltipBox/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.PlainTooltipState\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.TooltipBoxScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.PlainTooltipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//PlainTooltipBox/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.PlainTooltipState\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.TooltipBoxScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.PlainTooltipWithManualInvocationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//RadioButton/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.RadioButtonColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.RadioButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//RadioButton/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.RadioButtonColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.RadioGroupSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//RangeSlider/\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\],kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderPositions,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderPositions,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderPositions,kotlin\.Unit\]\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.RangeSliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//RangeSlider/\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\],kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderPositions,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderPositions,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderPositions,kotlin\.Unit\]\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.StepRangeSliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//RangeSlider/\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\],kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderPositions,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderPositions,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderPositions,kotlin\.Unit\]\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.RangeSliderWithCustomComponents\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//RangeSlider/\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\],kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Int\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.SliderColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.RangeSliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//RangeSlider/\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Function[0-9]+\[kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\],kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Int\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.SliderColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.StepRangeSliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//RichTooltipBox/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.RichTooltipState\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.RichTooltipColors\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.TooltipBoxScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.RichTooltipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//RichTooltipBox/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.RichTooltipState\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.RichTooltipColors\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.TooltipBoxScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.RichTooltipWithManualInvocationSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Scaffold/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.material[0-9]+\.FabPosition\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.layout\.WindowInsets\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.PaddingValues,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SimpleScaffoldWithTopBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Scaffold/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.material[0-9]+\.FabPosition\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.layout\.WindowInsets\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.PaddingValues,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ScaffoldWithSimpleSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//SearchBar/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.SearchBarColors\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SearchBarSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Slider/\#androidx\.compose\.material[0-9]+\.SliderState\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Slider/\#androidx\.compose\.material[0-9]+\.SliderState\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.StepsSliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Slider/\#androidx\.compose\.material[0-9]+\.SliderState\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SliderWithCustomThumbSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Slider/\#androidx\.compose\.material[0-9]+\.SliderState\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SliderWithCustomTrackAndThumb\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Slider/\#kotlin\.Float\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Slider/\#kotlin\.Float\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.StepsSliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Slider/\#kotlin\.Float\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SliderWithCustomThumbSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Slider/\#kotlin\.Float\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Int\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SliderState,kotlin\.Unit\]\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SliderWithCustomTrackAndThumb\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Slider/\#kotlin\.Float\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Int\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Slider/\#kotlin\.Float\#kotlin\.Function[0-9]+\[kotlin\.Float,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.ranges\.ClosedFloatingPointRange\[kotlin\.Float\]\#kotlin\.Int\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.SliderColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.StepsSliderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//SmallFloatingActionButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.material[0-9]+\.FloatingActionButtonElevation\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SmallFloatingActionButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Snackbar/\#androidx\.compose\.material[0-9]+\.SnackbarData\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ScaffoldWithSimpleSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Snackbar/\#androidx\.compose\.material[0-9]+\.SnackbarData\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ScaffoldWithCustomSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Snackbar/\#androidx\.compose\.material[0-9]+\.SnackbarData\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ScaffoldWithIndefiniteSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//SmallTopAppBar/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.material[0-9]+\.TopAppBarColors\#androidx\.compose\.material[0-9]+\.TopAppBarScrollBehavior\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SimpleTopAppBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Snackbar/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ScaffoldWithSimpleSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Snackbar/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ScaffoldWithCustomSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Snackbar/\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ScaffoldWithMultilineSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//SmallTopAppBar/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.material[0-9]+\.TopAppBarColors\#androidx\.compose\.material[0-9]+\.TopAppBarScrollBehavior\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.PinnedTopAppBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//SnackbarHost/\#androidx\.compose\.material[0-9]+\.SnackbarHostState\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SnackbarData,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ScaffoldWithSimpleSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//SnackbarHost/\#androidx\.compose\.material[0-9]+\.SnackbarHostState\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SnackbarData,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ScaffoldWithCustomSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//SuggestionChip/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ChipColors\#androidx\.compose\.material[0-9]+\.ChipElevation\?\#androidx\.compose\.material[0-9]+\.ChipBorder\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SuggestionChipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//SmallTopAppBar/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.material[0-9]+\.TopAppBarColors\#androidx\.compose\.material[0-9]+\.TopAppBarScrollBehavior\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.EnterAlwaysTopAppBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Surface/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.BorderStroke\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SurfaceSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Surface/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SelectableSurfaceSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Surface/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ToggleableSurfaceSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Surface/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ClickableSurfaceSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//SwipeToDismiss/\#androidx\.compose\.material[0-9]+\.DismissState\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.collections\.Set\[androidx\.compose\.material[0-9]+\.DismissDirection\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SwipeToDismissListItems\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Switch/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.SwitchColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SwitchSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//Surface/\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.BorderStroke\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Switch/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.SwitchColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SwitchWithThumbIconSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//Surface/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material[0-9]+\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TextTabs\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material[0-9]+\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FancyTabs\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material[0-9]+\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FancyTab\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material[0-9]+\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FancyIndicator\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material[0-9]+\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FancyIndicatorTabs\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material[0-9]+\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FancyAnimatedIndicator\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TabRow/\#kotlin\.Int\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[androidx\.compose\.material[0-9]+\.TabPosition\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FancyIndicatorContainerTabs\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TextButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.material[0-9]+\.ButtonElevation\?\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TextButtonSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//Surface/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Tab/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.FancyTab\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//Surface/\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Boolean,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `maxSwipes` of function androidx\.test\.uiautomator/UiScrollable/scrollToBeginning/\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `maxSwipes` of function androidx\.test\.uiautomator/UiScrollable/scrollToEnd/\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `type` of function androidx\.textclassifier/TextClassification\.Builder/setEntityType/\#java\.lang\.String\#float/PointingToDeclaration/
WARN: Missing @param tag for parameter `type` of function androidx\.textclassifier/TextSelection\.Builder/setEntityType/\#java\.lang\.String\#float/PointingToDeclaration/
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.material[0-9]+//TextButton/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.material[0-9]+\.ButtonElevation\?\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TextField/\#androidx\.compose\.ui\.text\.input\.TextFieldValue\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.text\.input\.TextFieldValue,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TextFieldSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SimpleTextFieldSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TextFieldWithPlaceholder\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TextFieldWithIcons\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TextFieldWithPrefixAndSuffix\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TextFieldWithErrorState\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TextFieldWithSupportingText\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.PasswordTextField\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TextField/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.String,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.TextStyle\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.text\.KeyboardOptions\#androidx\.compose\.foundation\.text\.KeyboardActions\#kotlin\.Boolean\#kotlin\.Int\#kotlin\.Int\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TextFieldWithHideKeyboardOnImeAction\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TimeInput/\#androidx\.compose\.material[0-9]+\.TimePickerState\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.TimePickerColors/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TimeInputSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TimePicker/\#androidx\.compose\.material[0-9]+\.TimePickerState\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.TimePickerColors\#androidx\.compose\.material[0-9]+\.TimePickerLayoutType/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TimePickerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TimePicker/\#androidx\.compose\.material[0-9]+\.TimePickerState\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.TimePickerColors\#androidx\.compose\.material[0-9]+\.TimePickerLayoutType/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TimePickerSwitchableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TopAppBar/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.material[0-9]+\.TopAppBarColors\#androidx\.compose\.material[0-9]+\.TopAppBarScrollBehavior\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SimpleTopAppBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TopAppBar/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.material[0-9]+\.TopAppBarColors\#androidx\.compose\.material[0-9]+\.TopAppBarScrollBehavior\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.PinnedTopAppBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TopAppBar/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.foundation\.layout\.WindowInsets\#androidx\.compose\.material[0-9]+\.TopAppBarColors\#androidx\.compose\.material[0-9]+\.TopAppBarScrollBehavior\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.EnterAlwaysTopAppBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//TriStateCheckbox/\#androidx\.compose\.ui\.state\.ToggleableState\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.CheckboxColors\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TriStateCheckboxSample\. b/[0-9]+
WARN: Missing @param tag for parameter `block` of function androidx\.tracing//traceAsync/\#kotlin\.String\#kotlin\.Int\#kotlin\.coroutines\.SuspendFunction[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `block` of function androidx\.tracing//traceAsync/\#kotlin\.Function[0-9]+\[kotlin\.String\]\#kotlin\.Function[0-9]+\[kotlin\.Int\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `block` of function androidx\.tracing/TraceKt/traceAsync/\#kotlin\.String\#kotlin\.Int\#kotlin\.coroutines\.SuspendFunction[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/
@@ -743,17 +1606,104 @@
WARN: Missing @param tag for parameter `label` of function androidx\.tv\.material\.immersivelist/ImmersiveListBackgroundScope/AnimatedVisibility/\#kotlin\.Boolean\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.EnterTransition\#androidx\.compose\.animation\.ExitTransition\#kotlin\.String\#kotlin\.Function[0-9]+\[androidx\.compose\.animation\.AnimatedVisibilityScope,kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `disabledElevation` of function androidx\.compose\.material[0-9]+/CardDefaults/cardElevation/\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/
WARN: Missing @param tag for parameter `disabledElevation` of function androidx\.compose\.material[0-9]+/CardDefaults/elevatedCardElevation/\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+/OutlinedTextFieldDefaults/DecorationBox/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.interaction\.InteractionSource\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.material[0-9]+\.TextFieldColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.CustomOutlinedTextFieldBasedOnDecorationBox\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+/SnackbarHostState/showSnackbar/\#androidx\.compose\.material[0-9]+\.SnackbarVisuals/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ScaffoldWithCustomSnackbar\. b/[0-9]+
WARN: Missing @param tag for parameter `disabledElevation` of function androidx\.compose\.material[0-9]+/CardDefaults/outlinedCardElevation/\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/
WARN: Missing @param tag for parameter `thumbSize` of function androidx\.compose\.material[0-9]+/SliderDefaults/Thumb/\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.SliderColors\#kotlin\.Boolean\#androidx\.compose\.ui\.unit\.DpSize/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//AlertDialog/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.window\.DialogProperties\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.AlertDialogWithCustomContentSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+/TextFieldDefaults/DecorationBox/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.interaction\.InteractionSource\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.CustomTextFieldBasedOnDecorationBox\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+/SnackbarHostState/showSnackbar/\#kotlin\.String\#kotlin\.String\?\#kotlin\.Boolean\#androidx\.compose\.material[0-9]+\.SnackbarDuration/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ScaffoldWithCoroutinesSnackbar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//AlertDialog/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.window\.DialogProperties/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.AlertDialogSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//AlertDialog/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.window\.DialogProperties/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.AlertDialogWithIconSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//AssistChip/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ChipColors\#androidx\.compose\.material[0-9]+\.ChipElevation\?\#androidx\.compose\.material[0-9]+\.ChipBorder\?\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.AssistChipSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//BadgedBox/\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.BoxScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.BoxScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.NavigationBarItemWithBadge\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//BottomAppBar/\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SimpleBottomAppBar\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//BottomAppBar/\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.layout\.WindowInsets/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.BottomAppBarWithFAB\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//BottomSheetScaffold/\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.ColumnScope,kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#androidx\.compose\.material[0-9]+\.BottomSheetScaffoldState\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[androidx\.compose\.material[0-9]+\.SnackbarHostState,kotlin\.Unit\]\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.PaddingValues,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.SimpleBottomSheetScaffoldSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Button/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.material[0-9]+\.ButtonElevation\?\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ButtonSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+//Button/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#androidx\.compose\.ui\.Modifier\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.ButtonColors\#androidx\.compose\.material[0-9]+\.ButtonElevation\?\#androidx\.compose\.foundation\.BorderStroke\?\#androidx\.compose\.foundation\.layout\.PaddingValues\#androidx\.compose\.foundation\.interaction\.MutableInteractionSource\#kotlin\.Function[0-9]+\[androidx\.compose\.foundation\.layout\.RowScope,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.ButtonWithIconSample\. b/[0-9]+
WARN: Missing @param tag for parameter `shape` of function androidx\.compose\.material[0-9]+/TextFieldDefaults/OutlinedBorderContainerBox/\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.foundation\.interaction\.InteractionSource\#androidx\.compose\.material[0-9]+\.TextFieldColors\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/
WARN: Missing @param tag for parameter `shape` of function androidx\.compose\.material[0-9]+/TextFieldDefaults/TextFieldDecorationBox/\#kotlin\.String\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\#kotlin\.Boolean\#kotlin\.Boolean\#androidx\.compose\.ui\.text\.input\.VisualTransformation\#androidx\.compose\.foundation\.interaction\.InteractionSource\#kotlin\.Boolean\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Unit\]\?\#androidx\.compose\.ui\.graphics\.Shape\#androidx\.compose\.material[0-9]+\.TextFieldColors\#androidx\.compose\.foundation\.layout\.PaddingValues\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `context` of function androidx\.tvprovider\.media\.tv/PreviewChannelHelper/PreviewChannelHelper/\#android\.content\.Context\#int\#int/PointingToDeclaration/
WARN: Missing @param tag for parameter `initial` of function androidx\.compose\.runtime//collectAsState/kotlinx\.coroutines\.flow\.Flow\[TypeParam\(bounds=\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\)\]\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#kotlin\.coroutines\.CoroutineContext/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.runtime//Composition/\#androidx\.compose\.runtime\.Applier\[\*\]\#androidx\.compose\.runtime\.CompositionContext/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.CustomTreeComposition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//collectAsState/kotlinx\.coroutines\.flow\.StateFlow\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.coroutines\.CoroutineContext/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.StateFlowSample\. b/[0-9]+
WARN: Missing @param tag for parameter `key` of function androidx\.compose\.runtime//traceEventStart/\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int\#kotlin\.String/PointingToDeclaration/
WARN: Missing @param tag for parameter `info` of function androidx\.compose\.runtime//traceEventStart/\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int\#kotlin\.String/PointingToDeclaration/
WARN: Missing @param tag for parameter `dataKey` of function androidx\.compose\.runtime/Composer/startMovableGroup/\#kotlin\.Int\#kotlin\.Any\?/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.runtime//CompositionLocalProvider/\#androidx\.compose\.runtime\.CompositionLocalContext\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.compositionLocalProvider\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//CompositionLocalProvider/\#kotlin\.Array\[androidx\.compose\.runtime\.ProvidedValue\[\*\]\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.compositionLocalProvider\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//ControlledComposition/\#androidx\.compose\.runtime\.Applier\[\*\]\#androidx\.compose\.runtime\.CompositionContext/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.CustomTreeComposition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//getValue/androidx\.compose\.runtime\.State\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Any\?\#kotlin\.reflect\.KProperty\[\*\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.DelegatedReadOnlyStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//DisposableEffect/\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.DisposableEffectScope,androidx\.compose\.runtime\.DisposableEffectResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.disposableEffectSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//setValue/androidx\.compose\.runtime\.MutableState\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Any\?\#kotlin\.reflect\.KProperty\[\*\]\#TypeParam\(bounds=\[kotlin\.Any\?\]\)/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.DelegatedStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//DisposableEffect/\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.DisposableEffectScope,androidx\.compose\.runtime\.DisposableEffectResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.disposableEffectSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//DisposableEffect/\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.DisposableEffectScope,androidx\.compose\.runtime\.DisposableEffectResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.disposableEffectSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//DisposableEffect/\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.DisposableEffectScope,androidx\.compose\.runtime\.DisposableEffectResult\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.disposableEffectSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//ReusableComposeNode/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.Updater\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.CustomTreeComposition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//ReusableComposeNode/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.Updater\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.SkippableUpdater\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],kotlin\.Unit\]\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.CustomTreeComposition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//ReusableComposeNode/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\]\)\]\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.Updater\[TypeParam\(bounds=\[kotlin\.Any\]\)\],kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.CustomTreeComposition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//derivedStateOf/\#androidx\.compose\.runtime\.SnapshotMutationPolicy\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.DerivedStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//derivedStateOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.DerivedStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//key/\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.LocallyUniqueKeys\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//key/\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.NotAlwaysUniqueKeys\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//key/\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MoreCorrectUniqueKeys\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//key/\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.TwoInputsKeySample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentOf/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentColumnRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentOf/\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentMultiColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentColumnRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentMultiColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentColumnRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentMultiColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentColumnRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentMultiColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentColumnRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentMultiColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentWithReceiverOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentColumnRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentWithReceiverOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentMultiColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentWithReceiverOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentColumnRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentWithReceiverOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentMultiColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentWithReceiverOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentColumnRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentWithReceiverOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentMultiColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentWithReceiverOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentColumnRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//movableContentWithReceiverOf/\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.MovableContentMultiColumnSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//mutableStateListOf/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.stateListSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//mutableStateMapOf/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.stateMapSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//mutableStateOf/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.runtime\.SnapshotMutationPolicy\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.SimpleStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//mutableStateOf/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.runtime\.SnapshotMutationPolicy\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.DestructuredStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//mutableStateOf/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.runtime\.SnapshotMutationPolicy\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.observeUserSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime//mutableStateOf/\#TypeParam\(bounds=\[kotlin\.Any\?\]\)\#androidx\.compose\.runtime\.SnapshotMutationPolicy\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.stateSample\. b/[0-9]+
WARN: Missing @param tag for parameter `content` of function androidx\.compose\.runtime\.saveable/SaveableStateHolder/SaveableStateProvider/\#kotlin\.Any\#kotlin\.Function[0-9]+\[kotlin\.Unit\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.runtime\.saveable//Saver/\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.saveable\.SaverScope,TypeParam\(bounds=\[kotlin\.Any\?\]\),TypeParam\(bounds=\[kotlin\.Any\]\)\?\]\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\]\),TypeParam\(bounds=\[kotlin\.Any\?\]\)\?\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.saveable\.samples\.CustomSaverSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime\.saveable//listSaver/\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.saveable\.SaverScope,TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.collections\.List\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\]\#kotlin\.Function[0-9]+\[kotlin\.collections\.List\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\],TypeParam\(bounds=\[kotlin\.Any\?\]\)\?\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.saveable\.samples\.ListSaverSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime\.saveable//mapSaver/\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.saveable\.SaverScope,TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.collections\.Map\[kotlin\.String,kotlin\.Any\?\]\]\#kotlin\.Function[0-9]+\[kotlin\.collections\.Map\[kotlin\.String,kotlin\.Any\?\],TypeParam\(bounds=\[kotlin\.Any\?\]\)\?\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.saveable\.samples\.MapSaverSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime\.saveable//rememberSaveable/\#kotlin\.Array\[kotlin\.Any\?\]\#androidx\.compose\.runtime\.saveable\.Saver\[TypeParam\(bounds=\[kotlin\.Any\?\]\),kotlin\.Any\]\#kotlin\.String\?\#kotlin\.Function[0-9]+\[androidx\.compose\.runtime\.MutableState\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.saveable\.samples\.RememberSaveableWithMutableStateAndCustomSaver\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime\.saveable//rememberSaveable/\#kotlin\.Array\[kotlin\.Any\?\]\#androidx\.compose\.runtime\.saveable\.Saver\[TypeParam\(bounds=\[kotlin\.Any\]\),kotlin\.Any\]\#kotlin\.String\?\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.saveable\.samples\.RememberSaveable\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime\.saveable//rememberSaveable/\#kotlin\.Array\[kotlin\.Any\?\]\#androidx\.compose\.runtime\.saveable\.Saver\[TypeParam\(bounds=\[kotlin\.Any\]\),kotlin\.Any\]\#kotlin\.String\?\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.saveable\.samples\.RememberSaveableCustomSaver\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime\.saveable//rememberSaveable/\#kotlin\.Array\[kotlin\.Any\?\]\#androidx\.compose\.runtime\.saveable\.Saver\[TypeParam\(bounds=\[kotlin\.Any\]\),kotlin\.Any\]\#kotlin\.String\?\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.saveable\.samples\.RememberSaveableWithMutableState\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime\.saveable//rememberSaveable/\#kotlin\.Array\[kotlin\.Any\?\]\#androidx\.compose\.runtime\.saveable\.Saver\[TypeParam\(bounds=\[kotlin\.Any\]\),kotlin\.Any\]\#kotlin\.String\?\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\]\)\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.saveable\.samples\.RememberSaveableWithMutableStateAndCustomSaver\. b/[0-9]+
WARN: Missing @param tag for parameter `block` of function androidx\.compose\.runtime\.snapshots/Snapshot\.Companion/observe/\#kotlin\.Function[0-9]+\[kotlin\.Any,kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[kotlin\.Any,kotlin\.Unit\]\?\#kotlin\.Function[0-9]+\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui//composed/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier\.Node/coroutineScope/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierNodeCoroutineScopeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier\.Node/onReset/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierNodeResetSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui//composed/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierWithArgumentsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui//composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui//composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierWithArgumentsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui//composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui//composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierWithArgumentsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/paddingFrom/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.layout\.AlignmentLine\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingFromSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui//composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/paddingFrom/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.layout\.AlignmentLine\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.unit\.TextUnit/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingFromSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui//composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Any\?\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierWithArgumentsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/paddingFromBaseline/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.unit\.Dp/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingFromBaselineSampleDp\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui//composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui//composed/androidx\.compose\.ui\.Modifier\#kotlin\.String\#kotlin\.Array\[kotlin\.Any\?\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.platform\.InspectorInfo,kotlin\.Unit\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.Modifier,androidx\.compose\.ui\.Modifier\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.InspectorInfoInComposedModifierWithArgumentsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/paddingFromBaseline/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.TextUnit\#androidx\.compose\.ui\.unit\.TextUnit/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.PaddingFromBaselineSampleTextUnit\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui//zIndex/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ZIndexModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/alpha/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.AlphaSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/animateContentSize/androidx\.compose\.ui\.Modifier\#androidx\.compose\.animation\.core\.FiniteAnimationSpec\[androidx\.compose\.ui\.unit\.IntSize\]\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.unit\.IntSize,androidx\.compose\.ui\.unit\.IntSize,kotlin\.Unit\]\?/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimateContent\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/aspectRatio/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.SimpleAspectRatio\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier/background/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Shape/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.DrawBackgroundColor\. b/[0-9]+
WARN: Missing @param tag for parameter `loadActionExecutor` of function androidx\.wear\.tiles\.renderer/TileRenderer/TileRenderer/\#android\.content\.Context\#androidx\.wear\.tiles\.LayoutElementBuilders\.Layout\#androidx\.wear\.tiles\.ResourceBuilders\.Resources\#java\.util\.concurrent\.Executor\#androidx\.wear\.tiles\.renderer\.TileRenderer\.LoadActionListener/PointingToDeclaration/
WARN: Missing @param tag for parameter `loadActionExecutor` of function androidx\.wear\.tiles\.renderer/TileRenderer/TileRenderer/\#android\.content\.Context\#androidx\.wear\.tiles\.LayoutElementBuilders\.Layout\#int\#androidx\.wear\.tiles\.ResourceBuilders\.Resources\#java\.util\.concurrent\.Executor\#androidx\.wear\.tiles\.renderer\.TileRenderer\.LoadActionListener/PointingToDeclaration/
WARN: Missing @param tag for parameter `listenerExecutor` of function androidx\.wear\.tiles\.timeline/TilesTimelineManager/TilesTimelineManager/\#android\.app\.AlarmManager\#androidx\.wear\.tiles\.timeline\.TilesTimelineManager\.Clock\#androidx\.wear\.tiles\.TimelineBuilders\.Timeline\#int\#java\.util\.concurrent\.Executor\#androidx\.wear\.tiles\.timeline\.TilesTimelineManager\.Listener/PointingToDeclaration/
@@ -769,13 +1719,77 @@
WARN: Missing @param tag for parameter `tags` of function androidx\.work\.testing//TestWorkerBuilder/\#android\.content\.Context\#java\.util\.concurrent\.Executor\#androidx\.work\.Data\#kotlin\.collections\.List\[kotlin\.String\]\#kotlin\.Int\#kotlin\.collections\.List\[android\.net\.Uri\]\#kotlin\.collections\.List\[kotlin\.String\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `tags` of function androidx\.work\.testing/TestWorkerBuilderKt/TestWorkerBuilder/\#android\.content\.Context\#java\.util\.concurrent\.Executor\#androidx\.work\.Data\#kotlin\.collections\.List\[kotlin\.String\]\#kotlin\.Int\#kotlin\.collections\.List\[android\.net\.Uri\]\#kotlin\.collections\.List\[kotlin\.String\]/PointingToDeclaration/
WARN: Missing @param tag for parameter `painter` of function androidx\.compose\.ui\.draw//paint/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.graphics\.painter\.Painter\#kotlin\.Boolean\#androidx\.compose\.ui\.Alignment\#androidx\.compose\.ui\.layout\.ContentScale\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.ColorFilter\?/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//rotate/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RotateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//scale/androidx\.compose\.ui\.Modifier\#kotlin\.Float\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ScaleNonUniformSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//scale/androidx\.compose\.ui\.Modifier\#kotlin\.Float/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ScaleUniformSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.draw//shadow/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ShadowSample\. b/[0-9]+
WARN: Missing @param tag for parameter `ambientColor` of function androidx\.compose\.ui\.draw//shadow/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/
WARN: Missing @param tag for parameter `spotColor` of function androidx\.compose\.ui\.draw//shadow/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.unit\.Dp\#androidx\.compose\.ui\.graphics\.Shape\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Color\#androidx\.compose\.ui\.graphics\.Color/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequesterModifier/focusRequester/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RequestFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequesterModifierNode/captureFocus/androidx\.compose\.ui\.focus\.FocusRequesterModifierNode\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CaptureFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus//captureFocus/androidx\.compose\.ui\.focus\.FocusRequesterModifierNode\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CaptureFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusState/isCaptured/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CaptureFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusOrder/down/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusDirection\.Companion/Down/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.MoveFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusProperties/down/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusOrder///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequester\.Companion/Cancel/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CancelFocusMoveSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequester\.Companion/createRefs/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CreateFocusRequesterRefsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequester/captureFocus/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CaptureFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequesterModifier///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RequestFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusOrder/end/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusManager/clearFocus/\#kotlin\.Boolean/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ClearFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusProperties/end/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusDirection\.Companion/Left/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.MoveFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusOrder/left/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusDirection\.Companion/Next/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.MoveFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusProperties/enter/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusEnterSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequesterModifierNode/freeFocus/androidx\.compose\.ui\.focus\.FocusRequesterModifierNode\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CaptureFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusState/isFocused/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.FocusableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusOrder/next/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequester/freeFocus/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CaptureFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusDirection\.Companion/Previous/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.MoveFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus//focusProperties/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.focus\.FocusProperties,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.FocusPropertiesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus//focusOrder/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.focus\.FocusRequester/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequesterModifierNode/requestFocus/androidx\.compose\.ui\.focus\.FocusRequesterModifierNode\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RequestFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequester/requestFocus/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RequestFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusDirection\.Companion/Right/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.MoveFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusOrder/previous/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus//focusRequester/androidx\.compose\.ui\.Modifier\#androidx\.compose\.ui\.focus\.FocusRequester/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RequestFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusManager/moveFocus/\#androidx\.compose\.ui\.focus\.FocusDirection/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.MoveFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusDirection\.Companion/Up/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.MoveFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus//focusTarget/androidx\.compose\.ui\.Modifier\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.FocusableSampleUsingLowerLevelFocusTarget\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus//focusOrder/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.focus\.FocusOrder,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusOrder/right/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusProperties/exit/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusExitSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus//freeFocus/androidx\.compose\.ui\.focus\.FocusRequesterModifierNode\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CaptureFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusOrder/start/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus//onFocusChanged/androidx\.compose\.ui\.Modifier\#kotlin\.Function[0-9]+\[androidx\.compose\.ui\.focus\.FocusState,kotlin\.Unit\]/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.FocusableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusOrder/up/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus//requestFocus/androidx\.compose\.ui\.focus\.FocusRequesterModifierNode\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RequestFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusProperties/left/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusProperties/next/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusProperties/previous/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusProperties/right/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusProperties/start/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusProperties/up/\#/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CustomFocusOrderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/horizontalGradient/\#kotlin\.Array\[kotlin\.Pair\[kotlin\.Float,androidx\.compose\.ui\.graphics\.Color\]\]\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.HorizontalGradientColorStopSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/ImageBitmap/readPixels/\#kotlin\.IntArray\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.ImageBitmapReadPixelsSample\. b/[0-9]+
WARN: Missing @param tag for parameter `radians` of function androidx\.compose\.ui\.graphics//rotateRad/androidx\.compose\.ui\.graphics\.Canvas\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/verticalGradient/\#kotlin\.Array\[kotlin\.Pair\[kotlin\.Float,androidx\.compose\.ui\.graphics\.Color\]\]\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.VerticalGradientColorStopSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/verticalGradient/\#kotlin\.Array\[kotlin\.Pair\[kotlin\.Float,androidx\.compose\.ui\.graphics\.Color\]\]\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.GradientBrushSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics//toPixelMap/androidx\.compose\.ui\.graphics\.ImageBitmap\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int\#kotlin\.Int\#kotlin\.IntArray\#kotlin\.Int\#kotlin\.Int/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.ImageBitmapToPixelMapSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/verticalGradient/\#kotlin\.collections\.List\[androidx\.compose\.ui\.graphics\.Color\]\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.VerticalGradientSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/verticalGradient/\#kotlin\.collections\.List\[androidx\.compose\.ui\.graphics\.Color\]\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.GradientBrushSample\. b/[0-9]+
WARN: Missing @param tag for parameter `renderEffect` of function androidx\.compose\.ui\.graphics/BlurEffect/BlurEffect/\#androidx\.compose\.ui\.graphics\.RenderEffect\?\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/
+WARN: Multiple sources exist for BlurEffect\. Artifact ID metadata will not be displayed
WARN: Missing @param tag for parameter `clipOp` of function androidx\.compose\.ui\.graphics/Canvas/clipRect/\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.ClipOp/PointingToDeclaration/
WARN: Missing @param tag for parameter `paint` of function androidx\.compose\.ui\.graphics/Canvas/drawArc/\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Float\#kotlin\.Boolean\#androidx\.compose\.ui\.graphics\.Paint/PointingToDeclaration/
WARN: Missing @param tag for parameter `operation` of function androidx\.compose\.ui\.graphics/AndroidPath/op/\#androidx\.compose\.ui\.graphics\.Path\#androidx\.compose\.ui\.graphics\.Path\#androidx\.compose\.ui\.graphics\.PathOperation/PointingToDeclaration/
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/horizontalGradient/\#kotlin\.collections\.List\[androidx\.compose\.ui\.graphics\.Color\]\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.HorizontalGradientSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/horizontalGradient/\#kotlin\.collections\.List\[androidx\.compose\.ui\.graphics\.Color\]\#kotlin\.Float\#kotlin\.Float\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.GradientBrushSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/linearGradient/\#kotlin\.Array\[kotlin\.Pair\[kotlin\.Float,androidx\.compose\.ui\.graphics\.Color\]\]\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.LinearGradientColorStopSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/Brush\.Companion/linearGradient/\#kotlin\.Array\[kotlin\.Pair\[kotlin\.Float,androidx\.compose\.ui\.graphics\.Color\]\]\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.geometry\.Offset\#androidx\.compose\.ui\.graphics\.TileMode/PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.GradientBrushSample\. b/[0-9]+
WARN\: Multiple sources exist for RestrictTo\. Artifact ID metadata will not be displayed
WARN\: Multiple sources exist for Scope\. Artifact ID metadata will not be displayed
WARN\: Multiple sources exist for SparseArrayCompat\. Artifact ID metadata will not be displayed
@@ -1017,7 +2031,10 @@
# > Configure project :internal-testutils-ktx
WARNING:.*The option setting 'android\.r8\.maxWorkers=[0-9]+' is experimental\.
# Building XCFrameworks (b/260140834) and iOS benchmark invocation
+Observed package id 'platforms;android-33-ext5' in inconsistent location.*
.*xcodebuild.*
+# > Task :core:core:compileDebugAndroidTestKotlin
+w: file://\$SUPPORT/core/core/src/androidTest/java/androidx/core/util/TypedValueCompatTest\.kt:[0-9]+:[0-9]+ 'scaledDensity: Float' is deprecated\. Deprecated in Java
# > Task :wear:tiles:tiles-material:compileDebugJavaWithJavac
\$SUPPORT/wear/tiles/tiles\-material/src/main/java/androidx/wear/tiles/material/CircularProgressIndicator\.java:[0-9]+: warning: \[deprecation\] Helper in androidx\.wear\.tiles\.material has been deprecated
import static androidx\.wear\.tiles\.material\.Helper\.checkNotNull;
@@ -1047,4 +2064,426 @@
w: file://\$SUPPORT/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/SelectionHandlePopupPositionTest\.kt:[0-9]+:[0-9]+ 'getter for windowLayoutParams: EspressoOptional<WindowManager\.LayoutParams!>!' is deprecated\. Deprecated in Java
w: file://\$SUPPORT/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextFieldVisualTransformationMagnifierTest\.kt:[0-9]+:[0-9]+ 'RequiresDevice' is deprecated\. Deprecated in Java
# > Task :compose:ui:ui:compileDebugAndroidTestKotlin
-w: file://\$SUPPORT/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/window/PopupTestUtils\.kt:[0-9]+:[0-9]+ 'getter for windowLayoutParams: EspressoOptional<WindowManager\.LayoutParams!>!' is deprecated\. Deprecated in Java
\ No newline at end of file
+w: file://\$SUPPORT/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/window/PopupTestUtils\.kt:[0-9]+:[0-9]+ 'getter for windowLayoutParams: EspressoOptional<WindowManager\.LayoutParams!>!' is deprecated\. Deprecated in Java
+# > Task :compose:ui:ui-inspection:dexInspectorRelease
+Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmFunctionSignature\$FakeJavaAnnotationConstructor\$asString\$[0-9]+'s kotlin\.Metadata: null
+Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$Method\$Instance's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.framework\.ViewExtensionsKt\$ancestors\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.Java[0-9]+RepeatableContainerLoader\$Cache's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmPropertySignature's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.InspectorNode\$WhenMappings's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KotlinReflectionInternalError's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KDeclarationContainerImpl\$findFunctionDescriptor\$allMembers\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.RuntimeTypeMapperKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.AnnotationConstructorCallerKt\$createAnnotationInstance\$hashCode\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KMutableProperty[0-9]+Impl\$_setter\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.compose\.AndroidComposeViewWrapper\$Companion's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KParameterImpl\$type\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KClasses\$isSubclassOf\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPackageImpl\$Data\$members\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.AnnotationConstructorCaller's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.UiToolingDataApi's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KCallableImpl\$_parameters\$[0-9]+\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.LambdaLocation's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KTypeImpl's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$getComposableNodes\$data\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.ModuleByClassLoaderKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmPropertySignature\$JavaField's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$supertypes\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$expand\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KProperty[0-9]+Impl\$Getter's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.AnnotationConstructorCaller\$CallMode's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KFunctionImpl\$caller\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldSetter\$BoundInstance's kotlin\.Metadata: null
+Info:
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$Method\$Instance's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.ParameterInformation's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.IllegalPropertyDelegateAccessException's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.InlineClassAwareCaller's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KClasses\$defaultType\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.PackageHashesKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KCallableImpl\$_returnType\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmFunctionSignature\$FakeJavaAnnotationConstructor\$asString\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.InlineClassAwareCaller\$BoxUnboxData's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$loadConstantsFromStaticFinal\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KProperty[0-9]+Impl's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$handleGetAllParametersCommand\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.ContextCache's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.RuntimeTypeMapperKt\$signature\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterKind's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$BoundConstructor's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$handleUnknownCommand\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.InlineClassAwareCallerKt's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$ParameterCreator\$findBestResourceFont\$\$inlined\$filterIsInstance\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.InlineClassConverter\$loadTypeMapper\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImpl\$Getter\$descriptor\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KClasses's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KMutableProperty[0-9]+Impl\$Setter's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.CachesKt\$CACHE_FOR_BASE_CLASSIFIERS\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KCallableImpl\$_returnType\$[0-9]+\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KTypeParameterImpl's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KTypeImpl\$arguments\$[0-9]+\$parameterizedTypeArguments\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KMutableProperty[0-9]+Impl's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterType's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$Method's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$Method\$JvmStaticInObject's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldGetter\$BoundInstance's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.compose\.ComposeExtensionsKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.ComputableClassValue's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$loadConstantsFromObjectInstance\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.RecompositionHandler\$MethodKey's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImpl\$Setter\$descriptor\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KCallableImpl\$_annotations\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree\$belongsToView\$[0-9]+\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KTypeImpl\$arguments\$[0-9]+\$[0-9]+\$type\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$typeParameters\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldSetter\$BoundJvmStaticInObject's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.KTypesJvm's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.RecompositionHandler\$Data's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.CachesKt\$K_PACKAGE_CACHE\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$supertypes\$[0-9]+\$[0-9]+\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImpl's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KDeclarationContainerImpl\$MemberBelonginess's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmPropertySignature\$JavaMethodProperty's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KFunctionImpl\$descriptor\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldSetter\$Static's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KCallableImpl\$_parameters\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldGetter\$BoundJvmStaticInObject's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$declaredNonStaticMembers\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$inheritedStaticMembers\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.NodeGroup's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KCallables\$callSuspendBy\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$ParameterCreator\$lookup\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.proto\.ViewExtensionsKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImplKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmPropertySignature\$KotlinProperty's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldGetter\$JvmStaticInObject's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldGetter's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$AccessorForHiddenConstructor's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$inheritedNonStaticMembers\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KProperty[0-9]+Impl\$delegateSource\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.SlotTreeKt\$extractParameterInfo\$\$inlined\$sortedBy\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$data\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$handleGetComposablesCommand\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.WeakClassLoaderBox's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$constructors\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.AnnotationConstructorCallerKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KCallableImpl\$_parameters\$[0-9]+\$invoke\$\$inlined\$sortBy\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldSetter\$JvmStaticInObject's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.ReflectionObjectRenderer\$renderLambda\$[0-9]+\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KParameterImpl\$annotations\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.KClassesJvm's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImpl\$Accessor's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmFunctionSignature\$JavaMethod's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree\$belongsToView\$[0-9]+\$invoke\$\$inlined\$filterIsInstance\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.ReflectLambdaKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImpl\$Getter's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ScopedReflectionFactory's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.SlotTreeKt's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$getComposableFromAnchor\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.ExperimentalReflectionOnLambdas's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree\$parseLayoutInfo\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.RuntimeTypeMapper's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$WhenMappings's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.Parameter's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.util\.AnchorMap's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPackageImpl\$Data\$multifileFacade\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.AnnotationConstructorCallerKt\$createAnnotationInstance\$toString\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.AnnotationConstructorCallerKt\$createAnnotationInstance\$toString\$[0-9]+\$[0-9]+\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree\$belongsToView\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.RecompositionHandlerKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KParameterImpl's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KDeclarationContainerImpl's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.ConcurrentHashMapCache's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.CacheByClassKt's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.InspectorNode's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.RecompositionHandler's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$annotations\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.ReflectLambdaKt\$reflect\$descriptor\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$Method\$BoundInstance's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KDeclarationContainerImpl\$Data\$moduleData\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$handleGetParameterDetailsCommand\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.ReflectionObjectRenderer's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.proto\.ComposeExtensionsKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KTypeImpl\$arguments\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.compose\.AndroidComposeViewWrapperKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.SourceContext's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KDeclarationContainerImpl\$findPropertyDescriptor\$mostVisibleProperties\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree\$SubCompositionRoots's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$allStaticMembers\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$handleGetParametersCommand\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.EmptyContainerForLocal's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KClassifiers's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.CompositionCallStack's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImpl\$Companion's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$loadConstantsFrom\$[0-9]+\$topClass\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.InternalUnderlyingValOfInlineClass\$Unbound's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KTypeParameterImpl\$upperBounds\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KAnnotatedElements's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.ParseError's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$CacheTree's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$allMembers\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KTypeImpl\$arguments\$[0-9]+\$WhenMappings's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.Group's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KClasses\$allSupertypes\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassifierImpl's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.ReflectionObjectRenderer\$renderFunction\$[0-9]+\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.CachesKt\$K_CLASS_CACHE\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.compose\.AndroidComposeViewWrapper's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$Method\$Static's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.FunctionWithAllInvokes's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$Method\$BoundJvmStaticInObject's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldGetter\$Static's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.TypeOfImplKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.ReflectionObjectRenderer\$WhenMappings's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ReflectionScope's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPackageImpl\$Data\$metadata\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.framework\.ViewExtensionsKt\$flatten\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$ParameterCreator\$unwrap\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.FunctionWithAllInvokes\$DefaultImpls's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPackageImpl\$Data\$kotlinClass\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$declaredStaticMembers\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$allNonStaticMembers\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KProperty[0-9]+Impl\$delegateValue\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.InternalUnderlyingValOfInlineClass\$Bound's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ReflectionScope\$Companion's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KProperty[0-9]+Impl\$_getter\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.CacheByClass's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.NodeParameterReference's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.CachesKt\$CACHE_FOR_NULLABLE_BASE_CLASSIFIERS\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.proto\.StringTable's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPackageImpl\$getLocalProperty\$[0-9]+\$[0-9]+\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KClassifiers\$WhenMappings's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree\$stitchTreesByLayoutInfo\$[0-9]+\$parentLayout\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspectorFactory's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.Caller's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.proto\.StringTable\$put\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.InlineClassConverter's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree\$convert\$group\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.LambdaLocation\$Companion's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldSetter's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KFunctionImpl\$defaultCaller\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KTypes's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.ReflectJvmMapping's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$loadConstantsFrom\$related\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$getLocalProperty\$[0-9]+\$[0-9]+\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPackageImpl\$data\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.InspectorNodeKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.Java[0-9]+RepeatableContainerLoader's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KCallables\$callSuspend\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.SourceInformationContext's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$Method\$BoundStatic's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KCallables's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KTypeParameterImpl\$WhenMappings's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$ParameterCreator's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$simpleName\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.InlineClassConverter\$notInlineType\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.InternalUnderlyingValOfInlineClass's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$handleUpdateSettingsCommand\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.ThrowingCaller's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmPropertySignature\$MappedKotlinProperty's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPackageImpl's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$Constructor's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KDeclarationContainerImpl\$getMembers\$visitor\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.util\.IntArrayKt's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTreeKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.KCallablesJvm's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ReflectionScopeKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.JoinedKey's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.CachesKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$descriptor\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree\$stitchTreesByLayoutInfo\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmFunctionSignature's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.SourceLocation's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPackageImpl\$Data\$scope\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.ReflectJvmMapping\$WhenMappings's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$objectInstance\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.CachesKt\$CACHE_FOR_GENERIC_CLASSIFIERS\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$getAndroidComposeViews\$roots\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspector\$CacheData's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.IllegalCallableAccessException's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$declaredMembers\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmFunctionSignature\$JavaConstructor's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.Caller\$DefaultImpls's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.NoSuchPropertyException's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KDeclarationContainerImpl\$Data's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KFunctionImpl's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.MutableInspectorNode's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldSetter\$Instance's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactoryKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$FieldGetter\$Instance's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$sealedSubclasses\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmFunctionSignature\$KotlinConstructor's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.CreateKCallableVisitor's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.AnnotationConstructorCaller\$Origin's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$Companion's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree\$findDeepParentTree\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.UtilKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImpl\$Getter\$caller\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImpl\$Setter\$caller\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImpl\$Setter's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmFunctionSignature\$FakeJavaAnnotationConstructor's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.util\.AnchorMapKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.EmptyGroup's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.BoundCaller's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$WhenMappings's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPackageImpl\$Data's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.ComposeLayoutInspectorKt's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.QuadBounds's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmFunctionSignature\$JavaConstructor\$asString\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.full\.KProperties's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KTypeImpl\$classifier\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree\$StitchInfo's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.ClassValueCache's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmFunctionSignature\$KotlinFunction's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$create\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.SourceLocationInfo's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.androidx\.compose\.ui\.tooling\.data\.CallGroup's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.calls\.CallerImpl\$AccessorForHiddenBoundConstructor's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KCallableImpl\$_typeParameters\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.util\.ThreadUtils's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$nestedClasses\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$supertypes\$[0-9]+\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.NodeParameter's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImpl\$_descriptor\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KDeclarationContainerImpl\$findPropertyDescriptor\$allMembers\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.ParameterFactory\$ModifierCollector's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree\$parseLayoutInfo\$\$inlined\$filterIsInstance\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KPropertyImpl\$_javaField\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.proto\.ComposeExtensionsKt\$WhenMappings's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.RawParameter's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.JvmFunctionSignature\$FakeJavaAnnotationConstructor\$special\$\$inlined\$sortedBy\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KTypeParameterOwnerImpl's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.inspector\.LayoutInspectorTree's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.framework\.ViewExtensionsKt's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.UtilKt\$WhenMappings's kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KDeclarationContainerImpl\$Companion's kotlin\.Metadata: null
+Info: Unexpected error while reading androidx\.compose\.ui\.inspection\.compose\.ComposeExtensionsKt\$flatten\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KClassImpl\$Data\$qualifiedName\$[0-9]+'s kotlin\.Metadata: null
+Info: Unexpected error while reading deps\.ui\.inspection\.kotlin\.reflect\.jvm\.internal\.KCallableImpl's kotlin\.Metadata: null
+# b/271306193 remove after aosp/2589888 :emoji:emoji:spdxSbomForRelease
+spdx sboms require a version but project: noto\-emoji\-compat\-flatbuffers has no specified version
+# > Task :docs-public:docs
+WARNING: no common source set for DPackage androidx\.compose\.ui\.test\.junit[0-9]+////PointingToDeclaration/! Falling back to jvmMain sourceSet! This is only defensible if every sourceSet depends onjvmMain! This is a bug in dackka: b/[0-9]+
+WARNING: no common source set for DPackage androidx\.compose\.ui\.tooling////PointingToDeclaration/! Falling back to jvmMain sourceSet! This is only defensible if every sourceSet depends onjvmMain! This is a bug in dackka: b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/AbstractApplier///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.CustomTreeComposition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/AlignmentLine///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.AlignmentLineSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/Animatable///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.AnimatableAnimateToGenericsType\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/AnimatedVisibilityScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AVScopeAnimateEnterExit\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/AnimationResult///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.AnimatableAnimationResultSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/AnnotatedString\.Builder///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderAppendableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/Applier///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.CustomTreeComposition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/BaselineShift///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.BaselineShiftSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/BaselineShift///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.BaselineShiftAnnotatedStringSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.relocation/BringIntoViewRequester///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.relocation/BringIntoViewRequester///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringPartOfComposableIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.relocation/BringIntoViewResponder///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.relocation/BringIntoViewResponder///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.BringPartOfComposableIntoViewSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/CompositionLocal///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.createCompositionLocal\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/CompositionLocal///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.compositionLocalProvider\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/CompositionLocal///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.someScreenSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/CompositionLocal///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.consumeCompositionLocal\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/CompositionLocalConsumerModifierNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CompositionLocalConsumingModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/ContentTransform///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatedContentTransitionSpecSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/DelegatingNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.DelegatedNodeSampleExplicit\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/DelegatingNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.DelegatedNodeSampleImplicit\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/DelegatingNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LazyDelegationExample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/DelegatingNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ConditionalDelegationExample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/DelegatingNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.DelegateInAttachSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.unit/Density///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.unit\.samples\.WithDensitySample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.unit/Dp///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.unit\.samples\.DpSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.unit/Dp///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.unit\.samples\.ToPxSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/DrawModifierNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.DrawModifierNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics\.drawscope/DrawScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.DrawScopeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/EnterExitState///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatedVisibilityWithBooleanVisibleParamNoReceiver\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/EnterTransition///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.SlideTransition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/ExitTransition///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.SlideTransition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusDirection///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.MoveFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequester///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.RequestFocusSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusRequester\.Companion\.FocusRequesterFactory///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.CreateFocusRequesterRefsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.focus/FocusState///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.FocusableSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.font/FontListFontFamily///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.FontFamilySansSerifSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.font/FontListFontFamily///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.CustomFontFamilySample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.font/FontSynthesis///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.FontFamilySynthesisSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/GlobalPositionAwareModifierNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnGloballyPositioned\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/GlobalPositionAwareModifierNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.GlobalPositionAwareModifierNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material\.icons/Icons///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.icons\.samples\.AppIcons\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material\.icons/Icons///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material\.icons\.samples\.DrawIcon\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/Immutable///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.simpleImmutableClass\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/InfiniteRepeatableSpec///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.InfiniteProgressIndicator\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/InfiniteTransition///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.InfiniteTransitionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.text/InlineTextContent///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.InlineTextContentSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.interaction/InteractionSource///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SimpleInteractionSourceSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.interaction/InteractionSource///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.InteractionSourceFlowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/Key///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventIsAltPressedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/KeyEvent///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.input\.key/KeyEventType///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.KeyEventTypeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/KeyframesSpec///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.FloatKeyframesBuilder\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/KeyframesSpec///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.KeyframesBuilderWithEasing\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/KeyframesSpec\.KeyframesSpecConfig///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.KeyframesBuilderForPosition\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/LayoutAwareModifierNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnSizeChangedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/LayoutAwareModifierNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnPlaced\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/LayoutAwareModifierNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutAwareModifierNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/LayoutModifier///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/LayoutModifierNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LayoutModifierNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/LineBreak///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.LineBreakSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/LineBreak///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AndroidLineBreakSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/LookaheadScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.LookaheadLayoutCoordinatesSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/MainTestClock///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.testSlideOut\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/MainTestClock///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.testControlClock\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierUsageSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierFactorySample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierParameterSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.SubcomponentModifierSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier\.Companion///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierUsageSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui/Modifier\.Companion///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierParameterSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.modifier/ModifierLocalModifierNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.JustReadingOrProvidingModifierLocalNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/ModifierNodeElement///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.ModifierNodeElementSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/ModifierNodeElement///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.SemanticsModifierNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/MouseInjectionScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.mouseInputClick\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/MouseInjectionScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.mouseInputScrollWhileDown\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/MultiModalInjectionScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.multiModalInputClickDragDrop\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/MutableTransitionState///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.InitialStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.layout/MutableWindowInsets///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.layout\.samples\.withConsumedInsetsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation/MutatorMutex///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.mutatorMutexStateObject\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/OnGloballyPositionedModifier///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnGloballyPositioned\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/OnPlacedModifier///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnPlaced\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/OnRemeasuredModifier///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.OnSizeChangedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation/OverscrollEffect///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.OverscrollSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.pager/PageSize///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.CustomPageSizeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/ParagraphStyle///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.ParagraphStyleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/ParagraphStyle///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.ParagraphStyleAnnotatedStringsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/PixelMap///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.ImageBitmapReadPixelsSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.node/PointerInputModifierNode///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.PointerInputModifierNodeSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.font/ResourceFont///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.CustomFontFamilySample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/RotaryInjectionScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.rotaryInputScroll\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime\.saveable/SaveableStateHolder///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.saveable\.samples\.SimpleNavigationWithSaveableStateSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime\.saveable/Saver///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.saveable\.samples\.CustomSaverSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation/ScrollState///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.ControlledScrollableRowSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/SemanticsNodeInteraction///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.clickAndVerifyCheckbox\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/SemanticsNodeInteraction///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.useUnmergedTree\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/SemanticsNodeInteractionCollection///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.verifyTwoClickableNodes\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation/SizeTransform///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.samples\.AnimatedContentTransitionSpecSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures\.snapping/SnapFlingBehavior///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SnapFlingBehaviorSimpleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.foundation\.gestures\.snapping/SnapFlingBehavior///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.foundation\.samples\.SnapFlingBehaviorCustomizedSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.runtime/SnapshotMutationPolicy///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.runtime\.samples\.counterSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/SpanStyle///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.SpanStyleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/SpanStyle///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.AnnotatedStringBuilderSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.graphics/StampedPathEffectStyle///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.graphics\.samples\.StampedPathEffectSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/StartOffset///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.InfiniteProgressIndicator\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.layout/SubcomposeIntermediateMeasureScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.samples\.SubcomposeLayoutWithIntermediateMeasurePolicySample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text\.style/TextMotion///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextMotionSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.text/TextStyle///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.text\.samples\.TextStyleSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.material[0-9]+/TimePickerState///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.material[0-9]+\.samples\.TimePickerSample\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/TouchInjectionScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.touchInputClick\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/TouchInjectionScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.touchInputSwipeUp\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.ui\.test/TouchInjectionScope///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.ui\.test\.samples\.touchInputLShapedGesture\. b/[0-9]+
+WARNING: no common sourceSet for androidx\.compose\.animation\.core/Transition///PointingToDeclaration/, falling back to \.single\(\) when resolving @sample androidx\.compose\.animation\.core\.samples\.GestureAnimationSample\. b/[0-9]+
\ No newline at end of file
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index b2b8c41..8ca6f01 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -29,7 +29,7 @@
docs("androidx.arch.core:core-testing:2.2.0")
docs("androidx.asynclayoutinflater:asynclayoutinflater:1.1.0-alpha01")
docs("androidx.asynclayoutinflater:asynclayoutinflater-appcompat:1.1.0-alpha01")
- docs("androidx.autofill:autofill:1.2.0-beta01")
+ docs("androidx.autofill:autofill:1.3.0-alpha01")
docs("androidx.benchmark:benchmark-common:1.2.0-alpha14")
docs("androidx.benchmark:benchmark-junit4:1.2.0-alpha14")
docs("androidx.benchmark:benchmark-macro:1.2.0-alpha14")
@@ -38,16 +38,16 @@
docs("androidx.biometric:biometric-ktx:1.2.0-alpha05")
samples("androidx.biometric:biometric-ktx-samples:1.2.0-alpha05")
docs("androidx.browser:browser:1.6.0-alpha01")
- docs("androidx.camera:camera-camera2:1.3.0-alpha06")
- docs("androidx.camera:camera-core:1.3.0-alpha06")
- docs("androidx.camera:camera-extensions:1.3.0-alpha06")
+ docs("androidx.camera:camera-camera2:1.3.0-alpha07")
+ docs("androidx.camera:camera-core:1.3.0-alpha07")
+ docs("androidx.camera:camera-extensions:1.3.0-alpha07")
stubs(fileTree(dir: "../camera/camera-extensions-stub", include: ["camera-extensions-stub.jar"]))
- docs("androidx.camera:camera-lifecycle:1.3.0-alpha06")
- docs("androidx.camera:camera-mlkit-vision:1.3.0-alpha06")
+ docs("androidx.camera:camera-lifecycle:1.3.0-alpha07")
+ docs("androidx.camera:camera-mlkit-vision:1.3.0-alpha07")
docs("androidx.camera:camera-previewview:1.1.0-beta02")
- docs("androidx.camera:camera-video:1.3.0-alpha06")
- docs("androidx.camera:camera-view:1.3.0-alpha06")
- docs("androidx.camera:camera-viewfinder:1.3.0-alpha06")
+ docs("androidx.camera:camera-video:1.3.0-alpha07")
+ docs("androidx.camera:camera-view:1.3.0-alpha07")
+ docs("androidx.camera:camera-viewfinder:1.3.0-alpha07")
docs("androidx.car.app:app:1.4.0-alpha01")
docs("androidx.car.app:app-automotive:1.4.0-alpha01")
docs("androidx.car.app:app-projected:1.4.0-alpha01")
@@ -55,60 +55,60 @@
docs("androidx.cardview:cardview:1.0.0")
kmpDocs("androidx.collection:collection:1.3.0-alpha03")
docs("androidx.collection:collection-ktx:1.3.0-alpha03")
- docs("androidx.compose.animation:animation:1.5.0-alpha04")
- docs("androidx.compose.animation:animation-core:1.5.0-alpha04")
- docs("androidx.compose.animation:animation-graphics:1.5.0-alpha04")
- samples("androidx.compose.animation:animation-samples:1.5.0-alpha04")
- samples("androidx.compose.animation:animation-core-samples:1.5.0-alpha04")
- samples("androidx.compose.animation:animation-graphics-samples:1.5.0-alpha04")
- docs("androidx.compose.foundation:foundation:1.5.0-alpha04")
- docs("androidx.compose.foundation:foundation-layout:1.5.0-alpha04")
- samples("androidx.compose.foundation:foundation-layout-samples:1.5.0-alpha04")
- samples("androidx.compose.foundation:foundation-samples:1.5.0-alpha04")
- docs("androidx.compose.material3:material3:1.2.0-alpha01")
- samples("androidx.compose.material3:material3-samples:1.2.0-alpha01")
- docs("androidx.compose.material3:material3-window-size-class:1.2.0-alpha01")
+ kmpDocs("androidx.compose.animation:animation:1.5.0-beta01")
+ kmpDocs("androidx.compose.animation:animation-core:1.5.0-beta01")
+ kmpDocs("androidx.compose.animation:animation-graphics:1.5.0-beta01")
+ samples("androidx.compose.animation:animation-samples:1.5.0-beta01")
+ samples("androidx.compose.animation:animation-core-samples:1.5.0-beta01")
+ samples("androidx.compose.animation:animation-graphics-samples:1.5.0-beta01")
+ kmpDocs("androidx.compose.foundation:foundation:1.5.0-beta01")
+ kmpDocs("androidx.compose.foundation:foundation-layout:1.5.0-beta01")
+ samples("androidx.compose.foundation:foundation-layout-samples:1.5.0-beta01")
+ samples("androidx.compose.foundation:foundation-samples:1.5.0-beta01")
+ kmpDocs("androidx.compose.material3:material3:1.2.0-alpha02")
+ samples("androidx.compose.material3:material3-samples:1.2.0-alpha02")
+ kmpDocs("androidx.compose.material3:material3-window-size-class:1.2.0-alpha02")
samples("androidx.compose.material3:material3-window-size-class-samples:1.2.0-alpha01")
- docs("androidx.compose.material:material:1.5.0-alpha04")
- docs("androidx.compose.material:material-icons-core:1.5.0-alpha04")
- samples("androidx.compose.material:material-icons-core-samples:1.5.0-alpha04")
- docs("androidx.compose.material:material-ripple:1.5.0-alpha04")
- samples("androidx.compose.material:material-samples:1.5.0-alpha04")
- docs("androidx.compose.runtime:runtime:1.5.0-alpha04")
- docs("androidx.compose.runtime:runtime-livedata:1.5.0-alpha04")
- samples("androidx.compose.runtime:runtime-livedata-samples:1.5.0-alpha04")
- docs("androidx.compose.runtime:runtime-rxjava2:1.5.0-alpha04")
- samples("androidx.compose.runtime:runtime-rxjava2-samples:1.5.0-alpha04")
- docs("androidx.compose.runtime:runtime-rxjava3:1.5.0-alpha04")
- samples("androidx.compose.runtime:runtime-rxjava3-samples:1.5.0-alpha04")
- docs("androidx.compose.runtime:runtime-saveable:1.5.0-alpha04")
- samples("androidx.compose.runtime:runtime-saveable-samples:1.5.0-alpha04")
- samples("androidx.compose.runtime:runtime-samples:1.5.0-alpha04")
+ kmpDocs("androidx.compose.material:material:1.5.0-beta01")
+ kmpDocs("androidx.compose.material:material-icons-core:1.5.0-beta01")
+ samples("androidx.compose.material:material-icons-core-samples:1.5.0-beta01")
+ kmpDocs("androidx.compose.material:material-ripple:1.5.0-beta01")
+ samples("androidx.compose.material:material-samples:1.5.0-beta01")
+ kmpDocs("androidx.compose.runtime:runtime:1.5.0-beta01")
+ docs("androidx.compose.runtime:runtime-livedata:1.5.0-beta01")
+ samples("androidx.compose.runtime:runtime-livedata-samples:1.5.0-beta01")
+ docs("androidx.compose.runtime:runtime-rxjava2:1.5.0-beta01")
+ samples("androidx.compose.runtime:runtime-rxjava2-samples:1.5.0-beta01")
+ docs("androidx.compose.runtime:runtime-rxjava3:1.5.0-beta01")
+ samples("androidx.compose.runtime:runtime-rxjava3-samples:1.5.0-beta01")
+ kmpDocs("androidx.compose.runtime:runtime-saveable:1.5.0-beta01")
+ samples("androidx.compose.runtime:runtime-saveable-samples:1.5.0-beta01")
+ samples("androidx.compose.runtime:runtime-samples:1.5.0-beta01")
docs("androidx.compose.runtime:runtime-tracing:1.0.0-alpha03")
- docs("androidx.compose.ui:ui:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-geometry:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-graphics:1.5.0-alpha04")
- samples("androidx.compose.ui:ui-graphics-samples:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-test:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-test-junit4:1.5.0-alpha04")
- samples("androidx.compose.ui:ui-test-samples:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-text:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-text-google-fonts:1.5.0-alpha04")
- samples("androidx.compose.ui:ui-text-samples:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-tooling:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-tooling-data:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-tooling-preview:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-unit:1.5.0-alpha04")
- samples("androidx.compose.ui:ui-unit-samples:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-util:1.5.0-alpha04")
- docs("androidx.compose.ui:ui-viewbinding:1.5.0-alpha04")
- samples("androidx.compose.ui:ui-viewbinding-samples:1.5.0-alpha04")
- samples("androidx.compose.ui:ui-samples:1.5.0-alpha04")
+ kmpDocs("androidx.compose.ui:ui:1.5.0-beta01")
+ kmpDocs("androidx.compose.ui:ui-geometry:1.5.0-beta01")
+ kmpDocs("androidx.compose.ui:ui-graphics:1.5.0-beta01")
+ samples("androidx.compose.ui:ui-graphics-samples:1.5.0-beta01")
+ kmpDocs("androidx.compose.ui:ui-test:1.5.0-beta01")
+ kmpDocs("androidx.compose.ui:ui-test-junit4:1.5.0-beta01")
+ samples("androidx.compose.ui:ui-test-samples:1.5.0-beta01")
+ kmpDocs("androidx.compose.ui:ui-text:1.5.0-beta01")
+ docs("androidx.compose.ui:ui-text-google-fonts:1.5.0-beta01")
+ samples("androidx.compose.ui:ui-text-samples:1.5.0-beta01")
+ kmpDocs("androidx.compose.ui:ui-tooling:1.5.0-beta01")
+ kmpDocs("androidx.compose.ui:ui-tooling-data:1.5.0-beta01")
+ kmpDocs("androidx.compose.ui:ui-tooling-preview:1.5.0-beta01")
+ kmpDocs("androidx.compose.ui:ui-unit:1.5.0-beta01")
+ samples("androidx.compose.ui:ui-unit-samples:1.5.0-beta01")
+ kmpDocs("androidx.compose.ui:ui-util:1.5.0-beta01")
+ docs("androidx.compose.ui:ui-viewbinding:1.5.0-beta01")
+ samples("androidx.compose.ui:ui-viewbinding-samples:1.5.0-beta01")
+ samples("androidx.compose.ui:ui-samples:1.5.0-beta01")
docs("androidx.concurrent:concurrent-futures:1.2.0-alpha01")
docs("androidx.concurrent:concurrent-futures-ktx:1.2.0-alpha01")
- docs("androidx.constraintlayout:constraintlayout:2.2.0-alpha09")
- docs("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha09")
- docs("androidx.constraintlayout:constraintlayout-core:1.1.0-alpha09")
+ docs("androidx.constraintlayout:constraintlayout:2.2.0-alpha10")
+ kmpDocs("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha10")
+ docs("androidx.constraintlayout:constraintlayout-core:1.1.0-alpha10")
docs("androidx.contentpager:contentpager:1.0.0")
docs("androidx.coordinatorlayout:coordinatorlayout:1.2.0")
docs("androidx.core.uwb:uwb:1.0.0-alpha05")
@@ -144,11 +144,11 @@
docs("androidx.drawerlayout:drawerlayout:1.2.0")
docs("androidx.dynamicanimation:dynamicanimation:1.1.0-alpha02")
docs("androidx.dynamicanimation:dynamicanimation-ktx:1.0.0-alpha03")
- docs("androidx.emoji2:emoji2:1.4.0-beta03")
- docs("androidx.emoji2:emoji2-bundled:1.4.0-beta03")
- docs("androidx.emoji2:emoji2-emojipicker:1.4.0-beta03")
- docs("androidx.emoji2:emoji2-views:1.4.0-beta03")
- docs("androidx.emoji2:emoji2-views-helper:1.4.0-beta03")
+ docs("androidx.emoji2:emoji2:1.4.0-beta04")
+ docs("androidx.emoji2:emoji2-bundled:1.4.0-beta04")
+ docs("androidx.emoji2:emoji2-emojipicker:1.4.0-beta04")
+ docs("androidx.emoji2:emoji2-views:1.4.0-beta04")
+ docs("androidx.emoji2:emoji2-views-helper:1.4.0-beta04")
docs("androidx.emoji:emoji:1.2.0-alpha03")
docs("androidx.emoji:emoji-appcompat:1.2.0-alpha03")
docs("androidx.emoji:emoji-bundled:1.2.0-alpha03")
@@ -167,7 +167,7 @@
docs("androidx.glance:glance-wear-tiles:1.0.0-alpha06")
docs("androidx.glance:glance-wear-tiles-preview:1.0.0-alpha06")
docs("androidx.graphics:graphics-core:1.0.0-alpha03")
- docs("androidx.gridlayout:gridlayout:1.1.0-alpha01")
+ docs("androidx.gridlayout:gridlayout:1.1.0-beta01")
docs("androidx.health.connect:connect-client:1.0.0-alpha11")
samples("androidx.health.connect:connect-client-samples:1.0.0-alpha11")
docs("androidx.health:health-services-client:1.0.0-beta03")
@@ -214,58 +214,59 @@
docs("androidx.media2:media2-session:1.2.1")
docs("androidx.media2:media2-widget:1.2.1")
docs("androidx.media:media:1.6.0")
- docs("androidx.media3:media3-cast:1.1.0-alpha01")
- docs("androidx.media3:media3-common:1.1.0-alpha01")
- docs("androidx.media3:media3-database:1.1.0-alpha01")
- docs("androidx.media3:media3-datasource:1.1.0-alpha01")
- docs("androidx.media3:media3-datasource-cronet:1.1.0-alpha01")
- docs("androidx.media3:media3-datasource-okhttp:1.1.0-alpha01")
- docs("androidx.media3:media3-datasource-rtmp:1.1.0-alpha01")
- docs("androidx.media3:media3-decoder:1.1.0-alpha01")
- docs("androidx.media3:media3-effect:1.1.0-alpha01")
- docs("androidx.media3:media3-exoplayer:1.1.0-alpha01")
- docs("androidx.media3:media3-exoplayer-dash:1.1.0-alpha01")
- docs("androidx.media3:media3-exoplayer-hls:1.1.0-alpha01")
- docs("androidx.media3:media3-exoplayer-ima:1.1.0-alpha01")
- docs("androidx.media3:media3-exoplayer-rtsp:1.1.0-alpha01")
- docs("androidx.media3:media3-exoplayer-smoothstreaming:1.1.0-alpha01")
- docs("androidx.media3:media3-exoplayer-workmanager:1.1.0-alpha01")
- docs("androidx.media3:media3-extractor:1.1.0-alpha01")
- docs("androidx.media3:media3-muxer:1.1.0-alpha01")
- docs("androidx.media3:media3-session:1.1.0-alpha01")
- docs("androidx.media3:media3-test-utils:1.1.0-alpha01")
- docs("androidx.media3:media3-test-utils-robolectric:1.1.0-alpha01")
- docs("androidx.media3:media3-transformer:1.1.0-alpha01")
- docs("androidx.media3:media3-ui:1.1.0-alpha01")
- docs("androidx.media3:media3-ui-leanback:1.1.0-alpha01")
+ docs("androidx.media3:media3-cast:1.1.0-beta01")
+ docs("androidx.media3:media3-common:1.1.0-beta01")
+ docs("androidx.media3:media3-container:1.1.0-beta01")
+ docs("androidx.media3:media3-database:1.1.0-beta01")
+ docs("androidx.media3:media3-datasource:1.1.0-beta01")
+ docs("androidx.media3:media3-datasource-cronet:1.1.0-beta01")
+ docs("androidx.media3:media3-datasource-okhttp:1.1.0-beta01")
+ docs("androidx.media3:media3-datasource-rtmp:1.1.0-beta01")
+ docs("androidx.media3:media3-decoder:1.1.0-beta01")
+ docs("androidx.media3:media3-effect:1.1.0-beta01")
+ docs("androidx.media3:media3-exoplayer:1.1.0-beta01")
+ docs("androidx.media3:media3-exoplayer-dash:1.1.0-beta01")
+ docs("androidx.media3:media3-exoplayer-hls:1.1.0-beta01")
+ docs("androidx.media3:media3-exoplayer-ima:1.1.0-beta01")
+ docs("androidx.media3:media3-exoplayer-rtsp:1.1.0-beta01")
+ docs("androidx.media3:media3-exoplayer-smoothstreaming:1.1.0-beta01")
+ docs("androidx.media3:media3-exoplayer-workmanager:1.1.0-beta01")
+ docs("androidx.media3:media3-extractor:1.1.0-beta01")
+ docs("androidx.media3:media3-muxer:1.1.0-beta01")
+ docs("androidx.media3:media3-session:1.1.0-beta01")
+ docs("androidx.media3:media3-test-utils:1.1.0-beta01")
+ docs("androidx.media3:media3-test-utils-robolectric:1.1.0-beta01")
+ docs("androidx.media3:media3-transformer:1.1.0-beta01")
+ docs("androidx.media3:media3-ui:1.1.0-beta01")
+ docs("androidx.media3:media3-ui-leanback:1.1.0-beta01")
docs("androidx.mediarouter:mediarouter:1.6.0-alpha03")
docs("androidx.mediarouter:mediarouter-testing:1.6.0-alpha03")
docs("androidx.metrics:metrics-performance:1.0.0-alpha04")
- docs("androidx.navigation:navigation-common:2.6.0-rc01")
- docs("androidx.navigation:navigation-common-ktx:2.6.0-rc01")
- docs("androidx.navigation:navigation-compose:2.6.0-rc01")
- samples("androidx.navigation:navigation-compose-samples:2.6.0-rc01")
- docs("androidx.navigation:navigation-dynamic-features-fragment:2.6.0-rc01")
- docs("androidx.navigation:navigation-dynamic-features-runtime:2.6.0-rc01")
- docs("androidx.navigation:navigation-fragment:2.6.0-rc01")
- docs("androidx.navigation:navigation-fragment-ktx:2.6.0-rc01")
- docs("androidx.navigation:navigation-runtime:2.6.0-rc01")
- docs("androidx.navigation:navigation-runtime-ktx:2.6.0-rc01")
- docs("androidx.navigation:navigation-testing:2.6.0-rc01")
- docs("androidx.navigation:navigation-ui:2.6.0-rc01")
- docs("androidx.navigation:navigation-ui-ktx:2.6.0-rc01")
- docs("androidx.paging:paging-common:3.2.0-alpha05")
- docs("androidx.paging:paging-common-ktx:3.2.0-alpha05")
- docs("androidx.paging:paging-compose:1.0.0-alpha19")
- samples("androidx.paging:paging-compose-samples:1.0.0-alpha19")
- docs("androidx.paging:paging-guava:3.2.0-alpha05")
- docs("androidx.paging:paging-runtime:3.2.0-alpha05")
- docs("androidx.paging:paging-runtime-ktx:3.2.0-alpha05")
- docs("androidx.paging:paging-rxjava2:3.2.0-alpha05")
- docs("androidx.paging:paging-rxjava2-ktx:3.2.0-alpha05")
- docs("androidx.paging:paging-rxjava3:3.2.0-alpha05")
- samples("androidx.paging:paging-samples:3.2.0-alpha05")
- docs("androidx.paging:paging-testing:3.2.0-alpha05")
+ docs("androidx.navigation:navigation-common:2.7.0-alpha01")
+ docs("androidx.navigation:navigation-common-ktx:2.7.0-alpha01")
+ docs("androidx.navigation:navigation-compose:2.7.0-alpha01")
+ samples("androidx.navigation:navigation-compose-samples:2.7.0-alpha01")
+ docs("androidx.navigation:navigation-dynamic-features-fragment:2.7.0-alpha01")
+ docs("androidx.navigation:navigation-dynamic-features-runtime:2.7.0-alpha01")
+ docs("androidx.navigation:navigation-fragment:2.7.0-alpha01")
+ docs("androidx.navigation:navigation-fragment-ktx:2.7.0-alpha01")
+ docs("androidx.navigation:navigation-runtime:2.7.0-alpha01")
+ docs("androidx.navigation:navigation-runtime-ktx:2.7.0-alpha01")
+ docs("androidx.navigation:navigation-testing:2.7.0-alpha01")
+ docs("androidx.navigation:navigation-ui:2.7.0-alpha01")
+ docs("androidx.navigation:navigation-ui-ktx:2.7.0-alpha01")
+ docs("androidx.paging:paging-common:3.2.0-alpha06")
+ docs("androidx.paging:paging-common-ktx:3.2.0-alpha06")
+ docs("androidx.paging:paging-compose:1.0.0-alpha20")
+ samples("androidx.paging:paging-compose-samples:1.0.0-alpha20")
+ docs("androidx.paging:paging-guava:3.2.0-alpha06")
+ docs("androidx.paging:paging-runtime:3.2.0-alpha06")
+ docs("androidx.paging:paging-runtime-ktx:3.2.0-alpha06")
+ docs("androidx.paging:paging-rxjava2:3.2.0-alpha06")
+ docs("androidx.paging:paging-rxjava2-ktx:3.2.0-alpha06")
+ docs("androidx.paging:paging-rxjava3:3.2.0-alpha06")
+ samples("androidx.paging:paging-samples:3.2.0-alpha06")
+ docs("androidx.paging:paging-testing:3.2.0-alpha06")
docs("androidx.palette:palette:1.0.0")
docs("androidx.palette:palette-ktx:1.0.0")
docs("androidx.percentlayout:percentlayout:1.0.1")
@@ -276,13 +277,13 @@
docs("androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta04")
docs("androidx.privacysandbox.sdkruntime:sdkruntime-client:1.0.0-alpha04")
docs("androidx.privacysandbox.sdkruntime:sdkruntime-core:1.0.0-alpha04")
- docs("androidx.privacysandbox.tools:tools:1.0.0-alpha03")
- docs("androidx.privacysandbox.tools:tools-apigenerator:1.0.0-alpha03")
- docs("androidx.privacysandbox.tools:tools-apipackager:1.0.0-alpha03")
- docs("androidx.privacysandbox.tools:tools-core:1.0.0-alpha03")
- docs("androidx.privacysandbox.ui:ui-client:1.0.0-alpha02")
- docs("androidx.privacysandbox.ui:ui-core:1.0.0-alpha02")
- docs("androidx.privacysandbox.ui:ui-provider:1.0.0-alpha02")
+ docs("androidx.privacysandbox.tools:tools:1.0.0-alpha04")
+ docs("androidx.privacysandbox.tools:tools-apigenerator:1.0.0-alpha04")
+ docs("androidx.privacysandbox.tools:tools-apipackager:1.0.0-alpha04")
+ docs("androidx.privacysandbox.tools:tools-core:1.0.0-alpha04")
+ docs("androidx.privacysandbox.ui:ui-client:1.0.0-alpha03")
+ docs("androidx.privacysandbox.ui:ui-core:1.0.0-alpha03")
+ docs("androidx.privacysandbox.ui:ui-provider:1.0.0-alpha03")
docs("androidx.profileinstaller:profileinstaller:1.3.1")
docs("androidx.recommendation:recommendation:1.0.0")
docs("androidx.recyclerview:recyclerview:1.3.0")
@@ -341,8 +342,8 @@
docs("androidx.test.services:storage:1.5.0-alpha01")
docs("androidx.test.uiautomator:uiautomator:2.3.0-alpha03")
docs("androidx.textclassifier:textclassifier:1.0.0-alpha04")
- docs("androidx.tracing:tracing:1.2.0-beta04")
- docs("androidx.tracing:tracing-ktx:1.2.0-beta04")
+ docs("androidx.tracing:tracing:1.2.0-rc01")
+ docs("androidx.tracing:tracing-ktx:1.2.0-rc01")
docs("androidx.tracing:tracing-perfetto:1.0.0-alpha15")
docs("androidx.tracing:tracing-perfetto-common:1.0.0-alpha15")
docs("androidx.transition:transition:1.5.0-alpha01")
@@ -355,29 +356,28 @@
docs("androidx.vectordrawable:vectordrawable-animated:1.2.0-alpha01")
docs("androidx.vectordrawable:vectordrawable-seekable:1.0.0-beta01")
docs("androidx.versionedparcelable:versionedparcelable:1.1.1")
- docs("androidx.viewpager2:viewpager2:1.1.0-beta01")
+ docs("androidx.viewpager2:viewpager2:1.1.0-beta02")
docs("androidx.viewpager:viewpager:1.1.0-alpha01")
- docs("androidx.wear.compose:compose-foundation:1.2.0-alpha10")
- samples("androidx.wear.compose:compose-foundation-samples:1.2.0-alpha10")
- docs("androidx.wear.compose:compose-material:1.2.0-alpha10")
- docs("androidx.wear.compose:compose-material-core:1.2.0-alpha10")
- samples("androidx.wear.compose:compose-material-samples:1.2.0-alpha10")
- docs("androidx.wear.compose:compose-material3:1.0.0-alpha04")
- samples("androidx.wear.compose:compose-material3-samples:1.2.0-alpha10")
- docs("androidx.wear.compose:compose-navigation:1.2.0-alpha10")
- samples("androidx.wear.compose:compose-navigation-samples:1.2.0-alpha10")
- docs("androidx.wear.compose:compose-ui-tooling:1.2.0-alpha10")
- docs("androidx.wear.protolayout:protolayout:1.0.0-alpha09")
- docs("androidx.wear.protolayout:protolayout-expression:1.0.0-alpha09")
- docs("androidx.wear.protolayout:protolayout-material:1.0.0-alpha09")
- docs("androidx.wear.protolayout:protolayout-proto:1.0.0-alpha09")
- docs("androidx.wear.protolayout:protolayout-renderer:1.0.0-alpha09")
- docs("androidx.wear.tiles:tiles:1.2.0-alpha05")
- docs("androidx.wear.tiles:tiles-material:1.2.0-alpha05")
- docs("androidx.wear.tiles:tiles-proto:1.2.0-alpha05")
- docs("androidx.wear.tiles:tiles-renderer:1.2.0-alpha05")
- docs("androidx.wear.tiles:tiles-testing:1.2.0-alpha05")
- docs("androidx.wear.tiles:tiles-tooling:1.2.0-alpha05")
+ docs("androidx.wear.compose:compose-foundation:1.2.0-beta01")
+ samples("androidx.wear.compose:compose-foundation-samples:1.2.0-beta01")
+ docs("androidx.wear.compose:compose-material:1.2.0-beta01")
+ docs("androidx.wear.compose:compose-material-core:1.2.0-beta01")
+ samples("androidx.wear.compose:compose-material-samples:1.2.0-beta01")
+ docs("androidx.wear.compose:compose-material3:1.0.0-alpha05")
+ samples("androidx.wear.compose:compose-material3-samples:1.2.0-beta01")
+ docs("androidx.wear.compose:compose-navigation:1.2.0-beta01")
+ samples("androidx.wear.compose:compose-navigation-samples:1.2.0-beta01")
+ docs("androidx.wear.compose:compose-ui-tooling:1.2.0-beta01")
+ docs("androidx.wear.protolayout:protolayout:1.0.0-alpha10")
+ docs("androidx.wear.protolayout:protolayout-expression:1.0.0-alpha10")
+ docs("androidx.wear.protolayout:protolayout-material:1.0.0-alpha10")
+ docs("androidx.wear.protolayout:protolayout-renderer:1.0.0-alpha10")
+ docs("androidx.wear.tiles:tiles:1.2.0-alpha06")
+ docs("androidx.wear.tiles:tiles-material:1.2.0-alpha06")
+ docs("androidx.wear.tiles:tiles-proto:1.2.0-alpha06")
+ docs("androidx.wear.tiles:tiles-renderer:1.2.0-alpha06")
+ docs("androidx.wear.tiles:tiles-testing:1.2.0-alpha06")
+ docs("androidx.wear.tiles:tiles-tooling:1.2.0-alpha06")
docs("androidx.wear.watchface:watchface:1.2.0-alpha08")
docs("androidx.wear.watchface:watchface-client:1.2.0-alpha08")
docs("androidx.wear.watchface:watchface-client-guava:1.2.0-alpha08")
@@ -402,17 +402,17 @@
docs("androidx.wear:wear-input:1.2.0-alpha02")
samples("androidx.wear:wear-input-samples:1.2.0-alpha01")
docs("androidx.wear:wear-input-testing:1.2.0-alpha02")
- docs("androidx.webkit:webkit:1.7.0-rc01")
- docs("androidx.window.extensions.core:core:1.0.0-rc01")
- docs("androidx.window:window:1.1.0-rc01")
+ docs("androidx.webkit:webkit:1.7.0")
+ docs("androidx.window.extensions.core:core:1.0.0")
+ docs("androidx.window:window:1.2.0-alpha01")
stubs(fileTree(dir: "../window/stubs/", include: ["window-sidecar-release-0.1.0-alpha01.aar"]))
- docs("androidx.window:window-core:1.1.0-rc01")
+ docs("androidx.window:window-core:1.2.0-alpha01")
stubs("androidx.window:window-extensions:1.0.0-alpha01")
- docs("androidx.window:window-java:1.1.0-rc01")
- docs("androidx.window:window-rxjava2:1.1.0-rc01")
- docs("androidx.window:window-rxjava3:1.1.0-rc01")
- samples("androidx.window:window-samples:1.1.0-rc01")
- docs("androidx.window:window-testing:1.1.0-rc01")
+ docs("androidx.window:window-java:1.2.0-alpha01")
+ docs("androidx.window:window-rxjava2:1.2.0-alpha01")
+ docs("androidx.window:window-rxjava3:1.2.0-alpha01")
+ samples("androidx.window:window-samples:1.2.0-alpha01")
+ docs("androidx.window:window-testing:1.2.0-alpha01")
docs("androidx.work:work-gcm:2.8.1")
docs("androidx.work:work-multiprocess:2.8.1")
docs("androidx.work:work-runtime:2.8.1")
diff --git a/docs-public/package-lists/android/package-list b/docs-public/package-lists/android/package-list
index 7a59cca3..9c51578 100644
--- a/docs-public/package-lists/android/package-list
+++ b/docs-public/package-lists/android/package-list
@@ -2,25 +2,48 @@
android
android.accessibilityservice
android.accounts
+android.adservices
+android.adservices.adid
+android.adservices.adselection
+android.adservices.appsetid
+android.adservices.common
+android.adservices.customaudience
+android.adservices.exceptions
+android.adservices.measurement
+android.adservices.topics
android.animation
android.annotation
android.app
android.app.admin
+android.app.appsearch
+android.app.appsearch.exceptions
+android.app.appsearch.observer
+android.app.appsearch.util
android.app.assist
android.app.backup
+android.app.blob
android.app.job
+android.app.people
android.app.role
+android.app.sdksandbox
+android.app.sdksandbox.sdkprovider
android.app.slice
android.app.usage
android.appwidget
android.bluetooth
android.bluetooth.le
android.companion
+android.companion.virtual
android.content
+android.content.om
android.content.pm
+android.content.pm.verify.domain
android.content.res
+android.content.res.loader
+android.credentials
android.database
android.database.sqlite
+android.devicelock
android.drm
android.gesture
android.graphics
@@ -36,28 +59,42 @@
android.hardware.display
android.hardware.fingerprint
android.hardware.input
+android.hardware.lights
android.hardware.usb
+android.health.connect
+android.health.connect.changelog
+android.health.connect.datatypes
+android.health.connect.datatypes.units
android.icu.lang
android.icu.math
+android.icu.number
android.icu.text
android.icu.util
android.inputmethodservice
android.location
+android.location.altitude
+android.location.provider
android.media
android.media.audiofx
android.media.browse
android.media.effect
+android.media.metrics
android.media.midi
android.media.projection
android.media.session
android.media.tv
+android.media.tv.interactive
android.mtp
android.net
+android.net.eap
android.net.http
+android.net.ipsec.ike
+android.net.ipsec.ike.exceptions
android.net.nsd
android.net.rtp
android.net.sip
android.net.ssl
+android.net.vcn
android.net.wifi
android.net.wifi.aware
android.net.wifi.hotspot2
@@ -71,6 +108,7 @@
android.nfc.tech
android.opengl
android.os
+android.os.ext
android.os.health
android.os.storage
android.os.strictmode
@@ -83,13 +121,20 @@
android.sax
android.se.omapi
android.security
+android.security.identity
android.security.keystore
+android.service.assist.classification
android.service.autofill
android.service.carrier
android.service.chooser
+android.service.controls
+android.service.controls.actions
+android.service.controls.templates
+android.service.credentials
android.service.dreams
android.service.media
android.service.notification
+android.service.quickaccesswallet
android.service.quicksettings
android.service.restrictions
android.service.textservice
@@ -106,6 +151,9 @@
android.telephony.emergency
android.telephony.euicc
android.telephony.gsm
+android.telephony.ims
+android.telephony.ims.feature
+android.telephony.ims.stub
android.telephony.mbms
android.test
android.test.mock
@@ -118,18 +166,24 @@
android.text.util
android.transition
android.util
+android.util.proto
android.view
android.view.accessibility
android.view.animation
android.view.autofill
android.view.contentcapture
+android.view.displayhash
android.view.inputmethod
android.view.inspector
android.view.textclassifier
android.view.textservice
+android.view.translation
android.webkit
android.widget
+android.widget.inline
+android.window
dalvik.annotation
+dalvik.annotation.optimization
dalvik.bytecode
dalvik.system
java.awt.font
@@ -140,6 +194,7 @@
java.lang.invoke
java.lang.ref
java.lang.reflect
+java.lang.runtime
java.math
java.net
java.nio
@@ -173,6 +228,7 @@
java.util.regex
java.util.stream
java.util.zip
+javax.annotation.processing
javax.crypto
javax.crypto.interfaces
javax.crypto.spec
@@ -210,4 +266,3 @@
org.xml.sax.helpers
org.xmlpull.v1
org.xmlpull.v1.sax2
-
diff --git a/docs-public/package-lists/auto-value/package-list b/docs-public/package-lists/auto-value/package-list
new file mode 100644
index 0000000..9941526
--- /dev/null
+++ b/docs-public/package-lists/auto-value/package-list
@@ -0,0 +1,13 @@
+com.google.auto.value
+com.google.auto.value.extension
+com.google.auto.value.extension.memoized
+com.google.auto.value.extension.memoized.processor
+com.google.auto.value.extension.serializable
+com.google.auto.value.extension.serializable.processor
+com.google.auto.value.extension.serializable.serializer
+com.google.auto.value.extension.serializable.serializer.impl
+com.google.auto.value.extension.serializable.serializer.interfaces
+com.google.auto.value.extension.serializable.serializer.runtime
+com.google.auto.value.extension.toprettystring
+com.google.auto.value.extension.toprettystring.processor
+com.google.auto.value.processor
diff --git a/docs-public/package-lists/dagger/package-list b/docs-public/package-lists/dagger/package-list
new file mode 100644
index 0000000..ff59b75
--- /dev/null
+++ b/docs-public/package-lists/dagger/package-list
@@ -0,0 +1,36 @@
+$dokka.format:javadoc-v1
+dagger
+dagger.android
+dagger.android.internal
+dagger.android.support
+dagger.assisted
+dagger.grpc.server
+dagger.grpc.server.processor
+dagger.hilt
+dagger.hilt.android
+dagger.hilt.android.components
+dagger.hilt.android.flags
+dagger.hilt.android.internal.builders
+dagger.hilt.android.internal.lifecycle
+dagger.hilt.android.internal.managers
+dagger.hilt.android.internal.migration
+dagger.hilt.android.internal.modules
+dagger.hilt.android.internal.testing
+dagger.hilt.android.lifecycle
+dagger.hilt.android.migration
+dagger.hilt.android.qualifiers
+dagger.hilt.android.scopes
+dagger.hilt.android.testing
+dagger.hilt.codegen
+dagger.hilt.components
+dagger.hilt.internal.aliasof
+dagger.hilt.internal.definecomponent
+dagger.hilt.internal.generatesrootinput
+dagger.hilt.migration
+dagger.hilt.testing
+dagger.model
+dagger.multibindings
+dagger.producers
+dagger.producers.monitoring
+dagger.spi
+dagger.spi.model
diff --git a/docs-public/package-lists/grpc/package-list b/docs-public/package-lists/grpc/package-list
new file mode 100644
index 0000000..67e3d0a
--- /dev/null
+++ b/docs-public/package-lists/grpc/package-list
@@ -0,0 +1,24 @@
+io.grpc
+io.grpc.auth
+io.grpc.binarylog.v1
+io.grpc.channelz.v1
+io.grpc.grpclb
+io.grpc.health.v1
+io.grpc.inprocess
+io.grpc.lb.v1
+io.grpc.netty
+io.grpc.okhttp
+io.grpc.protobuf
+io.grpc.protobuf.lite
+io.grpc.protobuf.services
+io.grpc.reflection.v1alpha
+io.grpc.rls
+io.grpc.services
+io.grpc.servlet
+io.grpc.servlet.jakarta
+io.grpc.stub
+io.grpc.stub.annotations
+io.grpc.testing
+io.grpc.util
+io.grpc.xds
+io.grpc.xds.orca
diff --git a/docs-public/package-lists/guava/package-list b/docs-public/package-lists/guava/package-list
index 8644ca9..bb28bbc 100644
--- a/docs-public/package-lists/guava/package-list
+++ b/docs-public/package-lists/guava/package-list
@@ -1 +1,16 @@
-com.google.common.util.concurrent
\ No newline at end of file
+$dokka.format:javadoc1
+com.google.common.annotations
+com.google.common.base
+com.google.common.cache
+com.google.common.collect
+com.google.common.escape
+com.google.common.eventbus
+com.google.common.hash
+com.google.common.html
+com.google.common.io
+com.google.common.math
+com.google.common.net
+com.google.common.primitives
+com.google.common.reflect
+com.google.common.util.concurrent
+com.google.common.xml
\ No newline at end of file
diff --git a/docs-public/package-lists/jetbrains-annotations/package-list b/docs-public/package-lists/jetbrains-annotations/package-list
new file mode 100644
index 0000000..b9d8d52
--- /dev/null
+++ b/docs-public/package-lists/jetbrains-annotations/package-list
@@ -0,0 +1,2 @@
+org.intellij.lang.annotations
+org.jetbrains.annotations
diff --git a/docs-public/package-lists/kotlinpoet/package-list b/docs-public/package-lists/kotlinpoet/package-list
new file mode 100644
index 0000000..c1ef0ed
--- /dev/null
+++ b/docs-public/package-lists/kotlinpoet/package-list
@@ -0,0 +1,762 @@
+$dokka.format:html-v1
+$dokka.linkExtension:html
+$dokka.location:com.squareup.kotlinpoet.jvm////PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/index.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmField/com.squareup.kotlinpoet.PropertySpec.Builder#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-field.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmInline/com.squareup.kotlinpoet.TypeSpec.Builder#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-inline.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmMultifileClass/com.squareup.kotlinpoet.FileSpec.Builder#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-multifile-class.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmName/com.squareup.kotlinpoet.FileSpec.Builder#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-name.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmName/com.squareup.kotlinpoet.FunSpec.Builder#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-name.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmOverloads/com.squareup.kotlinpoet.FunSpec.Builder#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-overloads.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmRecord/com.squareup.kotlinpoet.TypeSpec.Builder#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-record.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmStatic/com.squareup.kotlinpoet.FunSpec.Builder#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-static.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmStatic/com.squareup.kotlinpoet.PropertySpec.Builder#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-static.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmSuppressWildcards/com.squareup.kotlinpoet.FunSpec.Builder#kotlin.Boolean/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-suppress-wildcards.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmSuppressWildcards/com.squareup.kotlinpoet.PropertySpec.Builder#kotlin.Boolean/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-suppress-wildcards.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmSuppressWildcards/com.squareup.kotlinpoet.TypeName#kotlin.Boolean/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-suppress-wildcards.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmSuppressWildcards/com.squareup.kotlinpoet.TypeSpec.Builder#kotlin.Boolean/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-suppress-wildcards.html
+$dokka.location:com.squareup.kotlinpoet.jvm//jvmWildcard/com.squareup.kotlinpoet.TypeName#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/jvm-wildcard.html
+$dokka.location:com.squareup.kotlinpoet.jvm//strictfp/com.squareup.kotlinpoet.FunSpec.Builder#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/strictfp.html
+$dokka.location:com.squareup.kotlinpoet.jvm//synchronized/com.squareup.kotlinpoet.FunSpec.Builder#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/synchronized.html
+$dokka.location:com.squareup.kotlinpoet.jvm//throws/com.squareup.kotlinpoet.FunSpec.Builder#kotlin.Array[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/throws.html
+$dokka.location:com.squareup.kotlinpoet.jvm//throws/com.squareup.kotlinpoet.FunSpec.Builder#kotlin.Array[java.lang.reflect.Type]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/throws.html
+$dokka.location:com.squareup.kotlinpoet.jvm//throws/com.squareup.kotlinpoet.FunSpec.Builder#kotlin.Array[kotlin.reflect.KClass[kotlin.Throwable]]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/throws.html
+$dokka.location:com.squareup.kotlinpoet.jvm//throws/com.squareup.kotlinpoet.FunSpec.Builder#kotlin.collections.Iterable[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/throws.html
+$dokka.location:com.squareup.kotlinpoet.jvm//transient/com.squareup.kotlinpoet.PropertySpec.Builder#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/transient.html
+$dokka.location:com.squareup.kotlinpoet.jvm//volatile/com.squareup.kotlinpoet.PropertySpec.Builder#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.jvm/volatile.html
+$dokka.location:com.squareup.kotlinpoet.tags////PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.tags/index.html
+$dokka.location:com.squareup.kotlinpoet.tags/TypeAliasTag///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.tags/-type-alias-tag/index.html
+$dokka.location:com.squareup.kotlinpoet.tags/TypeAliasTag/TypeAliasTag/#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.tags/-type-alias-tag/-type-alias-tag.html
+$dokka.location:com.squareup.kotlinpoet.tags/TypeAliasTag/abbreviatedType/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet.tags/-type-alias-tag/abbreviated-type.html
+$dokka.location:com.squareup.kotlinpoet////PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/index.html
+$dokka.location:com.squareup.kotlinpoet//ANNOTATION/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-a-n-n-o-t-a-t-i-o-n.html
+$dokka.location:com.squareup.kotlinpoet//ANY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-a-n-y.html
+$dokka.location:com.squareup.kotlinpoet//ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//BOOLEAN/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-b-o-o-l-e-a-n.html
+$dokka.location:com.squareup.kotlinpoet//BOOLEAN_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-b-o-o-l-e-a-n_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//BYTE/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-b-y-t-e.html
+$dokka.location:com.squareup.kotlinpoet//BYTE_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-b-y-t-e_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//CHAR/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-c-h-a-r.html
+$dokka.location:com.squareup.kotlinpoet//CHAR_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-c-h-a-r_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//CHAR_SEQUENCE/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-c-h-a-r_-s-e-q-u-e-n-c-e.html
+$dokka.location:com.squareup.kotlinpoet//COLLECTION/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-c-o-l-l-e-c-t-i-o-n.html
+$dokka.location:com.squareup.kotlinpoet//COMPARABLE/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-c-o-m-p-a-r-a-b-l-e.html
+$dokka.location:com.squareup.kotlinpoet//DOUBLE/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-d-o-u-b-l-e.html
+$dokka.location:com.squareup.kotlinpoet//DOUBLE_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-d-o-u-b-l-e_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//DYNAMIC/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-d-y-n-a-m-i-c.html
+$dokka.location:com.squareup.kotlinpoet//ENUM/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-e-n-u-m.html
+$dokka.location:com.squareup.kotlinpoet//FLOAT/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-f-l-o-a-t.html
+$dokka.location:com.squareup.kotlinpoet//FLOAT_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-f-l-o-a-t_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//INT/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-i-n-t.html
+$dokka.location:com.squareup.kotlinpoet//INT_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-i-n-t_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//ITERABLE/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-i-t-e-r-a-b-l-e.html
+$dokka.location:com.squareup.kotlinpoet//LIST/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-l-i-s-t.html
+$dokka.location:com.squareup.kotlinpoet//LONG/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-l-o-n-g.html
+$dokka.location:com.squareup.kotlinpoet//LONG_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-l-o-n-g_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//MAP/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-m-a-p.html
+$dokka.location:com.squareup.kotlinpoet//MAP_ENTRY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-m-a-p_-e-n-t-r-y.html
+$dokka.location:com.squareup.kotlinpoet//MUTABLE_COLLECTION/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-m-u-t-a-b-l-e_-c-o-l-l-e-c-t-i-o-n.html
+$dokka.location:com.squareup.kotlinpoet//MUTABLE_ITERABLE/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-m-u-t-a-b-l-e_-i-t-e-r-a-b-l-e.html
+$dokka.location:com.squareup.kotlinpoet//MUTABLE_LIST/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-m-u-t-a-b-l-e_-l-i-s-t.html
+$dokka.location:com.squareup.kotlinpoet//MUTABLE_MAP/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-m-u-t-a-b-l-e_-m-a-p.html
+$dokka.location:com.squareup.kotlinpoet//MUTABLE_MAP_ENTRY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-m-u-t-a-b-l-e_-m-a-p_-e-n-t-r-y.html
+$dokka.location:com.squareup.kotlinpoet//MUTABLE_SET/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-m-u-t-a-b-l-e_-s-e-t.html
+$dokka.location:com.squareup.kotlinpoet//NOTHING/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-n-o-t-h-i-n-g.html
+$dokka.location:com.squareup.kotlinpoet//NUMBER/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-n-u-m-b-e-r.html
+$dokka.location:com.squareup.kotlinpoet//SET/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-s-e-t.html
+$dokka.location:com.squareup.kotlinpoet//SHORT/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-s-h-o-r-t.html
+$dokka.location:com.squareup.kotlinpoet//SHORT_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-s-h-o-r-t_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//STAR/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-s-t-a-r.html
+$dokka.location:com.squareup.kotlinpoet//STRING/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-s-t-r-i-n-g.html
+$dokka.location:com.squareup.kotlinpoet//THROWABLE/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-t-h-r-o-w-a-b-l-e.html
+$dokka.location:com.squareup.kotlinpoet//UNIT/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-u-n-i-t.html
+$dokka.location:com.squareup.kotlinpoet//U_BYTE/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-u_-b-y-t-e.html
+$dokka.location:com.squareup.kotlinpoet//U_BYTE_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-u_-b-y-t-e_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//U_INT/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-u_-i-n-t.html
+$dokka.location:com.squareup.kotlinpoet//U_INT_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-u_-i-n-t_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//U_LONG/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-u_-l-o-n-g.html
+$dokka.location:com.squareup.kotlinpoet//U_LONG_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-u_-l-o-n-g_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//U_SHORT/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-u_-s-h-o-r-t.html
+$dokka.location:com.squareup.kotlinpoet//U_SHORT_ARRAY/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-u_-s-h-o-r-t_-a-r-r-a-y.html
+$dokka.location:com.squareup.kotlinpoet//asClassName/java.lang.Class[*]#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-class-name.html
+$dokka.location:com.squareup.kotlinpoet//asClassName/javax.lang.model.element.TypeElement#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-class-name.html
+$dokka.location:com.squareup.kotlinpoet//asClassName/kotlin.reflect.KClass[*]#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-class-name.html
+$dokka.location:com.squareup.kotlinpoet//asParameterizedTypeName/java.lang.reflect.ParameterizedType#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-parameterized-type-name.html
+$dokka.location:com.squareup.kotlinpoet//asTypeName/java.lang.reflect.Type#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-type-name.html
+$dokka.location:com.squareup.kotlinpoet//asTypeName/javax.lang.model.type.TypeMirror#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-type-name.html
+$dokka.location:com.squareup.kotlinpoet//asTypeName/kotlin.reflect.KClass[*]#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-type-name.html
+$dokka.location:com.squareup.kotlinpoet//asTypeName/kotlin.reflect.KType#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-type-name.html
+$dokka.location:com.squareup.kotlinpoet//asTypeVariableName/javax.lang.model.element.TypeParameterElement#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-type-variable-name.html
+$dokka.location:com.squareup.kotlinpoet//asTypeVariableName/javax.lang.model.type.TypeVariable#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-type-variable-name.html
+$dokka.location:com.squareup.kotlinpoet//asTypeVariableName/kotlin.reflect.KTypeParameter#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-type-variable-name.html
+$dokka.location:com.squareup.kotlinpoet//asWildcardTypeName/java.lang.reflect.WildcardType#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-wildcard-type-name.html
+$dokka.location:com.squareup.kotlinpoet//asWildcardTypeName/javax.lang.model.type.WildcardType#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/as-wildcard-type-name.html
+$dokka.location:com.squareup.kotlinpoet//buildCodeBlock/#kotlin.Function1[com.squareup.kotlinpoet.CodeBlock.Builder,kotlin.Unit]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/build-code-block.html
+$dokka.location:com.squareup.kotlinpoet//joinToCode/kotlin.collections.Collection[com.squareup.kotlinpoet.CodeBlock]#kotlin.CharSequence#kotlin.CharSequence#kotlin.CharSequence/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/join-to-code.html
+$dokka.location:com.squareup.kotlinpoet//tag/com.squareup.kotlinpoet.AnnotationSpec.Builder#TypeParam(bounds=[kotlin.Any])?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/tag.html
+$dokka.location:com.squareup.kotlinpoet//tag/com.squareup.kotlinpoet.FileSpec.Builder#TypeParam(bounds=[kotlin.Any])?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/tag.html
+$dokka.location:com.squareup.kotlinpoet//tag/com.squareup.kotlinpoet.FunSpec.Builder#TypeParam(bounds=[kotlin.Any])?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/tag.html
+$dokka.location:com.squareup.kotlinpoet//tag/com.squareup.kotlinpoet.ParameterSpec.Builder#TypeParam(bounds=[kotlin.Any])?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/tag.html
+$dokka.location:com.squareup.kotlinpoet//tag/com.squareup.kotlinpoet.PropertySpec.Builder#TypeParam(bounds=[kotlin.Any])?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/tag.html
+$dokka.location:com.squareup.kotlinpoet//tag/com.squareup.kotlinpoet.Taggable#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/tag.html
+$dokka.location:com.squareup.kotlinpoet//tag/com.squareup.kotlinpoet.TypeAliasSpec.Builder#TypeParam(bounds=[kotlin.Any])?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/tag.html
+$dokka.location:com.squareup.kotlinpoet//tag/com.squareup.kotlinpoet.TypeSpec.Builder#TypeParam(bounds=[kotlin.Any])?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/tag.html
+$dokka.location:com.squareup.kotlinpoet//typeNameOf/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/type-name-of.html
+$dokka.location:com.squareup.kotlinpoet//withIndent/com.squareup.kotlinpoet.CodeBlock.Builder#kotlin.Function1[com.squareup.kotlinpoet.CodeBlock.Builder,kotlin.Unit]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/with-indent.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Builder.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-builder/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Builder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-builder/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Builder/addMember/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-builder/add-member.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Builder/addMember/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-builder/add-member.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Builder/build/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-builder/build.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Builder/members/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-builder/members.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Builder/tags/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-builder/tags.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Builder/useSiteTarget/#com.squareup.kotlinpoet.AnnotationSpec.UseSiteTarget?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-builder/use-site-target.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Companion/builder/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Companion/builder/#com.squareup.kotlinpoet.ParameterizedTypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Companion/builder/#java.lang.Class[kotlin.Annotation]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Companion/builder/#kotlin.reflect.KClass[kotlin.Annotation]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Companion/get/#javax.lang.model.element.AnnotationMirror/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-companion/get.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.Companion/get/#kotlin.Annotation#kotlin.Boolean/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-companion/get.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget.DELEGATE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/-d-e-l-e-g-a-t-e/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget.FIELD///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/-f-i-e-l-d/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget.FILE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/-f-i-l-e/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget.GET///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/-g-e-t/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget.PARAM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/-p-a-r-a-m/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget.PROPERTY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/-p-r-o-p-e-r-t-y/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget.RECEIVER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/-r-e-c-e-i-v-e-r/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget.SET///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/-s-e-t/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget.SETPARAM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/-s-e-t-p-a-r-a-m/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget/valueOf/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/value-of.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec.UseSiteTarget/values/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/-use-site-target/values.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/index.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/equals.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec/members/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/members.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec/toBuilder/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/to-builder.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec/toString/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/to-string.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec/typeName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/type-name.html
+$dokka.location:com.squareup.kotlinpoet/AnnotationSpec/useSiteTarget/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-annotation-spec/use-site-target.html
+$dokka.location:com.squareup.kotlinpoet/ClassName.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/ClassName.Companion/bestGuess/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/-companion/best-guess.html
+$dokka.location:com.squareup.kotlinpoet/ClassName///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/index.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/ClassName/#kotlin.String#kotlin.Array[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/-class-name.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/ClassName/#kotlin.String#kotlin.collections.List[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/-class-name.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/canonicalName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/canonical-name.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/compareTo/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/compare-to.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/constructorReference/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/constructor-reference.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/copy/#kotlin.Boolean#kotlin.collections.List[com.squareup.kotlinpoet.AnnotationSpec]#kotlin.collections.Map[kotlin.reflect.KClass[*],kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/copy.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/enclosingClassName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/enclosing-class-name.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/equals.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/nestedClass/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/nested-class.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/packageName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/package-name.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/peerClass/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/peer-class.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/reflectionName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/reflection-name.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/simpleName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/simple-name.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/simpleNames/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/simple-names.html
+$dokka.location:com.squareup.kotlinpoet/ClassName/topLevelClassName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-class-name/top-level-class-name.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/index.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/Builder/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/-builder.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/add/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/add.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/add/#kotlin.String#kotlin.Array[kotlin.Any?]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/add.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/addNamed/#kotlin.String#kotlin.collections.Map[kotlin.String,*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/add-named.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/addStatement/#kotlin.String#kotlin.Array[kotlin.Any?]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/add-statement.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/beginControlFlow/#kotlin.String#kotlin.Array[kotlin.Any?]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/begin-control-flow.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/build/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/build.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/clear/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/clear.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/endControlFlow/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/end-control-flow.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/indent/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/indent.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/isEmpty/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/is-empty.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/isNotEmpty/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/is-not-empty.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/nextControlFlow/#kotlin.String#kotlin.Array[kotlin.Any?]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/next-control-flow.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Builder/unindent/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-builder/unindent.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Companion/builder/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock.Companion/of/#kotlin.String#kotlin.Array[kotlin.Any?]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/-companion/of.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/index.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/equals.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock/isEmpty/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/is-empty.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock/isNotEmpty/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/is-not-empty.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock/toBuilder/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/to-builder.html
+$dokka.location:com.squareup.kotlinpoet/CodeBlock/toString/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-code-block/to-string.html
+$dokka.location:com.squareup.kotlinpoet/ContextReceivable.Builder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-context-receivable/-builder/index.html
+$dokka.location:com.squareup.kotlinpoet/ContextReceivable.Builder/contextReceiverTypes/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-context-receivable/-builder/context-receiver-types.html
+$dokka.location:com.squareup.kotlinpoet/ContextReceivable.Builder/contextReceivers/#kotlin.Array[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-context-receivable/-builder/context-receivers.html
+$dokka.location:com.squareup.kotlinpoet/ContextReceivable.Builder/contextReceivers/#kotlin.collections.Iterable[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-context-receivable/-builder/context-receivers.html
+$dokka.location:com.squareup.kotlinpoet/ContextReceivable///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-context-receivable/index.html
+$dokka.location:com.squareup.kotlinpoet/ContextReceivable/contextReceiverTypes/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-context-receivable/context-receiver-types.html
+$dokka.location:com.squareup.kotlinpoet/DelicateKotlinPoetApi///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-delicate-kotlin-poet-api/index.html
+$dokka.location:com.squareup.kotlinpoet/DelicateKotlinPoetApi/message/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-delicate-kotlin-poet-api/message.html
+$dokka.location:com.squareup.kotlinpoet/Dynamic///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-dynamic/index.html
+$dokka.location:com.squareup.kotlinpoet/Dynamic/copy/#kotlin.Boolean#kotlin.collections.List[com.squareup.kotlinpoet.AnnotationSpec]#kotlin.collections.Map[kotlin.reflect.KClass[*],kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-dynamic/copy.html
+$dokka.location:com.squareup.kotlinpoet/ExperimentalKotlinPoetApi///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-experimental-kotlin-poet-api/index.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/index.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addAliasedImport/#com.squareup.kotlinpoet.ClassName#kotlin.String#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-aliased-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addAliasedImport/#com.squareup.kotlinpoet.ClassName#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-aliased-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addAliasedImport/#com.squareup.kotlinpoet.MemberName#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-aliased-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addAliasedImport/#java.lang.Class[*]#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-aliased-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addAliasedImport/#kotlin.reflect.KClass[*]#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-aliased-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addAnnotation/#com.squareup.kotlinpoet.AnnotationSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addAnnotation/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addAnnotation/#java.lang.Class[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addAnnotation/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addBodyComment/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-body-comment.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addCode/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-code.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addCode/#kotlin.String#kotlin.Array[kotlin.Any?]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-code.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addDefaultPackageImport/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-default-package-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addFileComment/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-file-comment.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addFunction/#com.squareup.kotlinpoet.FunSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-function.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addImport/#com.squareup.kotlinpoet.ClassName#kotlin.Array[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addImport/#com.squareup.kotlinpoet.ClassName#kotlin.collections.Iterable[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addImport/#com.squareup.kotlinpoet.Import/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addImport/#java.lang.Class[*]#kotlin.Array[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addImport/#java.lang.Class[*]#kotlin.collections.Iterable[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addImport/#kotlin.Enum[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addImport/#kotlin.String#kotlin.Array[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addImport/#kotlin.String#kotlin.collections.Iterable[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addImport/#kotlin.reflect.KClass[*]#kotlin.Array[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addImport/#kotlin.reflect.KClass[*]#kotlin.collections.Iterable[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-import.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addKotlinDefaultImports/#kotlin.Boolean#kotlin.Boolean/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-kotlin-default-imports.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addNamedCode/#kotlin.String#kotlin.collections.Map[kotlin.String,*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-named-code.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addProperty/#com.squareup.kotlinpoet.PropertySpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-property.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addStatement/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-statement.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addType/#com.squareup.kotlinpoet.TypeSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-type.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/addTypeAlias/#com.squareup.kotlinpoet.TypeAliasSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/add-type-alias.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/annotations/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/annotations.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/beginControlFlow/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/begin-control-flow.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/build/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/build.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/clearBody/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/clear-body.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/clearComment/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/clear-comment.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/clearImports/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/clear-imports.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/defaultImports/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/default-imports.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/endControlFlow/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/end-control-flow.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/imports/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/imports.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/indent/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/indent.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/isScript/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/is-script.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/members/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/members.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/name/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/name.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/nextControlFlow/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/next-control-flow.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/packageName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/package-name.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Builder/tags/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-builder/tags.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Companion/builder/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Companion/builder/#kotlin.String#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Companion/get/#kotlin.String#com.squareup.kotlinpoet.TypeSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-companion/get.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec.Companion/scriptBuilder/#kotlin.String#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/-companion/script-builder.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/index.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/annotations/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/annotations.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/body/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/body.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/comment/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/comment.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/defaultImports/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/default-imports.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/equals.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/isScript/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/is-script.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/members/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/members.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/name/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/name.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/packageName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/package-name.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/toBuilder/#kotlin.String#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/to-builder.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/toJavaFileObject/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/to-java-file-object.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/toString/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/to-string.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/writeTo/#java.io.File/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/write-to.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/writeTo/#java.lang.Appendable/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/write-to.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/writeTo/#java.nio.file.Path/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/write-to.html
+$dokka.location:com.squareup.kotlinpoet/FileSpec/writeTo/#javax.annotation.processing.Filer/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-file-spec/write-to.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/index.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addAnnotation/#com.squareup.kotlinpoet.AnnotationSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addAnnotation/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addAnnotation/#java.lang.Class[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addAnnotation/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addAnnotations/#kotlin.collections.Iterable[com.squareup.kotlinpoet.AnnotationSpec]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-annotations.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addCode/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-code.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addCode/#kotlin.String#kotlin.Array[kotlin.Any?]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-code.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addComment/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-comment.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addKdoc/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addKdoc/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addModifiers/#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-modifiers.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addModifiers/#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-modifiers.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addNamedCode/#kotlin.String#kotlin.collections.Map[kotlin.String,*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-named-code.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addParameter/#com.squareup.kotlinpoet.ParameterSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-parameter.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addParameter/#kotlin.String#com.squareup.kotlinpoet.TypeName#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-parameter.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addParameter/#kotlin.String#com.squareup.kotlinpoet.TypeName#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-parameter.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addParameter/#kotlin.String#java.lang.reflect.Type#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-parameter.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addParameter/#kotlin.String#java.lang.reflect.Type#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-parameter.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addParameter/#kotlin.String#kotlin.reflect.KClass[*]#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-parameter.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addParameter/#kotlin.String#kotlin.reflect.KClass[*]#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-parameter.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addParameters/#kotlin.collections.Iterable[com.squareup.kotlinpoet.ParameterSpec]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-parameters.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addStatement/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-statement.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addTypeVariable/#com.squareup.kotlinpoet.TypeVariableName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-type-variable.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/addTypeVariables/#kotlin.collections.Iterable[com.squareup.kotlinpoet.TypeVariableName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/add-type-variables.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/annotations/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/annotations.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/beginControlFlow/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/begin-control-flow.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/build/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/build.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/callSuperConstructor/#kotlin.Array[com.squareup.kotlinpoet.CodeBlock]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/call-super-constructor.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/callSuperConstructor/#kotlin.Array[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/call-super-constructor.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/callSuperConstructor/#kotlin.collections.Iterable[com.squareup.kotlinpoet.CodeBlock]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/call-super-constructor.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/callSuperConstructor/#kotlin.collections.List[com.squareup.kotlinpoet.CodeBlock]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/call-super-constructor.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/callThisConstructor/#kotlin.Array[com.squareup.kotlinpoet.CodeBlock]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/call-this-constructor.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/callThisConstructor/#kotlin.Array[kotlin.String]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/call-this-constructor.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/callThisConstructor/#kotlin.collections.Iterable[com.squareup.kotlinpoet.CodeBlock]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/call-this-constructor.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/callThisConstructor/#kotlin.collections.List[com.squareup.kotlinpoet.CodeBlock]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/call-this-constructor.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/clearBody/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/clear-body.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/contextReceiverTypes/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/context-receiver-types.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/contextReceivers/#kotlin.collections.Iterable[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/context-receivers.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/endControlFlow/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/end-control-flow.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/jvmModifiers/#kotlin.collections.Iterable[javax.lang.model.element.Modifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/jvm-modifiers.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/modifiers/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/modifiers.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/nextControlFlow/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/next-control-flow.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/originatingElements/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/originating-elements.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/parameters/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/parameters.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/receiver/#com.squareup.kotlinpoet.TypeName#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/receiver.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/receiver/#java.lang.reflect.Type#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/receiver.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/receiver/#java.lang.reflect.Type#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/receiver.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/receiver/#kotlin.reflect.KClass[*]#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/receiver.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/receiver/#kotlin.reflect.KClass[*]#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/receiver.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/returns/#com.squareup.kotlinpoet.TypeName#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/returns.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/returns/#java.lang.reflect.Type#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/returns.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/returns/#java.lang.reflect.Type#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/returns.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/returns/#kotlin.reflect.KClass[*]#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/returns.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/returns/#kotlin.reflect.KClass[*]#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/returns.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/tags/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/tags.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Builder/typeVariables/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-builder/type-variables.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Companion/builder/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Companion/constructorBuilder/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-companion/constructor-builder.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Companion/getterBuilder/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-companion/getter-builder.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Companion/overriding/#javax.lang.model.element.ExecutableElement/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-companion/overriding.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec.Companion/setterBuilder/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/-companion/setter-builder.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/index.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/annotations/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/annotations.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/body/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/body.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/delegateConstructor/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/delegate-constructor.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/delegateConstructorArguments/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/delegate-constructor-arguments.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/equals.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/isAccessor/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/is-accessor.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/isConstructor/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/is-constructor.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/kdoc/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/kdoc.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/modifiers/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/modifiers.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/name/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/name.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/parameters/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/parameters.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/receiverKdoc/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/receiver-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/receiverType/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/receiver-type.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/returnKdoc/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/return-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/returnType/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/return-type.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/toBuilder/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/to-builder.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/toString/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/to-string.html
+$dokka.location:com.squareup.kotlinpoet/FunSpec/typeVariables/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-fun-spec/type-variables.html
+$dokka.location:com.squareup.kotlinpoet/Import///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-import/index.html
+$dokka.location:com.squareup.kotlinpoet/Import/alias/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-import/alias.html
+$dokka.location:com.squareup.kotlinpoet/Import/compareTo/#com.squareup.kotlinpoet.Import/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-import/compare-to.html
+$dokka.location:com.squareup.kotlinpoet/Import/qualifiedName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-import/qualified-name.html
+$dokka.location:com.squareup.kotlinpoet/Import/toString/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-import/to-string.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.ABSTRACT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-a-b-s-t-r-a-c-t/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.ACTUAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-a-c-t-u-a-l/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.ANNOTATION///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-a-n-n-o-t-a-t-i-o-n/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.COMPANION///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-c-o-m-p-a-n-i-o-n/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.CONST///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-c-o-n-s-t/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.CROSSINLINE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-c-r-o-s-s-i-n-l-i-n-e/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.DATA///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-d-a-t-a/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.ENUM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-e-n-u-m/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.EXPECT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-e-x-p-e-c-t/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.EXTERNAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-e-x-t-e-r-n-a-l/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.FINAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-f-i-n-a-l/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.FUN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-f-u-n/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.IN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-i-n/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.INFIX///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-i-n-f-i-x/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.INLINE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-i-n-l-i-n-e/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.INNER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-i-n-n-e-r/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.INTERNAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-i-n-t-e-r-n-a-l/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.LATEINIT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-l-a-t-e-i-n-i-t/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.NOINLINE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-n-o-i-n-l-i-n-e/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.OPEN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-o-p-e-n/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.OPERATOR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-o-p-e-r-a-t-o-r/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.OUT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-o-u-t/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.OVERRIDE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-o-v-e-r-r-i-d-e/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.PRIVATE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-p-r-i-v-a-t-e/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.PROTECTED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-p-r-o-t-e-c-t-e-d/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.PUBLIC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-p-u-b-l-i-c/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.REIFIED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-r-e-i-f-i-e-d/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.SEALED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-s-e-a-l-e-d/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.SUSPEND///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-s-u-s-p-e-n-d/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.TAILREC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-t-a-i-l-r-e-c/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.VALUE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-v-a-l-u-e/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier.VARARG///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-modifier/-v-a-r-a-r-g/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-k-modifier/index.html
+$dokka.location:com.squareup.kotlinpoet/KModifier/valueOf/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-k-modifier/value-of.html
+$dokka.location:com.squareup.kotlinpoet/KModifier/values/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-k-modifier/values.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.CONTAINS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-c-o-n-t-a-i-n-s/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.DEC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-d-e-c/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.DIV///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-d-i-v/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.DIV_ASSIGN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-d-i-v_-a-s-s-i-g-n/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.EQUALS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-e-q-u-a-l-s/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.GE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-g-e/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.GT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-g-t/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.INC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-i-n-c/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.ITERATOR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-i-t-e-r-a-t-o-r/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.LE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-l-e/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.LT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-l-t/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.MINUS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-m-i-n-u-s/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.MINUS_ASSIGN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-m-i-n-u-s_-a-s-s-i-g-n/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.NOT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-n-o-t/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.NOT_CONTAINS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-n-o-t_-c-o-n-t-a-i-n-s/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.NOT_EQUALS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-n-o-t_-e-q-u-a-l-s/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.PLUS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-p-l-u-s/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.PLUS_ASSIGN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-p-l-u-s_-a-s-s-i-g-n/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.RANGE_TO///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-r-a-n-g-e_-t-o/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.REM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-r-e-m/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.REM_ASSIGN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-r-e-m_-a-s-s-i-g-n/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.TIMES///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-t-i-m-e-s/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.TIMES_ASSIGN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-t-i-m-e-s_-a-s-s-i-g-n/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.UNARY_MINUS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-u-n-a-r-y_-m-i-n-u-s/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator.UNARY_PLUS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-k-operator/-u-n-a-r-y_-p-l-u-s/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-k-operator/index.html
+$dokka.location:com.squareup.kotlinpoet/KOperator/valueOf/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-k-operator/value-of.html
+$dokka.location:com.squareup.kotlinpoet/KOperator/values/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-k-operator/values.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName.Companion/get/#com.squareup.kotlinpoet.TypeName?#kotlin.Array[com.squareup.kotlinpoet.ParameterSpec]#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/-companion/get.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName.Companion/get/#com.squareup.kotlinpoet.TypeName?#kotlin.Array[com.squareup.kotlinpoet.TypeName]#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/-companion/get.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName.Companion/get/#com.squareup.kotlinpoet.TypeName?#kotlin.collections.List[com.squareup.kotlinpoet.ParameterSpec]#com.squareup.kotlinpoet.TypeName#kotlin.collections.List[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/-companion/get.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName.Companion/get/#com.squareup.kotlinpoet.TypeName?#kotlin.collections.List[com.squareup.kotlinpoet.ParameterSpec]#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/-companion/get.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/index.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName/contextReceivers/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/context-receivers.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName/copy/#kotlin.Boolean#kotlin.collections.List[com.squareup.kotlinpoet.AnnotationSpec]#kotlin.Boolean#kotlin.collections.Map[kotlin.reflect.KClass[*],kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/copy.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName/copy/#kotlin.Boolean#kotlin.collections.List[com.squareup.kotlinpoet.AnnotationSpec]#kotlin.collections.Map[kotlin.reflect.KClass[*],kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/copy.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/equals.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName/isSuspending/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/is-suspending.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName/parameters/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/parameters.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName/receiver/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/receiver.html
+$dokka.location:com.squareup.kotlinpoet/LambdaTypeName/returnType/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-lambda-type-name/return-type.html
+$dokka.location:com.squareup.kotlinpoet/MemberName.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/MemberName.Companion/member/com.squareup.kotlinpoet.ClassName#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/-companion/member.html
+$dokka.location:com.squareup.kotlinpoet/MemberName.Companion/member/java.lang.Class[*]#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/-companion/member.html
+$dokka.location:com.squareup.kotlinpoet/MemberName.Companion/member/kotlin.reflect.KClass[*]#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/-companion/member.html
+$dokka.location:com.squareup.kotlinpoet/MemberName///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/index.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/MemberName/#com.squareup.kotlinpoet.ClassName#com.squareup.kotlinpoet.KOperator/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/-member-name.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/MemberName/#com.squareup.kotlinpoet.ClassName#kotlin.String#kotlin.Boolean/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/-member-name.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/MemberName/#com.squareup.kotlinpoet.ClassName#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/-member-name.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/MemberName/#kotlin.String#com.squareup.kotlinpoet.KOperator/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/-member-name.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/MemberName/#kotlin.String#kotlin.String#kotlin.Boolean/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/-member-name.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/MemberName/#kotlin.String#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/-member-name.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/canonicalName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/canonical-name.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/enclosingClassName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/enclosing-class-name.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/isExtension/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/is-extension.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/operator/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/operator.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/packageName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/package-name.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/reference/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/reference.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/simpleName/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/simple-name.html
+$dokka.location:com.squareup.kotlinpoet/MemberName/toString/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-member-name/to-string.html
+$dokka.location:com.squareup.kotlinpoet/NameAllocator///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-name-allocator/index.html
+$dokka.location:com.squareup.kotlinpoet/NameAllocator/NameAllocator/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-name-allocator/-name-allocator.html
+$dokka.location:com.squareup.kotlinpoet/NameAllocator/copy/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-name-allocator/copy.html
+$dokka.location:com.squareup.kotlinpoet/NameAllocator/get/#kotlin.Any/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-name-allocator/get.html
+$dokka.location:com.squareup.kotlinpoet/NameAllocator/newName/#kotlin.String#kotlin.Any/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-name-allocator/new-name.html
+$dokka.location:com.squareup.kotlinpoet/OriginatingElementsHolder.Builder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-originating-elements-holder/-builder/index.html
+$dokka.location:com.squareup.kotlinpoet/OriginatingElementsHolder.Builder/addOriginatingElement/#javax.lang.model.element.Element/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-originating-elements-holder/-builder/add-originating-element.html
+$dokka.location:com.squareup.kotlinpoet/OriginatingElementsHolder.Builder/originatingElements/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-originating-elements-holder/-builder/originating-elements.html
+$dokka.location:com.squareup.kotlinpoet/OriginatingElementsHolder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-originating-elements-holder/index.html
+$dokka.location:com.squareup.kotlinpoet/OriginatingElementsHolder/originatingElements/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-originating-elements-holder/originating-elements.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/index.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/addAnnotation/#com.squareup.kotlinpoet.AnnotationSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/addAnnotation/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/addAnnotation/#java.lang.Class[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/addAnnotation/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/addAnnotations/#kotlin.collections.Iterable[com.squareup.kotlinpoet.AnnotationSpec]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/add-annotations.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/addKdoc/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/add-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/addKdoc/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/add-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/addModifiers/#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/add-modifiers.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/addModifiers/#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/add-modifiers.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/annotations/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/annotations.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/build/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/build.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/defaultValue/#com.squareup.kotlinpoet.CodeBlock?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/default-value.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/defaultValue/#kotlin.String#kotlin.Array[kotlin.Any?]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/default-value.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/kdoc/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/kdoc.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/modifiers/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/modifiers.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Builder/tags/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-builder/tags.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion/builder/#kotlin.String#com.squareup.kotlinpoet.TypeName#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion/builder/#kotlin.String#com.squareup.kotlinpoet.TypeName#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion/builder/#kotlin.String#java.lang.reflect.Type#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion/builder/#kotlin.String#java.lang.reflect.Type#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion/builder/#kotlin.String#kotlin.reflect.KClass[*]#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion/builder/#kotlin.String#kotlin.reflect.KClass[*]#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion/get/#javax.lang.model.element.VariableElement/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/get.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion/parametersOf/#javax.lang.model.element.ExecutableElement/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/parameters-of.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion/unnamed/#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/unnamed.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion/unnamed/#java.lang.reflect.Type/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/unnamed.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec.Companion/unnamed/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-companion/unnamed.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/index.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/ParameterSpec/#kotlin.String#com.squareup.kotlinpoet.TypeName#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-parameter-spec.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/ParameterSpec/#kotlin.String#com.squareup.kotlinpoet.TypeName#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/-parameter-spec.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/annotations/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/annotations.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/defaultValue/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/default-value.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/equals.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/kdoc/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/kdoc.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/modifiers/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/modifiers.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/name/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/name.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/toBuilder/#kotlin.String#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/to-builder.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/toString/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/to-string.html
+$dokka.location:com.squareup.kotlinpoet/ParameterSpec/type/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameter-spec/type.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName.Companion/parameterizedBy/com.squareup.kotlinpoet.ClassName#kotlin.Array[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/-companion/parameterized-by.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName.Companion/parameterizedBy/com.squareup.kotlinpoet.ClassName#kotlin.collections.List[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/-companion/parameterized-by.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName.Companion/parameterizedBy/java.lang.Class[*]#kotlin.Array[java.lang.reflect.Type]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/-companion/parameterized-by.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName.Companion/parameterizedBy/java.lang.Class[*]#kotlin.collections.Iterable[java.lang.reflect.Type]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/-companion/parameterized-by.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName.Companion/parameterizedBy/kotlin.reflect.KClass[*]#kotlin.Array[kotlin.reflect.KClass[*]]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/-companion/parameterized-by.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName.Companion/parameterizedBy/kotlin.reflect.KClass[*]#kotlin.collections.Iterable[kotlin.reflect.KClass[*]]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/-companion/parameterized-by.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName.Companion/plusParameter/com.squareup.kotlinpoet.ClassName#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/-companion/plus-parameter.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName.Companion/plusParameter/java.lang.Class[*]#java.lang.Class[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/-companion/plus-parameter.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName.Companion/plusParameter/kotlin.reflect.KClass[*]#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/-companion/plus-parameter.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/index.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName/copy/#kotlin.Boolean#kotlin.collections.List[com.squareup.kotlinpoet.AnnotationSpec]#kotlin.collections.Map[kotlin.reflect.KClass[*],kotlin.Any]#kotlin.collections.List[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/copy.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName/copy/#kotlin.Boolean#kotlin.collections.List[com.squareup.kotlinpoet.AnnotationSpec]#kotlin.collections.Map[kotlin.reflect.KClass[*],kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/copy.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/equals.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName/nestedClass/#kotlin.String#kotlin.collections.List[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/nested-class.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName/plusParameter/#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/plus-parameter.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName/plusParameter/#java.lang.Class[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/plus-parameter.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName/plusParameter/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/plus-parameter.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName/rawType/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/raw-type.html
+$dokka.location:com.squareup.kotlinpoet/ParameterizedTypeName/typeArguments/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-parameterized-type-name/type-arguments.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/index.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/addAnnotation/#com.squareup.kotlinpoet.AnnotationSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/addAnnotation/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/addAnnotation/#java.lang.Class[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/addAnnotation/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/addAnnotations/#kotlin.collections.Iterable[com.squareup.kotlinpoet.AnnotationSpec]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/add-annotations.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/addKdoc/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/add-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/addKdoc/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/add-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/addModifiers/#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/add-modifiers.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/addModifiers/#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/add-modifiers.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/addTypeVariable/#com.squareup.kotlinpoet.TypeVariableName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/add-type-variable.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/addTypeVariables/#kotlin.collections.Iterable[com.squareup.kotlinpoet.TypeVariableName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/add-type-variables.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/annotations/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/annotations.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/build/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/build.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/contextReceiverTypes/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/context-receiver-types.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/delegate/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/delegate.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/delegate/#kotlin.String#kotlin.Array[kotlin.Any?]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/delegate.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/getter/#com.squareup.kotlinpoet.FunSpec?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/getter.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/initializer/#com.squareup.kotlinpoet.CodeBlock?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/initializer.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/initializer/#kotlin.String#kotlin.Array[kotlin.Any?]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/initializer.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/modifiers/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/modifiers.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/mutable/#kotlin.Boolean/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/mutable.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/originatingElements/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/originating-elements.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/receiver/#com.squareup.kotlinpoet.TypeName?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/receiver.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/receiver/#java.lang.reflect.Type/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/receiver.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/receiver/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/receiver.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/setter/#com.squareup.kotlinpoet.FunSpec?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/setter.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/tags/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/tags.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Builder/typeVariables/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-builder/type-variables.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Companion/builder/#kotlin.String#com.squareup.kotlinpoet.TypeName#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Companion/builder/#kotlin.String#com.squareup.kotlinpoet.TypeName#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Companion/builder/#kotlin.String#java.lang.reflect.Type#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Companion/builder/#kotlin.String#java.lang.reflect.Type#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Companion/builder/#kotlin.String#kotlin.reflect.KClass[*]#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec.Companion/builder/#kotlin.String#kotlin.reflect.KClass[*]#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/index.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/annotations/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/annotations.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/delegated/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/delegated.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/equals.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/getter/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/getter.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/initializer/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/initializer.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/kdoc/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/kdoc.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/modifiers/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/modifiers.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/mutable/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/mutable.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/name/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/name.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/receiverType/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/receiver-type.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/setter/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/setter.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/toBuilder/#kotlin.String#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/to-builder.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/toString/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/to-string.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/type/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/type.html
+$dokka.location:com.squareup.kotlinpoet/PropertySpec/typeVariables/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-property-spec/type-variables.html
+$dokka.location:com.squareup.kotlinpoet/Taggable.Builder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-taggable/-builder/index.html
+$dokka.location:com.squareup.kotlinpoet/Taggable.Builder/tag/#java.lang.Class[*]#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-taggable/-builder/tag.html
+$dokka.location:com.squareup.kotlinpoet/Taggable.Builder/tag/#kotlin.reflect.KClass[*]#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-taggable/-builder/tag.html
+$dokka.location:com.squareup.kotlinpoet/Taggable.Builder/tags/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-taggable/-builder/tags.html
+$dokka.location:com.squareup.kotlinpoet/Taggable///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-taggable/index.html
+$dokka.location:com.squareup.kotlinpoet/Taggable/tag/#java.lang.Class[TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-taggable/tag.html
+$dokka.location:com.squareup.kotlinpoet/Taggable/tag/#kotlin.reflect.KClass[TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-taggable/tag.html
+$dokka.location:com.squareup.kotlinpoet/Taggable/tags/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-taggable/tags.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/addAnnotation/#com.squareup.kotlinpoet.AnnotationSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/addAnnotation/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/addAnnotation/#java.lang.Class[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/addAnnotation/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/addAnnotations/#kotlin.collections.Iterable[com.squareup.kotlinpoet.AnnotationSpec]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/add-annotations.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/addKdoc/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/add-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/addKdoc/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/add-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/addModifiers/#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/add-modifiers.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/addModifiers/#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/add-modifiers.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/addTypeVariable/#com.squareup.kotlinpoet.TypeVariableName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/add-type-variable.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/addTypeVariables/#kotlin.collections.Iterable[com.squareup.kotlinpoet.TypeVariableName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/add-type-variables.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/annotations/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/annotations.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/build/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/build.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/modifiers/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/modifiers.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/tags/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/tags.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Builder/typeVariables/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-builder/type-variables.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Companion/builder/#kotlin.String#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Companion/builder/#kotlin.String#java.lang.reflect.Type/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec.Companion/builder/#kotlin.String#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/-companion/builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec/annotations/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/annotations.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/equals.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec/kdoc/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/kdoc.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec/modifiers/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/modifiers.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec/name/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/name.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec/toBuilder/#kotlin.String#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/to-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec/toString/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/to-string.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec/type/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/type.html
+$dokka.location:com.squareup.kotlinpoet/TypeAliasSpec/typeVariables/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-alias-spec/type-variables.html
+$dokka.location:com.squareup.kotlinpoet/TypeName.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-name/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeName///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-name/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeName/annotations/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-name/annotations.html
+$dokka.location:com.squareup.kotlinpoet/TypeName/copy/#kotlin.Boolean#kotlin.collections.List[com.squareup.kotlinpoet.AnnotationSpec]#kotlin.collections.Map[kotlin.reflect.KClass[*],kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-name/copy.html
+$dokka.location:com.squareup.kotlinpoet/TypeName/copy/#kotlin.Boolean#kotlin.collections.List[com.squareup.kotlinpoet.AnnotationSpec]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-name/copy.html
+$dokka.location:com.squareup.kotlinpoet/TypeName/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-name/equals.html
+$dokka.location:com.squareup.kotlinpoet/TypeName/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-name/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/TypeName/isAnnotated/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-name/is-annotated.html
+$dokka.location:com.squareup.kotlinpoet/TypeName/isNullable/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-name/is-nullable.html
+$dokka.location:com.squareup.kotlinpoet/TypeName/toString/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-name/to-string.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addAnnotation/#com.squareup.kotlinpoet.AnnotationSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addAnnotation/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addAnnotation/#java.lang.Class[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addAnnotation/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-annotation.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addAnnotations/#kotlin.collections.Iterable[com.squareup.kotlinpoet.AnnotationSpec]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-annotations.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addEnumConstant/#kotlin.String#com.squareup.kotlinpoet.TypeSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-enum-constant.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addFunction/#com.squareup.kotlinpoet.FunSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-function.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addFunctions/#kotlin.collections.Iterable[com.squareup.kotlinpoet.FunSpec]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-functions.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addInitializerBlock/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-initializer-block.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addKdoc/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addKdoc/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-kdoc.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addModifiers/#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-modifiers.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addModifiers/#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-modifiers.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addProperties/#kotlin.collections.Iterable[com.squareup.kotlinpoet.PropertySpec]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-properties.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addProperty/#com.squareup.kotlinpoet.PropertySpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-property.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addProperty/#kotlin.String#com.squareup.kotlinpoet.TypeName#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-property.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addProperty/#kotlin.String#com.squareup.kotlinpoet.TypeName#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-property.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addProperty/#kotlin.String#java.lang.reflect.Type#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-property.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addProperty/#kotlin.String#java.lang.reflect.Type#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-property.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addProperty/#kotlin.String#kotlin.reflect.KClass[*]#kotlin.Array[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-property.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addProperty/#kotlin.String#kotlin.reflect.KClass[*]#kotlin.collections.Iterable[com.squareup.kotlinpoet.KModifier]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-property.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addSuperclassConstructorParameter/#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-superclass-constructor-parameter.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addSuperclassConstructorParameter/#kotlin.String#kotlin.Array[kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-superclass-constructor-parameter.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addSuperinterface/#com.squareup.kotlinpoet.TypeName#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-superinterface.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addSuperinterface/#com.squareup.kotlinpoet.TypeName#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-superinterface.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addSuperinterface/#java.lang.reflect.Type#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-superinterface.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addSuperinterface/#kotlin.reflect.KClass[*]#com.squareup.kotlinpoet.CodeBlock/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-superinterface.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addSuperinterface/#kotlin.reflect.KClass[*]#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-superinterface.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addSuperinterfaces/#kotlin.collections.Iterable[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-superinterfaces.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addType/#com.squareup.kotlinpoet.TypeSpec/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-type.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addTypeVariable/#com.squareup.kotlinpoet.TypeVariableName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-type-variable.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addTypeVariables/#kotlin.collections.Iterable[com.squareup.kotlinpoet.TypeVariableName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-type-variables.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/addTypes/#kotlin.collections.Iterable[com.squareup.kotlinpoet.TypeSpec]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/add-types.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/annotationSpecs/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/annotation-specs.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/build/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/build.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/contextReceiverTypes/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/context-receiver-types.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/contextReceivers/#kotlin.collections.Iterable[com.squareup.kotlinpoet.TypeName]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/context-receivers.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/enumConstants/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/enum-constants.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/funSpecs/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/fun-specs.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/initializerIndex/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/initializer-index.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/modifiers/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/modifiers.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/originatingElements/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/originating-elements.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/primaryConstructor/#com.squareup.kotlinpoet.FunSpec?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/primary-constructor.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/propertySpecs/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/property-specs.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/superclass/#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/superclass.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/superclass/#java.lang.reflect.Type/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/superclass.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/superclass/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/superclass.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/superclassConstructorParameters/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/superclass-constructor-parameters.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/superinterfaces/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/superinterfaces.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/tags/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/tags.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/typeSpecs/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/type-specs.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Builder/typeVariables/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-builder/type-variables.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/annotationBuilder/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/annotation-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/annotationBuilder/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/annotation-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/anonymousClassBuilder/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/anonymous-class-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/classBuilder/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/class-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/classBuilder/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/class-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/companionObjectBuilder/#kotlin.String?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/companion-object-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/enumBuilder/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/enum-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/enumBuilder/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/enum-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/expectClassBuilder/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/expect-class-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/expectClassBuilder/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/expect-class-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/funInterfaceBuilder/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/fun-interface-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/funInterfaceBuilder/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/fun-interface-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/interfaceBuilder/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/interface-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/interfaceBuilder/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/interface-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/objectBuilder/#com.squareup.kotlinpoet.ClassName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/object-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/objectBuilder/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/object-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Companion/valueClassBuilder/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-companion/value-class-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Kind.CLASS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-type-spec/-kind/-c-l-a-s-s/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Kind.INTERFACE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-type-spec/-kind/-i-n-t-e-r-f-a-c-e/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Kind.OBJECT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}kotlinpoet/com.squareup.kotlinpoet/-type-spec/-kind/-o-b-j-e-c-t/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Kind///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-kind/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Kind/valueOf/#kotlin.String/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-kind/value-of.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec.Kind/values/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/-kind/values.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/annotationSpecs/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/annotation-specs.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/enumConstants/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/enum-constants.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/equals.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/funSpecs/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/fun-specs.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/initializerBlock/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/initializer-block.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/initializerIndex/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/initializer-index.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/isAnnotation/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/is-annotation.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/isAnonymousClass/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/is-anonymous-class.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/isCompanion/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/is-companion.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/isEnum/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/is-enum.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/isFunctionalInterface/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/is-functional-interface.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/kdoc/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/kdoc.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/kind/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/kind.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/modifiers/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/modifiers.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/name/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/name.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/primaryConstructor/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/primary-constructor.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/propertySpecs/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/property-specs.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/superclass/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/superclass.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/superclassConstructorParameters/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/superclass-constructor-parameters.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/superinterfaces/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/superinterfaces.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/toBuilder/#com.squareup.kotlinpoet.TypeSpec.Kind#kotlin.String?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/to-builder.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/toString/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/to-string.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/typeSpecs/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/type-specs.html
+$dokka.location:com.squareup.kotlinpoet/TypeSpec/typeVariables/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-spec/type-variables.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName.Companion/invoke/#kotlin.String#com.squareup.kotlinpoet.KModifier?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/-companion/invoke.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName.Companion/invoke/#kotlin.String#kotlin.Array[com.squareup.kotlinpoet.TypeName]#com.squareup.kotlinpoet.KModifier?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/-companion/invoke.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName.Companion/invoke/#kotlin.String#kotlin.Array[java.lang.reflect.Type]#com.squareup.kotlinpoet.KModifier?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/-companion/invoke.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName.Companion/invoke/#kotlin.String#kotlin.Array[kotlin.reflect.KClass[*]]#com.squareup.kotlinpoet.KModifier?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/-companion/invoke.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName.Companion/invoke/#kotlin.String#kotlin.collections.Iterable[java.lang.reflect.Type]#com.squareup.kotlinpoet.KModifier?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/-companion/invoke.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName.Companion/invoke/#kotlin.String#kotlin.collections.Iterable[kotlin.reflect.KClass[*]]#com.squareup.kotlinpoet.KModifier?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/-companion/invoke.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName.Companion/invoke/#kotlin.String#kotlin.collections.List[com.squareup.kotlinpoet.TypeName]#com.squareup.kotlinpoet.KModifier?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/-companion/invoke.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/index.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName/bounds/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/bounds.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName/copy/#kotlin.Boolean#kotlin.collections.List[com.squareup.kotlinpoet.AnnotationSpec]#kotlin.collections.List[com.squareup.kotlinpoet.TypeName]#kotlin.Boolean#kotlin.collections.Map[kotlin.reflect.KClass[*],kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/copy.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName/copy/#kotlin.Boolean#kotlin.collections.List[com.squareup.kotlinpoet.AnnotationSpec]#kotlin.collections.Map[kotlin.reflect.KClass[*],kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/copy.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/equals.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName/isReified/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/is-reified.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName/name/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/name.html
+$dokka.location:com.squareup.kotlinpoet/TypeVariableName/variance/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-type-variable-name/variance.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName.Companion///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/-companion/index.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName.Companion/consumerOf/#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/-companion/consumer-of.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName.Companion/consumerOf/#java.lang.reflect.Type/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/-companion/consumer-of.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName.Companion/consumerOf/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/-companion/consumer-of.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName.Companion/producerOf/#com.squareup.kotlinpoet.TypeName/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/-companion/producer-of.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName.Companion/producerOf/#java.lang.reflect.Type/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/-companion/producer-of.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName.Companion/producerOf/#kotlin.reflect.KClass[*]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/-companion/producer-of.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName///PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/index.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName/copy/#kotlin.Boolean#kotlin.collections.List[com.squareup.kotlinpoet.AnnotationSpec]#kotlin.collections.Map[kotlin.reflect.KClass[*],kotlin.Any]/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/copy.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName/equals/#kotlin.Any?/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/equals.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName/hashCode/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/hash-code.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName/inTypes/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/in-types.html
+$dokka.location:com.squareup.kotlinpoet/WildcardTypeName/outTypes/#/PointingToDeclaration/kotlinpoet/com.squareup.kotlinpoet/-wildcard-type-name/out-types.html
+com.squareup.kotlinpoet
+com.squareup.kotlinpoet.jvm
+com.squareup.kotlinpoet.tags
diff --git a/docs-public/package-lists/material/package-list b/docs-public/package-lists/material/package-list
new file mode 100644
index 0000000..967af3a
--- /dev/null
+++ b/docs-public/package-lists/material/package-list
@@ -0,0 +1,51 @@
+$dokka.format:javadoc1
+com.google.android.material.animation
+com.google.android.material.appbar
+com.google.android.material.badge
+com.google.android.material.behavior
+com.google.android.material.bottomappbar
+com.google.android.material.bottomnavigation
+com.google.android.material.bottomsheet
+com.google.android.material.button
+com.google.android.material.card
+com.google.android.material.carousel
+com.google.android.material.checkbox
+com.google.android.material.chip
+com.google.android.material.circularreveal
+com.google.android.material.circularreveal.cardview
+com.google.android.material.circularreveal.coordinatorlayout
+com.google.android.material.color
+com.google.android.material.datepicker
+com.google.android.material.dialog
+com.google.android.material.divider
+com.google.android.material.elevation
+com.google.android.material.expandable
+com.google.android.material.floatingactionbutton
+com.google.android.material.imageview
+com.google.android.material.lists
+com.google.android.material.materialswitch
+com.google.android.material.math
+com.google.android.material.motion
+com.google.android.material.navigation
+com.google.android.material.navigationrail
+com.google.android.material.progressindicator
+com.google.android.material.radiobutton
+com.google.android.material.resources
+com.google.android.material.ripple
+com.google.android.material.search
+com.google.android.material.shadow
+com.google.android.material.shape
+com.google.android.material.sidesheet
+com.google.android.material.slider
+com.google.android.material.snackbar
+com.google.android.material.stateful
+com.google.android.material.switchmaterial
+com.google.android.material.tabs
+com.google.android.material.textfield
+com.google.android.material.textview
+com.google.android.material.theme
+com.google.android.material.theme.overlay
+com.google.android.material.timepicker
+com.google.android.material.transformation
+com.google.android.material.transition
+com.google.android.material.transition.platform
diff --git a/docs-public/package-lists/mlkit/package-list b/docs-public/package-lists/mlkit/package-list
new file mode 100644
index 0000000..b147f59
--- /dev/null
+++ b/docs-public/package-lists/mlkit/package-list
@@ -0,0 +1,37 @@
+$dokka.format:javadoc1
+com.google.mlkit
+com.google.mlkit.common
+com.google.mlkit.common.model
+com.google.mlkit.linkfirebase
+com.google.mlkit.nl
+com.google.mlkit.nl.entityextraction
+com.google.mlkit.nl.languageid
+com.google.mlkit.nl.smartreply
+com.google.mlkit.nl.translate
+com.google.mlkit.vision
+com.google.mlkit.vision.barcode
+com.google.mlkit.vision.barcode.common
+com.google.mlkit.vision.camera
+com.google.mlkit.vision.codescanner
+com.google.mlkit.vision.common
+com.google.mlkit.vision.digitalink
+com.google.mlkit.vision.face
+com.google.mlkit.vision.facemesh
+com.google.mlkit.vision.interfaces
+com.google.mlkit.vision.label
+com.google.mlkit.vision.label.custom
+com.google.mlkit.vision.label.defaults
+com.google.mlkit.vision.objects
+com.google.mlkit.vision.objects.custom
+com.google.mlkit.vision.objects.defaults
+com.google.mlkit.vision.pose
+com.google.mlkit.vision.pose.accurate
+com.google.mlkit.vision.pose.defaults
+com.google.mlkit.vision.segmentation
+com.google.mlkit.vision.segmentation.selfie
+com.google.mlkit.vision.text
+com.google.mlkit.vision.text.chinese
+com.google.mlkit.vision.text.devanagari
+com.google.mlkit.vision.text.japanese
+com.google.mlkit.vision.text.korean
+com.google.mlkit.vision.text.latin
diff --git a/docs-public/package-lists/play/package-list b/docs-public/package-lists/play/package-list
new file mode 100644
index 0000000..f6b2b0e
--- /dev/null
+++ b/docs-public/package-lists/play/package-list
@@ -0,0 +1,18 @@
+$dokka.format:javadoc1
+com.google.android.play.core.appupdate
+com.google.android.play.core.appupdate.testing
+com.google.android.play.core.assetpacks
+com.google.android.play.core.assetpacks.model
+com.google.android.play.core.common
+com.google.android.play.core.install
+com.google.android.play.core.install.model
+com.google.android.play.core.listener
+com.google.android.play.core.missingsplits
+com.google.android.play.core.review
+com.google.android.play.core.review.model
+com.google.android.play.core.review.testing
+com.google.android.play.core.splitcompat
+com.google.android.play.core.splitinstall
+com.google.android.play.core.splitinstall.model
+com.google.android.play.core.splitinstall.testing
+com.google.android.play.core.tasks
diff --git a/docs-public/package-lists/protobuf/package-list b/docs-public/package-lists/protobuf/package-list
new file mode 100644
index 0000000..9cf5273
--- /dev/null
+++ b/docs-public/package-lists/protobuf/package-list
@@ -0,0 +1,4 @@
+$dokka.format:javadoc1
+com.google.protobuf
+com.google.protobuf.compiler
+com.google.protobuf.util
diff --git a/docs-public/package-lists/reactivestreams/package-list b/docs-public/package-lists/reactivestreams/package-list
new file mode 100644
index 0000000..5519daa
--- /dev/null
+++ b/docs-public/package-lists/reactivestreams/package-list
@@ -0,0 +1,2 @@
+$dokka.format:javadoc1
+org.reactivestreams
diff --git a/docs-public/package-lists/reactivex-rxjava3/package-list b/docs-public/package-lists/reactivex-rxjava3/package-list
new file mode 100644
index 0000000..4d5ce83
--- /dev/null
+++ b/docs-public/package-lists/reactivex-rxjava3/package-list
@@ -0,0 +1,15 @@
+io.reactivex.rxjava3.annotations
+io.reactivex.rxjava3.core
+io.reactivex.rxjava3.disposables
+io.reactivex.rxjava3.exceptions
+io.reactivex.rxjava3.flowables
+io.reactivex.rxjava3.functions
+io.reactivex.rxjava3.observables
+io.reactivex.rxjava3.observers
+io.reactivex.rxjava3.operators
+io.reactivex.rxjava3.parallel
+io.reactivex.rxjava3.plugins
+io.reactivex.rxjava3.processors
+io.reactivex.rxjava3.schedulers
+io.reactivex.rxjava3.subjects
+io.reactivex.rxjava3.subscribers
diff --git a/docs-public/package-lists/reactivex/package-list b/docs-public/package-lists/reactivex/package-list
new file mode 100644
index 0000000..5be2c9e
--- /dev/null
+++ b/docs-public/package-lists/reactivex/package-list
@@ -0,0 +1,14 @@
+io.reactivex
+io.reactivex.annotations
+io.reactivex.disposables
+io.reactivex.exceptions
+io.reactivex.flowables
+io.reactivex.functions
+io.reactivex.observables
+io.reactivex.observers
+io.reactivex.parallel
+io.reactivex.plugins
+io.reactivex.processors
+io.reactivex.schedulers
+io.reactivex.subjects
+io.reactivex.subscribers
diff --git a/docs-public/package-lists/skiko/package-list b/docs-public/package-lists/skiko/package-list
new file mode 100644
index 0000000..168dcf6
--- /dev/null
+++ b/docs-public/package-lists/skiko/package-list
@@ -0,0 +1,3215 @@
+$dokka.format:html-v1
+$dokka.linkExtension:html
+$dokka.location:org.jetbrains.skia.icu////PointingToDeclaration/skiko/org.jetbrains.skia.icu/index.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection///PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/index.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/ARABIC_NUMBER/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-a-r-a-b-i-c_-n-u-m-b-e-r.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/BLOCK_SEPARATOR/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-b-l-o-c-k_-s-e-p-a-r-a-t-o-r.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/BOUNDARY_NEUTRAL/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-b-o-u-n-d-a-r-y_-n-e-u-t-r-a-l.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/COMMON_NUMBER_SEPARATOR/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-c-o-m-m-o-n_-n-u-m-b-e-r_-s-e-p-a-r-a-t-o-r.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/DIR_NON_SPACING_MARK/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-d-i-r_-n-o-n_-s-p-a-c-i-n-g_-m-a-r-k.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/EUROPEAN_NUMBER/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-e-u-r-o-p-e-a-n_-n-u-m-b-e-r.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/EUROPEAN_NUMBER_SEPARATOR/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-e-u-r-o-p-e-a-n_-n-u-m-b-e-r_-s-e-p-a-r-a-t-o-r.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/EUROPEAN_NUMBER_TERMINATOR/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-e-u-r-o-p-e-a-n_-n-u-m-b-e-r_-t-e-r-m-i-n-a-t-o-r.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/FIRST_STRONG_ISOLATE/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-f-i-r-s-t_-s-t-r-o-n-g_-i-s-o-l-a-t-e.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/LEFT_TO_RIGHT/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-l-e-f-t_-t-o_-r-i-g-h-t.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/LEFT_TO_RIGHT_EMBEDDING/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-l-e-f-t_-t-o_-r-i-g-h-t_-e-m-b-e-d-d-i-n-g.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/LEFT_TO_RIGHT_ISOLATE/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-l-e-f-t_-t-o_-r-i-g-h-t_-i-s-o-l-a-t-e.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/LEFT_TO_RIGHT_OVERRIDE/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-l-e-f-t_-t-o_-r-i-g-h-t_-o-v-e-r-r-i-d-e.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/OTHER_NEUTRAL/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-o-t-h-e-r_-n-e-u-t-r-a-l.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/POP_DIRECTIONAL_FORMAT/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-p-o-p_-d-i-r-e-c-t-i-o-n-a-l_-f-o-r-m-a-t.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/POP_DIRECTIONAL_ISOLATE/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-p-o-p_-d-i-r-e-c-t-i-o-n-a-l_-i-s-o-l-a-t-e.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/RIGHT_TO_LEFT/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-r-i-g-h-t_-t-o_-l-e-f-t.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/RIGHT_TO_LEFT_ARABIC/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-r-i-g-h-t_-t-o_-l-e-f-t_-a-r-a-b-i-c.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/RIGHT_TO_LEFT_EMBEDDING/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-r-i-g-h-t_-t-o_-l-e-f-t_-e-m-b-e-d-d-i-n-g.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/RIGHT_TO_LEFT_ISOLATE/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-r-i-g-h-t_-t-o_-l-e-f-t_-i-s-o-l-a-t-e.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/RIGHT_TO_LEFT_OVERRIDE/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-r-i-g-h-t_-t-o_-l-e-f-t_-o-v-e-r-r-i-d-e.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/SEGMENT_SEPARATOR/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-s-e-g-m-e-n-t_-s-e-p-a-r-a-t-o-r.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/WHITE_SPACE_NEUTRAL/#/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/-w-h-i-t-e_-s-p-a-c-e_-n-e-u-t-r-a-l.html
+$dokka.location:org.jetbrains.skia.icu/CharDirection/of/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.icu/-char-direction/of.html
+$dokka.location:org.jetbrains.skia.impl////PointingToDeclaration/skiko/org.jetbrains.skia.impl/index.html
+$dokka.location:org.jetbrains.skia.impl//use/TypeParam(bounds=[org.jetbrains.skia.impl.Managed])#kotlin.Function1[TypeParam(bounds=[org.jetbrains.skia.impl.Managed]),TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/skiko/org.jetbrains.skia.impl/use.html
+$dokka.location:org.jetbrains.skia.impl/BufferUtil///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-buffer-util/index.html
+$dokka.location:org.jetbrains.skia.impl/BufferUtil/getByteBufferFromPointer/#kotlin.Long#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-buffer-util/get-byte-buffer-from-pointer.html
+$dokka.location:org.jetbrains.skia.impl/BufferUtil/getPointerFromByteBuffer/#java.nio.ByteBuffer/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-buffer-util/get-pointer-from-byte-buffer.html
+$dokka.location:org.jetbrains.skia.impl/InteropPointer///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-interop-pointer/index.html
+$dokka.location:org.jetbrains.skia.impl/Library.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-library/-companion/index.html
+$dokka.location:org.jetbrains.skia.impl/Library.Companion/_nAfterLoad/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-library/-companion/_n-after-load.html
+$dokka.location:org.jetbrains.skia.impl/Library.Companion/loaded/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-library/-companion/loaded.html
+$dokka.location:org.jetbrains.skia.impl/Library.Companion/staticLoad/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-library/-companion/static-load.html
+$dokka.location:org.jetbrains.skia.impl/Library///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-library/index.html
+$dokka.location:org.jetbrains.skia.impl/Library/Library/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-library/-library.html
+$dokka.location:org.jetbrains.skia.impl/Log///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/index.html
+$dokka.location:org.jetbrains.skia.impl/Log/_log/#kotlin.Int#kotlin.String#java.util.function.Supplier[kotlin.String]/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/_log.html
+$dokka.location:org.jetbrains.skia.impl/Log/_log/#kotlin.Int#kotlin.String#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/_log.html
+$dokka.location:org.jetbrains.skia.impl/Log/_time/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/_time.html
+$dokka.location:org.jetbrains.skia.impl/Log/debug/#java.util.function.Supplier[kotlin.String]/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/debug.html
+$dokka.location:org.jetbrains.skia.impl/Log/debug/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/debug.html
+$dokka.location:org.jetbrains.skia.impl/Log/error/#java.util.function.Supplier[kotlin.String]/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/error.html
+$dokka.location:org.jetbrains.skia.impl/Log/error/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/error.html
+$dokka.location:org.jetbrains.skia.impl/Log/info/#java.util.function.Supplier[kotlin.String]/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/info.html
+$dokka.location:org.jetbrains.skia.impl/Log/info/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/info.html
+$dokka.location:org.jetbrains.skia.impl/Log/trace/#java.util.function.Supplier[kotlin.String]/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/trace.html
+$dokka.location:org.jetbrains.skia.impl/Log/trace/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/trace.html
+$dokka.location:org.jetbrains.skia.impl/Log/warn/#java.util.function.Supplier[kotlin.String]/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/warn.html
+$dokka.location:org.jetbrains.skia.impl/Log/warn/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-log/warn.html
+$dokka.location:org.jetbrains.skia.impl/Managed.CleanerThunk///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/-cleaner-thunk/index.html
+$dokka.location:org.jetbrains.skia.impl/Managed.CleanerThunk/CleanerThunk/#kotlin.String#kotlin.Long#kotlin.Long/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/-cleaner-thunk/-cleaner-thunk.html
+$dokka.location:org.jetbrains.skia.impl/Managed.CleanerThunk/className/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/-cleaner-thunk/class-name.html
+$dokka.location:org.jetbrains.skia.impl/Managed.CleanerThunk/finalizerPtr/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/-cleaner-thunk/finalizer-ptr.html
+$dokka.location:org.jetbrains.skia.impl/Managed.CleanerThunk/ptr/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/-cleaner-thunk/ptr.html
+$dokka.location:org.jetbrains.skia.impl/Managed.CleanerThunk/run/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/-cleaner-thunk/run.html
+$dokka.location:org.jetbrains.skia.impl/Managed.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/-companion/index.html
+$dokka.location:org.jetbrains.skia.impl/Managed.Companion/_nInvokeFinalizer/#kotlin.Long#kotlin.Long/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/-companion/_n-invoke-finalizer.html
+$dokka.location:org.jetbrains.skia.impl/Managed///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/index.html
+$dokka.location:org.jetbrains.skia.impl/Managed/Managed/#org.jetbrains.skia.impl.NativePointer#org.jetbrains.skia.impl.NativePointer#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/-managed.html
+$dokka.location:org.jetbrains.skia.impl/Managed/close/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/close.html
+$dokka.location:org.jetbrains.skia.impl/Managed/isClosed/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-managed/is-closed.html
+$dokka.location:org.jetbrains.skia.impl/Native.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native/-companion/index.html
+$dokka.location:org.jetbrains.skia.impl/Native.Companion/NullPointer/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native/-companion/-null-pointer.html
+$dokka.location:org.jetbrains.skia.impl/Native///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native/index.html
+$dokka.location:org.jetbrains.skia.impl/Native/Native/#org.jetbrains.skia.impl.NativePointer/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native/-native.html
+$dokka.location:org.jetbrains.skia.impl/Native/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native/[native]equals.html
+$dokka.location:org.jetbrains.skia.impl/Native/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native/[native]hash-code.html
+$dokka.location:org.jetbrains.skia.impl/Native/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native/to-string.html
+$dokka.location:org.jetbrains.skia.impl/NativePointer///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native-pointer/index.html
+$dokka.location:org.jetbrains.skia.impl/NativePointerArray.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native-pointer-array/-companion/index.html
+$dokka.location:org.jetbrains.skia.impl/NativePointerArray///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native-pointer-array/index.html
+$dokka.location:org.jetbrains.skia.impl/NativePointerArray/NativePointerArray/#kotlin.Int#kotlin.LongArray/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native-pointer-array/-native-pointer-array.html
+$dokka.location:org.jetbrains.skia.impl/NativePointerArray/NativePointerArray/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native-pointer-array/-native-pointer-array.html
+$dokka.location:org.jetbrains.skia.impl/NativePointerArray/get/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native-pointer-array/get.html
+$dokka.location:org.jetbrains.skia.impl/NativePointerArray/set/#kotlin.Int#org.jetbrains.skia.impl.NativePointer/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native-pointer-array/set.html
+$dokka.location:org.jetbrains.skia.impl/NativePointerArray/size/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-native-pointer-array/size.html
+$dokka.location:org.jetbrains.skia.impl/RefCnt.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-ref-cnt/-companion/index.html
+$dokka.location:org.jetbrains.skia.impl/RefCnt.Companion/_nGetFinalizer/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-ref-cnt/-companion/_n-get-finalizer.html
+$dokka.location:org.jetbrains.skia.impl/RefCnt.Companion/_nGetRefCount/#kotlin.Long/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-ref-cnt/-companion/_n-get-ref-count.html
+$dokka.location:org.jetbrains.skia.impl/RefCnt///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-ref-cnt/index.html
+$dokka.location:org.jetbrains.skia.impl/RefCnt/refCount/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-ref-cnt/ref-count.html
+$dokka.location:org.jetbrains.skia.impl/RefCnt/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-ref-cnt/[native]to-string.html
+$dokka.location:org.jetbrains.skia.impl/Stats///PointingToDeclaration/skiko/org.jetbrains.skia.impl/-stats/index.html
+$dokka.location:org.jetbrains.skia.impl/Stats/allocated/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-stats/[native]allocated.html
+$dokka.location:org.jetbrains.skia.impl/Stats/enabled/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-stats/[native]enabled.html
+$dokka.location:org.jetbrains.skia.impl/Stats/nativeCalls/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-stats/[native]native-calls.html
+$dokka.location:org.jetbrains.skia.impl/Stats/onAllocated/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-stats/on-allocated.html
+$dokka.location:org.jetbrains.skia.impl/Stats/onDeallocated/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-stats/on-deallocated.html
+$dokka.location:org.jetbrains.skia.impl/Stats/onNativeCall/#/PointingToDeclaration/skiko/org.jetbrains.skia.impl/-stats/on-native-call.html
+$dokka.location:org.jetbrains.skia.paragraph////PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Affinity.DOWNSTREAM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-affinity/-d-o-w-n-s-t-r-e-a-m/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Affinity.UPSTREAM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-affinity/-u-p-s-t-r-e-a-m/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Affinity///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-affinity/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Affinity/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-affinity/value-of.html
+$dokka.location:org.jetbrains.skia.paragraph/Affinity/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-affinity/values.html
+$dokka.location:org.jetbrains.skia.paragraph/Alignment.CENTER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-alignment/-c-e-n-t-e-r/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Alignment.END///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-alignment/-e-n-d/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Alignment.JUSTIFY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-alignment/-j-u-s-t-i-f-y/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Alignment.LEFT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-alignment/-l-e-f-t/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Alignment.RIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-alignment/-r-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Alignment.START///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-alignment/-s-t-a-r-t/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Alignment///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-alignment/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Alignment/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-alignment/value-of.html
+$dokka.location:org.jetbrains.skia.paragraph/Alignment/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-alignment/values.html
+$dokka.location:org.jetbrains.skia.paragraph/BaselineMode.ALPHABETIC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-baseline-mode/-a-l-p-h-a-b-e-t-i-c/index.html
+$dokka.location:org.jetbrains.skia.paragraph/BaselineMode.IDEOGRAPHIC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-baseline-mode/-i-d-e-o-g-r-a-p-h-i-c/index.html
+$dokka.location:org.jetbrains.skia.paragraph/BaselineMode///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-baseline-mode/index.html
+$dokka.location:org.jetbrains.skia.paragraph/BaselineMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-baseline-mode/value-of.html
+$dokka.location:org.jetbrains.skia.paragraph/BaselineMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-baseline-mode/values.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationLineStyle.DASHED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-decoration-line-style/-d-a-s-h-e-d/index.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationLineStyle.DOTTED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-decoration-line-style/-d-o-t-t-e-d/index.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationLineStyle.DOUBLE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-decoration-line-style/-d-o-u-b-l-e/index.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationLineStyle.SOLID///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-decoration-line-style/-s-o-l-i-d/index.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationLineStyle.WAVY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-decoration-line-style/-w-a-v-y/index.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationLineStyle///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-line-style/index.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationLineStyle/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-line-style/value-of.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationLineStyle/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-line-style/values.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/-companion/index.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle.Companion/NONE/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/-companion/-n-o-n-e.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/index.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/DecorationStyle/#kotlin.Boolean#kotlin.Boolean#kotlin.Boolean#kotlin.Boolean#kotlin.Int#org.jetbrains.skia.paragraph.DecorationLineStyle#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/-decoration-style.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/_gaps/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/_gaps.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/_lineStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/_line-style.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/_lineThrough/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/_line-through.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/_overline/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/_overline.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/_underline/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/_underline.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/color/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/color.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/equals.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/hasGaps/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/has-gaps.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/hasLineThrough/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/has-line-through.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/hasOverline/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/has-overline.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/hasUnderline/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/has-underline.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/hash-code.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/lineStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/line-style.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/thicknessMultiplier/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/thickness-multiplier.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/to-string.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/withColor/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/with-color.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/withGaps/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/with-gaps.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/withLineStyle/#org.jetbrains.skia.paragraph.DecorationLineStyle/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/with-line-style.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/withLineThrough/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/with-line-through.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/withOverline/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/with-overline.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/withThicknessMultiplier/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/with-thickness-multiplier.html
+$dokka.location:org.jetbrains.skia.paragraph/DecorationStyle/withUnderline/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-decoration-style/with-underline.html
+$dokka.location:org.jetbrains.skia.paragraph/Direction.LTR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-direction/-l-t-r/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Direction.RTL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-direction/-r-t-l/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Direction///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-direction/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Direction/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-direction/value-of.html
+$dokka.location:org.jetbrains.skia.paragraph/Direction/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-direction/values.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/-companion/index.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/index.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/FontCollection/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/-font-collection.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/defaultFallback/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/default-fallback.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/defaultFallback/#kotlin.Int#org.jetbrains.skia.FontStyle#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/default-fallback.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/fallbackManager/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/fallback-manager.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/findTypefaces/#kotlin.Array[kotlin.String]?#org.jetbrains.skia.FontStyle/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/find-typefaces.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/fontManagersCount/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/font-managers-count.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/paragraphCache/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/paragraph-cache.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/setAssetFontManager/#org.jetbrains.skia.FontMgr?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/set-asset-font-manager.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/setDefaultFontManager/#org.jetbrains.skia.FontMgr?#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/set-default-font-manager.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/setDefaultFontManager/#org.jetbrains.skia.FontMgr?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/set-default-font-manager.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/setDynamicFontManager/#org.jetbrains.skia.FontMgr?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/set-dynamic-font-manager.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/setEnableFallback/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/set-enable-fallback.html
+$dokka.location:org.jetbrains.skia.paragraph/FontCollection/setTestFontManager/#org.jetbrains.skia.FontMgr?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-collection/set-test-font-manager.html
+$dokka.location:org.jetbrains.skia.paragraph/FontRastrSettings///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-rastr-settings/index.html
+$dokka.location:org.jetbrains.skia.paragraph/FontRastrSettings/FontRastrSettings/#org.jetbrains.skia.FontEdging#org.jetbrains.skia.FontHinting#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-rastr-settings/-font-rastr-settings.html
+$dokka.location:org.jetbrains.skia.paragraph/FontRastrSettings/edging/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-rastr-settings/edging.html
+$dokka.location:org.jetbrains.skia.paragraph/FontRastrSettings/hinting/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-rastr-settings/hinting.html
+$dokka.location:org.jetbrains.skia.paragraph/FontRastrSettings/subpixel/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-font-rastr-settings/subpixel.html
+$dokka.location:org.jetbrains.skia.paragraph/HeightMode.ALL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-height-mode/-a-l-l/index.html
+$dokka.location:org.jetbrains.skia.paragraph/HeightMode.DISABLE_ALL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-height-mode/-d-i-s-a-b-l-e_-a-l-l/index.html
+$dokka.location:org.jetbrains.skia.paragraph/HeightMode.DISABLE_FIRST_ASCENT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-height-mode/-d-i-s-a-b-l-e_-f-i-r-s-t_-a-s-c-e-n-t/index.html
+$dokka.location:org.jetbrains.skia.paragraph/HeightMode.DISABLE_LAST_DESCENT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-height-mode/-d-i-s-a-b-l-e_-l-a-s-t_-d-e-s-c-e-n-t/index.html
+$dokka.location:org.jetbrains.skia.paragraph/HeightMode///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-height-mode/index.html
+$dokka.location:org.jetbrains.skia.paragraph/HeightMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-height-mode/value-of.html
+$dokka.location:org.jetbrains.skia.paragraph/HeightMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-height-mode/values.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/index.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/LineMetrics/#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Boolean#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/-line-metrics.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/ascent/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/ascent.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/baseline/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/baseline.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/descent/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/descent.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/endExcludingWhitespaces/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/end-excluding-whitespaces.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/endIncludingNewline/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/end-including-newline.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/endIndex/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/end-index.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/equals.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/hash-code.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/height/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/height.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/isHardBreak/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/is-hard-break.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/left/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/left.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/lineHeight/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/line-height.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/lineNumber/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/line-number.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/right/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/right.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/startIndex/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/start-index.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/to-string.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/unscaledAscent/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/unscaled-ascent.html
+$dokka.location:org.jetbrains.skia.paragraph/LineMetrics/width/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-line-metrics/width.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/-companion/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/alphabeticBaseline/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/alphabetic-baseline.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/close/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/close.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/didExceedMaxLines/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/did-exceed-max-lines.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/getGlyphPositionAtCoordinate/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/get-glyph-position-at-coordinate.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/getRectsForRange/#kotlin.Int#kotlin.Int#org.jetbrains.skia.paragraph.RectHeightMode#org.jetbrains.skia.paragraph.RectWidthMode/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/get-rects-for-range.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/getText/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/get-text.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/getWordBoundary/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/get-word-boundary.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/height/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/height.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/ideographicBaseline/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/ideographic-baseline.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/layout/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/layout.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/lineMetrics/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/line-metrics.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/lineNumber/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/line-number.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/longestLine/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/longest-line.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/markDirty/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/mark-dirty.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/maxIntrinsicWidth/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/max-intrinsic-width.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/maxWidth/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/max-width.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/minIntrinsicWidth/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/min-intrinsic-width.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/paint/#org.jetbrains.skia.Canvas?#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/paint.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/rectsForPlaceholders/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/rects-for-placeholders.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/unresolvedGlyphsCount/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/unresolved-glyphs-count.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/updateAlignment/#org.jetbrains.skia.paragraph.Alignment/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/update-alignment.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/updateBackgroundPaint/#kotlin.Int#kotlin.Int#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/update-background-paint.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/updateFontSize/#kotlin.Int#kotlin.Int#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/update-font-size.html
+$dokka.location:org.jetbrains.skia.paragraph/Paragraph/updateForegroundPaint/#kotlin.Int#kotlin.Int#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph/update-foreground-paint.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphBuilder.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-builder/-companion/index.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphBuilder///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-builder/index.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphBuilder/ParagraphBuilder/#org.jetbrains.skia.paragraph.ParagraphStyle?#org.jetbrains.skia.paragraph.FontCollection?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-builder/-paragraph-builder.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphBuilder/addPlaceholder/#org.jetbrains.skia.paragraph.PlaceholderStyle/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-builder/add-placeholder.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphBuilder/addText/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-builder/add-text.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphBuilder/build/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-builder/build.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphBuilder/popStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-builder/pop-style.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphBuilder/pushStyle/#org.jetbrains.skia.paragraph.TextStyle?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-builder/push-style.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphCache.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-cache/-companion/index.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphCache///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-cache/index.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphCache/abandon/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-cache/abandon.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphCache/count/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-cache/count.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphCache/findParagraph/#org.jetbrains.skia.paragraph.Paragraph?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-cache/find-paragraph.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphCache/printStatistics/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-cache/print-statistics.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphCache/reset/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-cache/reset.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphCache/setEnabled/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-cache/set-enabled.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphCache/updateParagraph/#org.jetbrains.skia.paragraph.Paragraph?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-cache/update-paragraph.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/-companion/index.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/index.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/ParagraphStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/-paragraph-style.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/alignment/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/alignment.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/direction/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/direction.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/disableHinting/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/disable-hinting.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/effectiveAlignment/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/effective-alignment.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/ellipsis/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/ellipsis.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/fontRastrSettings/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/font-rastr-settings.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/height/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/height.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/heightMode/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/height-mode.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/isHintingEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/is-hinting-enabled.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/maxLinesCount/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/max-lines-count.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/strutStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/strut-style.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/textIndent/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/text-indent.html
+$dokka.location:org.jetbrains.skia.paragraph/ParagraphStyle/textStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-paragraph-style/text-style.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderAlignment.ABOVE_BASELINE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-placeholder-alignment/-a-b-o-v-e_-b-a-s-e-l-i-n-e/index.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderAlignment.BASELINE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-placeholder-alignment/-b-a-s-e-l-i-n-e/index.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderAlignment.BELOW_BASELINE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-placeholder-alignment/-b-e-l-o-w_-b-a-s-e-l-i-n-e/index.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderAlignment.BOTTOM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-placeholder-alignment/-b-o-t-t-o-m/index.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderAlignment.MIDDLE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-placeholder-alignment/-m-i-d-d-l-e/index.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderAlignment.TOP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-placeholder-alignment/-t-o-p/index.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderAlignment///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-alignment/index.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderAlignment/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-alignment/value-of.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderAlignment/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-alignment/values.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/index.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle/PlaceholderStyle/#kotlin.Float#kotlin.Float#org.jetbrains.skia.paragraph.PlaceholderAlignment#org.jetbrains.skia.paragraph.BaselineMode#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/-placeholder-style.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle/_alignment/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/_alignment.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle/_baselineMode/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/_baseline-mode.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle/alignment/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/alignment.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle/baseline/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/baseline.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle/baselineMode/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/baseline-mode.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/equals.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/hash-code.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle/height/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/height.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/to-string.html
+$dokka.location:org.jetbrains.skia.paragraph/PlaceholderStyle/width/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-placeholder-style/width.html
+$dokka.location:org.jetbrains.skia.paragraph/PositionWithAffinity///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-position-with-affinity/index.html
+$dokka.location:org.jetbrains.skia.paragraph/PositionWithAffinity/PositionWithAffinity/#kotlin.Int#org.jetbrains.skia.paragraph.Affinity/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-position-with-affinity/-position-with-affinity.html
+$dokka.location:org.jetbrains.skia.paragraph/PositionWithAffinity/_affinity/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-position-with-affinity/_affinity.html
+$dokka.location:org.jetbrains.skia.paragraph/PositionWithAffinity/affinity/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-position-with-affinity/affinity.html
+$dokka.location:org.jetbrains.skia.paragraph/PositionWithAffinity/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-position-with-affinity/equals.html
+$dokka.location:org.jetbrains.skia.paragraph/PositionWithAffinity/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-position-with-affinity/hash-code.html
+$dokka.location:org.jetbrains.skia.paragraph/PositionWithAffinity/position/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-position-with-affinity/position.html
+$dokka.location:org.jetbrains.skia.paragraph/PositionWithAffinity/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-position-with-affinity/to-string.html
+$dokka.location:org.jetbrains.skia.paragraph/RectHeightMode.INCLUDE_LINE_SPACING_BOTTOM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-rect-height-mode/-i-n-c-l-u-d-e_-l-i-n-e_-s-p-a-c-i-n-g_-b-o-t-t-o-m/index.html
+$dokka.location:org.jetbrains.skia.paragraph/RectHeightMode.INCLUDE_LINE_SPACING_MIDDLE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-rect-height-mode/-i-n-c-l-u-d-e_-l-i-n-e_-s-p-a-c-i-n-g_-m-i-d-d-l-e/index.html
+$dokka.location:org.jetbrains.skia.paragraph/RectHeightMode.INCLUDE_LINE_SPACING_TOP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-rect-height-mode/-i-n-c-l-u-d-e_-l-i-n-e_-s-p-a-c-i-n-g_-t-o-p/index.html
+$dokka.location:org.jetbrains.skia.paragraph/RectHeightMode.MAX///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-rect-height-mode/-m-a-x/index.html
+$dokka.location:org.jetbrains.skia.paragraph/RectHeightMode.STRUT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-rect-height-mode/-s-t-r-u-t/index.html
+$dokka.location:org.jetbrains.skia.paragraph/RectHeightMode.TIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-rect-height-mode/-t-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia.paragraph/RectHeightMode///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-rect-height-mode/index.html
+$dokka.location:org.jetbrains.skia.paragraph/RectHeightMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-rect-height-mode/value-of.html
+$dokka.location:org.jetbrains.skia.paragraph/RectHeightMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-rect-height-mode/values.html
+$dokka.location:org.jetbrains.skia.paragraph/RectWidthMode.MAX///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-rect-width-mode/-m-a-x/index.html
+$dokka.location:org.jetbrains.skia.paragraph/RectWidthMode.TIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-rect-width-mode/-t-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia.paragraph/RectWidthMode///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-rect-width-mode/index.html
+$dokka.location:org.jetbrains.skia.paragraph/RectWidthMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-rect-width-mode/value-of.html
+$dokka.location:org.jetbrains.skia.paragraph/RectWidthMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-rect-width-mode/values.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/-companion/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/index.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/Shadow/#kotlin.Int#kotlin.Float#kotlin.Float#kotlin.Double/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/-shadow.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/Shadow/#kotlin.Int#org.jetbrains.skia.Point#kotlin.Double/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/-shadow.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/blurSigma/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/blur-sigma.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/color/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/color.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/equals.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/hash-code.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/offset/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/offset.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/offsetX/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/offset-x.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/offsetY/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/offset-y.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/to-string.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/withBlurSigma/#kotlin.Double/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/with-blur-sigma.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/withColor/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/with-color.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/withOffsetX/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/with-offset-x.html
+$dokka.location:org.jetbrains.skia.paragraph/Shadow/withOffsetY/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-shadow/with-offset-y.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/-companion/index.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/index.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/StrutStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/-strut-style.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/fontFamilies/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/font-families.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/fontSize/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/font-size.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/fontStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/font-style.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/height/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/height.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/isEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/is-enabled.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/isHalfLeading/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/is-half-leading.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/isHeightForced/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/is-height-forced.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/isHeightOverridden/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/is-height-overridden.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/leading/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/leading.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/setEnabled/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/set-enabled.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/setFontFamilies/#kotlin.Array[kotlin.String]/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/set-font-families.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/setFontSize/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/set-font-size.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/setFontStyle/#org.jetbrains.skia.FontStyle/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/set-font-style.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/setHalfLeading/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/set-half-leading.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/setHeight/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/set-height.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/setHeightForced/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/set-height-forced.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/setHeightOverridden/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/set-height-overridden.html
+$dokka.location:org.jetbrains.skia.paragraph/StrutStyle/setLeading/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-strut-style/set-leading.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/-companion/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox.Companion/disposeArray/#org.jetbrains.skia.impl.InteropPointer/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/-companion/dispose-array.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox.Companion/getArrayElement/#org.jetbrains.skia.impl.InteropPointer#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/-companion/get-array-element.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox.Companion/getArraySize/#org.jetbrains.skia.impl.InteropPointer/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/-companion/get-array-size.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox/TextBox/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/-text-box.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox/TextBox/#org.jetbrains.skia.Rect#org.jetbrains.skia.paragraph.Direction/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/-text-box.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox/_direction/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/_direction.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox/direction/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/direction.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/equals.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/hash-code.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox/rect/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/rect.html
+$dokka.location:org.jetbrains.skia.paragraph/TextBox/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-box/to-string.html
+$dokka.location:org.jetbrains.skia.paragraph/TextIndent///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-indent/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextIndent/TextIndent/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-indent/-text-indent.html
+$dokka.location:org.jetbrains.skia.paragraph/TextIndent/firstLine/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-indent/first-line.html
+$dokka.location:org.jetbrains.skia.paragraph/TextIndent/restLine/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-indent/rest-line.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/-companion/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/TextStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/-text-style.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/addFontFeature/#org.jetbrains.skia.FontFeature/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/add-font-feature.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/addFontFeatures/#kotlin.Array[org.jetbrains.skia.FontFeature]/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/add-font-features.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/addShadow/#org.jetbrains.skia.paragraph.Shadow/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/add-shadow.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/addShadows/#kotlin.Array[org.jetbrains.skia.paragraph.Shadow]/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/add-shadows.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/background/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/background.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/baselineMode/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/baseline-mode.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/baselineShift/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/baseline-shift.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/clearFontFeatures/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/clear-font-features.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/clearShadows/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/clear-shadows.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/color/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/color.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/decorationStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/decoration-style.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/equals/#org.jetbrains.skia.paragraph.TextStyleAttribute#org.jetbrains.skia.paragraph.TextStyle?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/equals.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/fontFamilies/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/font-families.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/fontFeatures/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/font-features.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/fontMetrics/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/font-metrics.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/fontSize/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/font-size.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/fontStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/font-style.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/foreground/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/foreground.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/height/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/height.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/isHalfLeading/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/is-half-leading.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/isPlaceholder/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/is-placeholder.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/letterSpacing/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/letter-spacing.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/locale/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/locale.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setBackground/#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-background.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setBaselineMode/#org.jetbrains.skia.paragraph.BaselineMode/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-baseline-mode.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setBaselineShift/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-baseline-shift.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setColor/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-color.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setDecorationStyle/#org.jetbrains.skia.paragraph.DecorationStyle/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-decoration-style.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setFontFamilies/#kotlin.Array[kotlin.String]?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-font-families.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setFontFamily/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-font-family.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setFontSize/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-font-size.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setFontStyle/#org.jetbrains.skia.FontStyle/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-font-style.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setForeground/#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-foreground.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setHalfLeading/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-half-leading.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setHeight/#kotlin.Float?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-height.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setLetterSpacing/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-letter-spacing.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setLocale/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-locale.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setPlaceholder/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-placeholder.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setTypeface/#org.jetbrains.skia.Typeface?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-typeface.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/setWordSpacing/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/set-word-spacing.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/shadows/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/shadows.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/typeface/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/typeface.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyle/wordSpacing/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style/word-spacing.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute.ALL_ATTRIBUTES///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-text-style-attribute/-a-l-l_-a-t-t-r-i-b-u-t-e-s/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute.BACKGROUND///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-text-style-attribute/-b-a-c-k-g-r-o-u-n-d/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute.DECORATIONS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-text-style-attribute/-d-e-c-o-r-a-t-i-o-n-s/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute.FONT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-text-style-attribute/-f-o-n-t/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute.FONT_EXACT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-text-style-attribute/-f-o-n-t_-e-x-a-c-t/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute.FOREGROUND///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-text-style-attribute/-f-o-r-e-g-r-o-u-n-d/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute.LETTER_SPACING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-text-style-attribute/-l-e-t-t-e-r_-s-p-a-c-i-n-g/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute.NONE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-text-style-attribute/-n-o-n-e/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute.SHADOW///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-text-style-attribute/-s-h-a-d-o-w/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute.WORD_SPACING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.paragraph/-text-style-attribute/-w-o-r-d_-s-p-a-c-i-n-g/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style-attribute/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style-attribute/value-of.html
+$dokka.location:org.jetbrains.skia.paragraph/TextStyleAttribute/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-text-style-attribute/values.html
+$dokka.location:org.jetbrains.skia.paragraph/TypefaceFontProvider.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-typeface-font-provider/-companion/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TypefaceFontProvider///PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-typeface-font-provider/index.html
+$dokka.location:org.jetbrains.skia.paragraph/TypefaceFontProvider/TypefaceFontProvider/#/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-typeface-font-provider/-typeface-font-provider.html
+$dokka.location:org.jetbrains.skia.paragraph/TypefaceFontProvider/registerTypeface/#org.jetbrains.skia.Typeface?#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia.paragraph/-typeface-font-provider/register-typeface.html
+$dokka.location:org.jetbrains.skia.shaper////PointingToDeclaration/skiko/org.jetbrains.skia.shaper/index.html
+$dokka.location:org.jetbrains.skia.shaper/BidiRun///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-bidi-run/index.html
+$dokka.location:org.jetbrains.skia.shaper/BidiRun/BidiRun/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-bidi-run/-bidi-run.html
+$dokka.location:org.jetbrains.skia.shaper/BidiRun/end/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-bidi-run/end.html
+$dokka.location:org.jetbrains.skia.shaper/BidiRun/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-bidi-run/equals.html
+$dokka.location:org.jetbrains.skia.shaper/BidiRun/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-bidi-run/hash-code.html
+$dokka.location:org.jetbrains.skia.shaper/BidiRun/level/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-bidi-run/level.html
+$dokka.location:org.jetbrains.skia.shaper/BidiRun/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-bidi-run/to-string.html
+$dokka.location:org.jetbrains.skia.shaper/FontMgrRunIterator.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-mgr-run-iterator/-companion/index.html
+$dokka.location:org.jetbrains.skia.shaper/FontMgrRunIterator///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-mgr-run-iterator/index.html
+$dokka.location:org.jetbrains.skia.shaper/FontMgrRunIterator/FontMgrRunIterator/#kotlin.String#org.jetbrains.skia.Font#org.jetbrains.skia.shaper.ShapingOptions/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-mgr-run-iterator/-font-mgr-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/FontMgrRunIterator/FontMgrRunIterator/#kotlin.String#org.jetbrains.skia.Font/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-mgr-run-iterator/-font-mgr-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/FontMgrRunIterator/FontMgrRunIterator/#org.jetbrains.skia.ManagedString#kotlin.Boolean#org.jetbrains.skia.Font#org.jetbrains.skia.shaper.ShapingOptions/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-mgr-run-iterator/-font-mgr-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/FontMgrRunIterator/next/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-mgr-run-iterator/next.html
+$dokka.location:org.jetbrains.skia.shaper/FontMgrRunIterator/remove/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-mgr-run-iterator/remove.html
+$dokka.location:org.jetbrains.skia.shaper/FontRun///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-run/index.html
+$dokka.location:org.jetbrains.skia.shaper/FontRun/FontRun/#kotlin.Int#org.jetbrains.skia.Font/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-run/-font-run.html
+$dokka.location:org.jetbrains.skia.shaper/FontRun/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-run/equals.html
+$dokka.location:org.jetbrains.skia.shaper/FontRun/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-run/hash-code.html
+$dokka.location:org.jetbrains.skia.shaper/FontRun/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-font-run/to-string.html
+$dokka.location:org.jetbrains.skia.shaper/HbIcuScriptRunIterator.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-hb-icu-script-run-iterator/-companion/index.html
+$dokka.location:org.jetbrains.skia.shaper/HbIcuScriptRunIterator///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-hb-icu-script-run-iterator/index.html
+$dokka.location:org.jetbrains.skia.shaper/HbIcuScriptRunIterator/HbIcuScriptRunIterator/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-hb-icu-script-run-iterator/-hb-icu-script-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/HbIcuScriptRunIterator/HbIcuScriptRunIterator/#org.jetbrains.skia.ManagedString#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-hb-icu-script-run-iterator/-hb-icu-script-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/HbIcuScriptRunIterator/next/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-hb-icu-script-run-iterator/next.html
+$dokka.location:org.jetbrains.skia.shaper/HbIcuScriptRunIterator/remove/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-hb-icu-script-run-iterator/remove.html
+$dokka.location:org.jetbrains.skia.shaper/IcuBidiRunIterator.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-icu-bidi-run-iterator/-companion/index.html
+$dokka.location:org.jetbrains.skia.shaper/IcuBidiRunIterator///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-icu-bidi-run-iterator/index.html
+$dokka.location:org.jetbrains.skia.shaper/IcuBidiRunIterator/IcuBidiRunIterator/#kotlin.String#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-icu-bidi-run-iterator/-icu-bidi-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/IcuBidiRunIterator/IcuBidiRunIterator/#org.jetbrains.skia.ManagedString#kotlin.Boolean#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-icu-bidi-run-iterator/-icu-bidi-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/IcuBidiRunIterator/next/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-icu-bidi-run-iterator/next.html
+$dokka.location:org.jetbrains.skia.shaper/IcuBidiRunIterator/remove/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-icu-bidi-run-iterator/remove.html
+$dokka.location:org.jetbrains.skia.shaper/JavaTextBidiRunIterator///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-java-text-bidi-run-iterator/index.html
+$dokka.location:org.jetbrains.skia.shaper/JavaTextBidiRunIterator/JavaTextBidiRunIterator/#kotlin.String?#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-java-text-bidi-run-iterator/-java-text-bidi-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/JavaTextBidiRunIterator/hasNext/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-java-text-bidi-run-iterator/has-next.html
+$dokka.location:org.jetbrains.skia.shaper/JavaTextBidiRunIterator/next/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-java-text-bidi-run-iterator/next.html
+$dokka.location:org.jetbrains.skia.shaper/JavaTextBidiRunIterator/remove/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-java-text-bidi-run-iterator/remove.html
+$dokka.location:org.jetbrains.skia.shaper/LanguageRun///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-language-run/index.html
+$dokka.location:org.jetbrains.skia.shaper/LanguageRun/LanguageRun/#kotlin.Int#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-language-run/-language-run.html
+$dokka.location:org.jetbrains.skia.shaper/LanguageRun/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-language-run/equals.html
+$dokka.location:org.jetbrains.skia.shaper/LanguageRun/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-language-run/hash-code.html
+$dokka.location:org.jetbrains.skia.shaper/LanguageRun/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-language-run/to-string.html
+$dokka.location:org.jetbrains.skia.shaper/ManagedRunIterator.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-managed-run-iterator/-companion/index.html
+$dokka.location:org.jetbrains.skia.shaper/ManagedRunIterator///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-managed-run-iterator/index.html
+$dokka.location:org.jetbrains.skia.shaper/ManagedRunIterator/close/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-managed-run-iterator/close.html
+$dokka.location:org.jetbrains.skia.shaper/ManagedRunIterator/hasNext/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-managed-run-iterator/has-next.html
+$dokka.location:org.jetbrains.skia.shaper/RunHandler///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-handler/index.html
+$dokka.location:org.jetbrains.skia.shaper/RunHandler/beginLine/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-handler/begin-line.html
+$dokka.location:org.jetbrains.skia.shaper/RunHandler/commitLine/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-handler/commit-line.html
+$dokka.location:org.jetbrains.skia.shaper/RunHandler/commitRun/#org.jetbrains.skia.shaper.RunInfo?#kotlin.ShortArray?#kotlin.Array[org.jetbrains.skia.Point?]?#kotlin.IntArray?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-handler/commit-run.html
+$dokka.location:org.jetbrains.skia.shaper/RunHandler/commitRunInfo/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-handler/commit-run-info.html
+$dokka.location:org.jetbrains.skia.shaper/RunHandler/runInfo/#org.jetbrains.skia.shaper.RunInfo?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-handler/run-info.html
+$dokka.location:org.jetbrains.skia.shaper/RunHandler/runOffset/#org.jetbrains.skia.shaper.RunInfo?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-handler/run-offset.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/index.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/RunInfo/#org.jetbrains.skia.impl.NativePointer#kotlin.Int#kotlin.Float#kotlin.Float#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/-run-info.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/_fontPtr/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/_font-ptr.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/advance/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/advance.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/advanceX/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/advance-x.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/advanceY/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/advance-y.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/bidiLevel/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/bidi-level.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/equals.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/font/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/font.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/glyphCount/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/glyph-count.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/hash-code.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/rangeBegin/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/range-begin.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/rangeEnd/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/range-end.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/rangeSize/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/range-size.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/setFontPtr/#org.jetbrains.skia.impl.NativePointer/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/set-font-ptr.html
+$dokka.location:org.jetbrains.skia.shaper/RunInfo/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-info/to-string.html
+$dokka.location:org.jetbrains.skia.shaper/RunIteratorBase.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-iterator-base/-companion/index.html
+$dokka.location:org.jetbrains.skia.shaper/RunIteratorBase.Companion/fromIterator/#kotlin.collections.Iterator[org.jetbrains.skia.shaper.BidiRun?]#org.jetbrains.skia.ManagedString/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-iterator-base/-companion/from-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/RunIteratorBase.Companion/fromIterator/#kotlin.collections.Iterator[org.jetbrains.skia.shaper.FontRun?]#org.jetbrains.skia.ManagedString/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-iterator-base/-companion/from-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/RunIteratorBase.Companion/fromIterator/#kotlin.collections.Iterator[org.jetbrains.skia.shaper.LanguageRun?]#org.jetbrains.skia.ManagedString/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-iterator-base/-companion/from-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/RunIteratorBase.Companion/fromIterator/#kotlin.collections.Iterator[org.jetbrains.skia.shaper.ScriptRun?]#org.jetbrains.skia.ManagedString/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-iterator-base/-companion/from-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/RunIteratorBase///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-iterator-base/index.html
+$dokka.location:org.jetbrains.skia.shaper/RunIteratorBase/atEnd/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-iterator-base/at-end.html
+$dokka.location:org.jetbrains.skia.shaper/RunIteratorBase/consume/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-iterator-base/consume.html
+$dokka.location:org.jetbrains.skia.shaper/RunIteratorBase/endOfCurrentRun/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-run-iterator-base/end-of-current-run.html
+$dokka.location:org.jetbrains.skia.shaper/ScriptRun///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-script-run/index.html
+$dokka.location:org.jetbrains.skia.shaper/ScriptRun/ScriptRun/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-script-run/-script-run.html
+$dokka.location:org.jetbrains.skia.shaper/ScriptRun/ScriptRun/#kotlin.Int#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-script-run/-script-run.html
+$dokka.location:org.jetbrains.skia.shaper/ScriptRun/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-script-run/equals.html
+$dokka.location:org.jetbrains.skia.shaper/ScriptRun/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-script-run/hash-code.html
+$dokka.location:org.jetbrains.skia.shaper/ScriptRun/script/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-script-run/script.html
+$dokka.location:org.jetbrains.skia.shaper/ScriptRun/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-script-run/to-string.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/-companion/index.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper.Companion/make/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/-companion/make.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper.Companion/make/#org.jetbrains.skia.FontMgr?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/-companion/make.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper.Companion/makeCoreText/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/-companion/make-core-text.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper.Companion/makePrimitive/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/-companion/make-primitive.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper.Companion/makeShapeDontWrapOrReorder/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/-companion/make-shape-dont-wrap-or-reorder.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper.Companion/makeShapeDontWrapOrReorder/#org.jetbrains.skia.FontMgr?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/-companion/make-shape-dont-wrap-or-reorder.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper.Companion/makeShapeThenWrap/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/-companion/make-shape-then-wrap.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper.Companion/makeShapeThenWrap/#org.jetbrains.skia.FontMgr?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/-companion/make-shape-then-wrap.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper.Companion/makeShaperDrivenWrapper/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/-companion/make-shaper-driven-wrapper.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper.Companion/makeShaperDrivenWrapper/#org.jetbrains.skia.FontMgr?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/-companion/make-shaper-driven-wrapper.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/index.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper/shape/#kotlin.String#kotlin.collections.Iterator[org.jetbrains.skia.shaper.FontRun?]#kotlin.collections.Iterator[org.jetbrains.skia.shaper.BidiRun?]#kotlin.collections.Iterator[org.jetbrains.skia.shaper.ScriptRun?]#kotlin.collections.Iterator[org.jetbrains.skia.shaper.LanguageRun?]#org.jetbrains.skia.shaper.ShapingOptions#kotlin.Float#org.jetbrains.skia.shaper.RunHandler/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/shape.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper/shape/#kotlin.String#org.jetbrains.skia.Font#kotlin.Float#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/shape.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper/shape/#kotlin.String#org.jetbrains.skia.Font#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/shape.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper/shape/#kotlin.String#org.jetbrains.skia.Font#org.jetbrains.skia.shaper.ShapingOptions#kotlin.Float#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/shape.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper/shape/#kotlin.String#org.jetbrains.skia.Font#org.jetbrains.skia.shaper.ShapingOptions#kotlin.Float#org.jetbrains.skia.shaper.RunHandler/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/shape.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper/shape/#kotlin.String#org.jetbrains.skia.Font/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/shape.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper/shape/#org.jetbrains.skia.ManagedString#kotlin.collections.Iterator[org.jetbrains.skia.shaper.FontRun?]#kotlin.collections.Iterator[org.jetbrains.skia.shaper.BidiRun?]#kotlin.collections.Iterator[org.jetbrains.skia.shaper.ScriptRun?]#kotlin.collections.Iterator[org.jetbrains.skia.shaper.LanguageRun?]#org.jetbrains.skia.shaper.ShapingOptions#kotlin.Float#org.jetbrains.skia.shaper.RunHandler/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/shape.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper/shapeLine/#kotlin.String?#org.jetbrains.skia.Font?#org.jetbrains.skia.shaper.ShapingOptions/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/shape-line.html
+$dokka.location:org.jetbrains.skia.shaper/Shaper/shapeLine/#kotlin.String?#org.jetbrains.skia.Font?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaper/shape-line.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/-companion/index.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions.Companion/DEFAULT/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/-companion/-d-e-f-a-u-l-t.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/index.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions/ShapingOptions/#org.jetbrains.skia.FontMgr?#kotlin.Array[org.jetbrains.skia.FontFeature]?#kotlin.Boolean#kotlin.Boolean#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/-shaping-options.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/equals.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/hash-code.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/to-string.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions/withApproximatePunctuation/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/with-approximate-punctuation.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions/withApproximateSpaces/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/with-approximate-spaces.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions/withFeatures/#kotlin.Array[org.jetbrains.skia.FontFeature]?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/with-features.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions/withFeatures/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/with-features.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions/withFontMgr/#org.jetbrains.skia.FontMgr?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/with-font-mgr.html
+$dokka.location:org.jetbrains.skia.shaper/ShapingOptions/withLeftToRight/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-shaping-options/with-left-to-right.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/-companion/index.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/index.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler/TextBlobBuilderRunHandler/#kotlin.String?#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/-text-blob-builder-run-handler.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler/TextBlobBuilderRunHandler/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/-text-blob-builder-run-handler.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler/beginLine/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/begin-line.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler/close/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/close.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler/commitLine/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/commit-line.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler/commitRun/#org.jetbrains.skia.shaper.RunInfo?#kotlin.ShortArray?#kotlin.Array[org.jetbrains.skia.Point?]?#kotlin.IntArray?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/commit-run.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler/commitRunInfo/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/commit-run-info.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler/makeBlob/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/make-blob.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler/runInfo/#org.jetbrains.skia.shaper.RunInfo?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/run-info.html
+$dokka.location:org.jetbrains.skia.shaper/TextBlobBuilderRunHandler/runOffset/#org.jetbrains.skia.shaper.RunInfo?/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-text-blob-builder-run-handler/run-offset.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialBidiRunIterator///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-bidi-run-iterator/index.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialBidiRunIterator/TrivialBidiRunIterator/#kotlin.String#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-bidi-run-iterator/-trivial-bidi-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialBidiRunIterator/_length/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-bidi-run-iterator/_length.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialBidiRunIterator/_level/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-bidi-run-iterator/_level.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialBidiRunIterator/hasNext/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-bidi-run-iterator/has-next.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialBidiRunIterator/next/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-bidi-run-iterator/next.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialBidiRunIterator/remove/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-bidi-run-iterator/remove.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialFontRunIterator///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-font-run-iterator/index.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialFontRunIterator/TrivialFontRunIterator/#kotlin.String#org.jetbrains.skia.Font/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-font-run-iterator/-trivial-font-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialFontRunIterator/_font/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-font-run-iterator/_font.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialFontRunIterator/_length/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-font-run-iterator/_length.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialFontRunIterator/hasNext/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-font-run-iterator/has-next.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialFontRunIterator/next/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-font-run-iterator/next.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialFontRunIterator/remove/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-font-run-iterator/remove.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialLanguageRunIterator///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-language-run-iterator/index.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialLanguageRunIterator/TrivialLanguageRunIterator/#kotlin.String#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-language-run-iterator/-trivial-language-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialLanguageRunIterator/_language/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-language-run-iterator/_language.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialLanguageRunIterator/_length/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-language-run-iterator/_length.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialLanguageRunIterator/hasNext/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-language-run-iterator/has-next.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialLanguageRunIterator/next/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-language-run-iterator/next.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialLanguageRunIterator/remove/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-language-run-iterator/remove.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialScriptRunIterator///PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-script-run-iterator/index.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialScriptRunIterator/TrivialScriptRunIterator/#kotlin.String#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-script-run-iterator/-trivial-script-run-iterator.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialScriptRunIterator/_length/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-script-run-iterator/_length.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialScriptRunIterator/_script/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-script-run-iterator/_script.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialScriptRunIterator/hasNext/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-script-run-iterator/has-next.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialScriptRunIterator/next/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-script-run-iterator/next.html
+$dokka.location:org.jetbrains.skia.shaper/TrivialScriptRunIterator/remove/#/PointingToDeclaration/skiko/org.jetbrains.skia.shaper/-trivial-script-run-iterator/remove.html
+$dokka.location:org.jetbrains.skia.skottie////PointingToDeclaration/skiko/org.jetbrains.skia.skottie/index.html
+$dokka.location:org.jetbrains.skia.skottie//buildFromFile/org.jetbrains.skia.skottie.AnimationBuilder#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/[native]build-from-file.html
+$dokka.location:org.jetbrains.skia.skottie//makeFromFile/org.jetbrains.skia.skottie.Animation.Companion#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/[native]make-from-file.html
+$dokka.location:org.jetbrains.skia.skottie/Animation.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/-companion/index.html
+$dokka.location:org.jetbrains.skia.skottie/Animation.Companion/makeFromData/#org.jetbrains.skia.Data/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/-companion/make-from-data.html
+$dokka.location:org.jetbrains.skia.skottie/Animation.Companion/makeFromString/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/-companion/make-from-string.html
+$dokka.location:org.jetbrains.skia.skottie/Animation///PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/index.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/duration/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/duration.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/fPS/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/f-p-s.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/height/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/height.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/inPoint/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/in-point.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/outPoint/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/out-point.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/render/#org.jetbrains.skia.Canvas#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/render.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/render/#org.jetbrains.skia.Canvas#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/render.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/render/#org.jetbrains.skia.Canvas#org.jetbrains.skia.Rect#kotlin.Array[org.jetbrains.skia.skottie.RenderFlag]/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/render.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/render/#org.jetbrains.skia.Canvas/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/render.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/seek/#kotlin.Float#org.jetbrains.skia.sksg.InvalidationController?/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/seek.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/seek/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/seek.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/seekFrame/#kotlin.Float#org.jetbrains.skia.sksg.InvalidationController?/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/seek-frame.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/seekFrame/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/seek-frame.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/seekFrameTime/#kotlin.Float#org.jetbrains.skia.sksg.InvalidationController?/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/seek-frame-time.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/seekFrameTime/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/seek-frame-time.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/size/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/size.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/version/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/version.html
+$dokka.location:org.jetbrains.skia.skottie/Animation/width/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation/width.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilder.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder/-companion/index.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilder///PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder/index.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilder/AnimationBuilder/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder/-animation-builder.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilder/AnimationBuilder/#kotlin.Array[org.jetbrains.skia.skottie.AnimationBuilderFlag]/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder/-animation-builder.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilder/buildFromData/#org.jetbrains.skia.Data/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder/build-from-data.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilder/buildFromString/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder/build-from-string.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilder/setFontManager/#org.jetbrains.skia.FontMgr?/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder/set-font-manager.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilder/setLogger/#org.jetbrains.skia.skottie.Logger?/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder/set-logger.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilderFlag.DEFER_IMAGE_LOADING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.skottie/-animation-builder-flag/-d-e-f-e-r_-i-m-a-g-e_-l-o-a-d-i-n-g/index.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilderFlag.PREFER_EMBEDDED_FONTS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.skottie/-animation-builder-flag/-p-r-e-f-e-r_-e-m-b-e-d-d-e-d_-f-o-n-t-s/index.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilderFlag///PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder-flag/index.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilderFlag/_flag/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder-flag/_flag.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilderFlag/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder-flag/value-of.html
+$dokka.location:org.jetbrains.skia.skottie/AnimationBuilderFlag/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-animation-builder-flag/values.html
+$dokka.location:org.jetbrains.skia.skottie/LogLevel.ERROR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.skottie/-log-level/-e-r-r-o-r/index.html
+$dokka.location:org.jetbrains.skia.skottie/LogLevel.WARNING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.skottie/-log-level/-w-a-r-n-i-n-g/index.html
+$dokka.location:org.jetbrains.skia.skottie/LogLevel///PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-log-level/index.html
+$dokka.location:org.jetbrains.skia.skottie/LogLevel/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-log-level/value-of.html
+$dokka.location:org.jetbrains.skia.skottie/LogLevel/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-log-level/values.html
+$dokka.location:org.jetbrains.skia.skottie/Logger.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-logger/-companion/index.html
+$dokka.location:org.jetbrains.skia.skottie/Logger///PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-logger/index.html
+$dokka.location:org.jetbrains.skia.skottie/Logger/Logger/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-logger/-logger.html
+$dokka.location:org.jetbrains.skia.skottie/Logger/log/#org.jetbrains.skia.skottie.LogLevel#kotlin.String#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-logger/log.html
+$dokka.location:org.jetbrains.skia.skottie/RenderFlag.DISABLE_TOP_LEVEL_CLIPPING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.skottie/-render-flag/-d-i-s-a-b-l-e_-t-o-p_-l-e-v-e-l_-c-l-i-p-p-i-n-g/index.html
+$dokka.location:org.jetbrains.skia.skottie/RenderFlag.SKIP_TOP_LEVEL_ISOLATION///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.skottie/-render-flag/-s-k-i-p_-t-o-p_-l-e-v-e-l_-i-s-o-l-a-t-i-o-n/index.html
+$dokka.location:org.jetbrains.skia.skottie/RenderFlag///PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-render-flag/index.html
+$dokka.location:org.jetbrains.skia.skottie/RenderFlag/_flag/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-render-flag/_flag.html
+$dokka.location:org.jetbrains.skia.skottie/RenderFlag/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-render-flag/value-of.html
+$dokka.location:org.jetbrains.skia.skottie/RenderFlag/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.skottie/-render-flag/values.html
+$dokka.location:org.jetbrains.skia.sksg////PointingToDeclaration/skiko/org.jetbrains.skia.sksg/index.html
+$dokka.location:org.jetbrains.skia.sksg/InvalidationController.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.sksg/-invalidation-controller/-companion/index.html
+$dokka.location:org.jetbrains.skia.sksg/InvalidationController///PointingToDeclaration/skiko/org.jetbrains.skia.sksg/-invalidation-controller/index.html
+$dokka.location:org.jetbrains.skia.sksg/InvalidationController/InvalidationController/#/PointingToDeclaration/skiko/org.jetbrains.skia.sksg/-invalidation-controller/-invalidation-controller.html
+$dokka.location:org.jetbrains.skia.sksg/InvalidationController/bounds/#/PointingToDeclaration/skiko/org.jetbrains.skia.sksg/-invalidation-controller/bounds.html
+$dokka.location:org.jetbrains.skia.sksg/InvalidationController/invalidate/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia.sksg/-invalidation-controller/invalidate.html
+$dokka.location:org.jetbrains.skia.sksg/InvalidationController/reset/#/PointingToDeclaration/skiko/org.jetbrains.skia.sksg/-invalidation-controller/reset.html
+$dokka.location:org.jetbrains.skia.svg////PointingToDeclaration/skiko/org.jetbrains.skia.svg/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGCanvas///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-canvas/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGCanvas/make/#org.jetbrains.skia.Rect#org.jetbrains.skia.WStream#kotlin.Boolean#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-canvas/make.html
+$dokka.location:org.jetbrains.skia.svg/SVGCanvas/make/#org.jetbrains.skia.Rect#org.jetbrains.skia.WStream/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-canvas/make.html
+$dokka.location:org.jetbrains.skia.svg/SVGContainer.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-container/-companion/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGContainer///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-container/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGDOM.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-d-o-m/-companion/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGDOM///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-d-o-m/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGDOM/SVGDOM/#org.jetbrains.skia.Data/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-d-o-m/-s-v-g-d-o-m.html
+$dokka.location:org.jetbrains.skia.svg/SVGDOM/containerSize/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-d-o-m/container-size.html
+$dokka.location:org.jetbrains.skia.svg/SVGDOM/render/#org.jetbrains.skia.Canvas/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-d-o-m/render.html
+$dokka.location:org.jetbrains.skia.svg/SVGDOM/root/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-d-o-m/root.html
+$dokka.location:org.jetbrains.skia.svg/SVGDOM/setContainerSize/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-d-o-m/set-container-size.html
+$dokka.location:org.jetbrains.skia.svg/SVGDOM/setContainerSize/#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-d-o-m/set-container-size.html
+$dokka.location:org.jetbrains.skia.svg/SVGLength.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length/-companion/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLength///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLength/SVGLength/#kotlin.Float#org.jetbrains.skia.svg.SVGLengthUnit/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length/-s-v-g-length.html
+$dokka.location:org.jetbrains.skia.svg/SVGLength/SVGLength/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length/-s-v-g-length.html
+$dokka.location:org.jetbrains.skia.svg/SVGLength/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length/equals.html
+$dokka.location:org.jetbrains.skia.svg/SVGLength/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length/hash-code.html
+$dokka.location:org.jetbrains.skia.svg/SVGLength/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length/to-string.html
+$dokka.location:org.jetbrains.skia.svg/SVGLength/unit/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length/unit.html
+$dokka.location:org.jetbrains.skia.svg/SVGLength/value/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length/value.html
+$dokka.location:org.jetbrains.skia.svg/SVGLength/withUnit/#org.jetbrains.skia.svg.SVGLengthUnit/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length/with-unit.html
+$dokka.location:org.jetbrains.skia.svg/SVGLength/withValue/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length/with-value.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/SVGLengthContext/#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/-s-v-g-length-context.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/SVGLengthContext/#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/-s-v-g-length-context.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/dpi/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/dpi.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/equals.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/hash-code.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/height/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/height.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/resolve/#org.jetbrains.skia.svg.SVGLength#org.jetbrains.skia.svg.SVGLengthType/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/resolve.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/resolveRect/#org.jetbrains.skia.svg.SVGLength#org.jetbrains.skia.svg.SVGLength#org.jetbrains.skia.svg.SVGLength#org.jetbrains.skia.svg.SVGLength/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/resolve-rect.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/to-string.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/width/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/width.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/withDpi/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/with-dpi.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/withHeight/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/with-height.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthContext/withWidth/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-context/with-width.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthType.HORIZONTAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-type/-h-o-r-i-z-o-n-t-a-l/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthType.OTHER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-type/-o-t-h-e-r/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthType.VERTICAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-type/-v-e-r-t-i-c-a-l/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthType///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-type/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthType/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-type/value-of.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthType/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-type/values.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit.CM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/-c-m/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit.EMS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/-e-m-s/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit.EXS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/-e-x-s/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit.IN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/-i-n/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit.MM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/-m-m/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit.NUMBER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/-n-u-m-b-e-r/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit.PC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/-p-c/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit.PERCENTAGE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/-p-e-r-c-e-n-t-a-g-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit.PT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/-p-t/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit.PX///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/-p-x/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/value-of.html
+$dokka.location:org.jetbrains.skia.svg/SVGLengthUnit/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-length-unit/values.html
+$dokka.location:org.jetbrains.skia.svg/SVGNode.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-node/-companion/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGNode///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-node/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGNode/tag/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-node/tag.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/-companion/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio/SVGPreserveAspectRatio/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/-s-v-g-preserve-aspect-ratio.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio/SVGPreserveAspectRatio/#org.jetbrains.skia.svg.SVGPreserveAspectRatioAlign#org.jetbrains.skia.svg.SVGPreserveAspectRatioScale/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/-s-v-g-preserve-aspect-ratio.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio/SVGPreserveAspectRatio/#org.jetbrains.skia.svg.SVGPreserveAspectRatioAlign/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/-s-v-g-preserve-aspect-ratio.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio/SVGPreserveAspectRatio/#org.jetbrains.skia.svg.SVGPreserveAspectRatioScale/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/-s-v-g-preserve-aspect-ratio.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio/align/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/align.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/equals.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/hash-code.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio/scale/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/scale.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/to-string.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio/withAlign/#org.jetbrains.skia.svg.SVGPreserveAspectRatioAlign/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/with-align.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatio/withScale/#org.jetbrains.skia.svg.SVGPreserveAspectRatioScale/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio/with-scale.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/-companion/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign.NONE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/-n-o-n-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign.XMAX_YMAX///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/-x-m-a-x_-y-m-a-x/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign.XMAX_YMID///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/-x-m-a-x_-y-m-i-d/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign.XMAX_YMIN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/-x-m-a-x_-y-m-i-n/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign.XMID_YMAX///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/-x-m-i-d_-y-m-a-x/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign.XMID_YMID///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/-x-m-i-d_-y-m-i-d/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign.XMID_YMIN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/-x-m-i-d_-y-m-i-n/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign.XMIN_YMAX///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/-x-m-i-n_-y-m-a-x/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign.XMIN_YMID///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/-x-m-i-n_-y-m-i-d/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign.XMIN_YMIN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/-x-m-i-n_-y-m-i-n/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/value-of.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioAlign/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-align/values.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioScale.MEET///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-scale/-m-e-e-t/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioScale.SLICE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-scale/-s-l-i-c-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioScale///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-scale/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioScale/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-scale/value-of.html
+$dokka.location:org.jetbrains.skia.svg/SVGPreserveAspectRatioScale/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-preserve-aspect-ratio-scale/values.html
+$dokka.location:org.jetbrains.skia.svg/SVGSVG.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-s-v-g/-companion/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGSVG///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-s-v-g/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGSVG/getIntrinsicSize/#org.jetbrains.skia.svg.SVGLengthContext/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-s-v-g/get-intrinsic-size.html
+$dokka.location:org.jetbrains.skia.svg/SVGSVG/height/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-s-v-g/height.html
+$dokka.location:org.jetbrains.skia.svg/SVGSVG/preserveAspectRatio/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-s-v-g/preserve-aspect-ratio.html
+$dokka.location:org.jetbrains.skia.svg/SVGSVG/setY/#org.jetbrains.skia.svg.SVGLength/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-s-v-g/set-y.html
+$dokka.location:org.jetbrains.skia.svg/SVGSVG/viewBox/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-s-v-g/view-box.html
+$dokka.location:org.jetbrains.skia.svg/SVGSVG/width/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-s-v-g/width.html
+$dokka.location:org.jetbrains.skia.svg/SVGSVG/x/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-s-v-g/x.html
+$dokka.location:org.jetbrains.skia.svg/SVGSVG/y/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-s-v-g/y.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.CIRCLE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-c-i-r-c-l-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.CLIP_PATH///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-c-l-i-p_-p-a-t-h/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.DEFS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-d-e-f-s/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.ELLIPSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-e-l-l-i-p-s-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_BLEND///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-b-l-e-n-d/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_COLOR_MATRIX///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-c-o-l-o-r_-m-a-t-r-i-x/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_COMPOSITE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-c-o-m-p-o-s-i-t-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_DIFFUSE_LIGHTING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-d-i-f-f-u-s-e_-l-i-g-h-t-i-n-g/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_DISPLACEMENT_MAP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-d-i-s-p-l-a-c-e-m-e-n-t_-m-a-p/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_DISTANT_LIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-d-i-s-t-a-n-t_-l-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_FLOOD///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-f-l-o-o-d/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_GAUSSIAN_BLUR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-g-a-u-s-s-i-a-n_-b-l-u-r/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_IMAGE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-i-m-a-g-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_MORPHOLOGY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-m-o-r-p-h-o-l-o-g-y/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_OFFSET///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-o-f-f-s-e-t/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_POINT_LIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-p-o-i-n-t_-l-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_SPECULAR_LIGHTING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-s-p-e-c-u-l-a-r_-l-i-g-h-t-i-n-g/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_SPOT_LIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-s-p-o-t_-l-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FE_TURBULENCE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-e_-t-u-r-b-u-l-e-n-c-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.FILTER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-f-i-l-t-e-r/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.G///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-g/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.IMAGE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-i-m-a-g-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.LINE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-l-i-n-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.LINEAR_GRADIENT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-l-i-n-e-a-r_-g-r-a-d-i-e-n-t/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.MASK///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-m-a-s-k/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.PATH///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-p-a-t-h/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.PATTERN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-p-a-t-t-e-r-n/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.POLYGON///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-p-o-l-y-g-o-n/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.POLYLINE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-p-o-l-y-l-i-n-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.RADIAL_GRADIENT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-r-a-d-i-a-l_-g-r-a-d-i-e-n-t/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.RECT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-r-e-c-t/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.STOP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-s-t-o-p/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.SVG///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-s-v-g/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.TEXT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-t-e-x-t/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.TEXTPATH///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-t-e-x-t-p-a-t-h/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.TEXT_LITERAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-t-e-x-t_-l-i-t-e-r-a-l/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.TSPAN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-t-s-p-a-n/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag.USE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia.svg/-s-v-g-tag/-u-s-e/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-tag/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-tag/value-of.html
+$dokka.location:org.jetbrains.skia.svg/SVGTag/values/#/PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-tag/values.html
+$dokka.location:org.jetbrains.skia.svg/SVGTransformableNode.Companion///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-transformable-node/-companion/index.html
+$dokka.location:org.jetbrains.skia.svg/SVGTransformableNode///PointingToDeclaration/skiko/org.jetbrains.skia.svg/-s-v-g-transformable-node/index.html
+$dokka.location:org.jetbrains.skia////PointingToDeclaration/skiko/org.jetbrains.skia/index.html
+$dokka.location:org.jetbrains.skia//LANG/#/PointingToDeclaration/skiko/org.jetbrains.skia/-l-a-n-g.html
+$dokka.location:org.jetbrains.skia//makeFromFile/org.jetbrains.skia.Typeface.Companion#kotlin.String#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/[native]make-from-file.html
+$dokka.location:org.jetbrains.skia//makeFromFileName/org.jetbrains.skia.Data.Companion#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia/[native]make-from-file-name.html
+$dokka.location:org.jetbrains.skia//toIPoint/#kotlin.Long/PointingToDeclaration/skiko/org.jetbrains.skia/to-i-point.html
+$dokka.location:org.jetbrains.skia//useContext/org.jetbrains.skia.DirectContext#kotlin.Function1[org.jetbrains.skia.DirectContext,TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/skiko/org.jetbrains.skia/use-context.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMethod.KEEP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-animation-disposal-method/-k-e-e-p/index.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMethod.RESTORE_BG_COLOR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-animation-disposal-method/-r-e-s-t-o-r-e_-b-g_-c-o-l-o-r/index.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMethod.RESTORE_PREVIOUS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-animation-disposal-method/-r-e-s-t-o-r-e_-p-r-e-v-i-o-u-s/index.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMethod.UNUSED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-animation-disposal-method/-u-n-u-s-e-d/index.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMethod///PointingToDeclaration/skiko/org.jetbrains.skia/-animation-disposal-method/index.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMethod/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-disposal-method/value-of.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMethod/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-disposal-method/values.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMode.KEEP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-animation-disposal-mode/-k-e-e-p/index.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMode.RESTORE_BG_COLOR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-animation-disposal-mode/-r-e-s-t-o-r-e_-b-g_-c-o-l-o-r/index.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMode.RESTORE_PREVIOUS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-animation-disposal-mode/-r-e-s-t-o-r-e_-p-r-e-v-i-o-u-s/index.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMode.UNUSED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-animation-disposal-mode/-u-n-u-s-e-d/index.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMode///PointingToDeclaration/skiko/org.jetbrains.skia/-animation-disposal-mode/index.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-disposal-mode/value-of.html
+$dokka.location:org.jetbrains.skia/AnimationDisposalMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-disposal-mode/values.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/-companion/index.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo///PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/index.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/AnimationFrameInfo/#kotlin.Int#kotlin.Int#kotlin.Boolean#org.jetbrains.skia.ColorAlphaType#kotlin.Boolean#org.jetbrains.skia.AnimationDisposalMode#org.jetbrains.skia.BlendMode#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/-animation-frame-info.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/alphaType/#/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/alpha-type.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/blendMode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/blend-mode.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/disposalMethod/#/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/disposal-method.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/duration/#/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/duration.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/equals.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/hash-code.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/isFullyReceived/#/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/is-fully-received.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/isHasAlphaWithinBounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/is-has-alpha-within-bounds.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/requiredFrame/#/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/required-frame.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/to-string.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/withAlphaType/#org.jetbrains.skia.ColorAlphaType/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/with-alpha-type.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/withBlendMode/#org.jetbrains.skia.BlendMode/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/with-blend-mode.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/withDisposalMethod/#org.jetbrains.skia.AnimationDisposalMode/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/with-disposal-method.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/withDuration/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/with-duration.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/withFrameRect/#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/with-frame-rect.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/withFullyReceived/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/with-fully-received.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/withHasAlphaWithinBounds/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/with-has-alpha-within-bounds.html
+$dokka.location:org.jetbrains.skia/AnimationFrameInfo/withRequiredFrame/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-animation-frame-info/with-required-frame.html
+$dokka.location:org.jetbrains.skia/ArrayDecoder///PointingToDeclaration/skiko/org.jetbrains.skia/-array-decoder/index.html
+$dokka.location:org.jetbrains.skia/ArrayDecoder/ArrayDecoder/#org.jetbrains.skia.impl.NativePointer#org.jetbrains.skia.impl.NativePointer/PointingToDeclaration/skiko/org.jetbrains.skia/-array-decoder/-array-decoder.html
+$dokka.location:org.jetbrains.skia/ArrayDecoder/dispose/#/PointingToDeclaration/skiko/org.jetbrains.skia/-array-decoder/dispose.html
+$dokka.location:org.jetbrains.skia/ArrayDecoder/release/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-array-decoder/release.html
+$dokka.location:org.jetbrains.skia/ArrayDecoder/size/#/PointingToDeclaration/skiko/org.jetbrains.skia/-array-decoder/size.html
+$dokka.location:org.jetbrains.skia/BackendRenderTarget.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-backend-render-target/-companion/index.html
+$dokka.location:org.jetbrains.skia/BackendRenderTarget.Companion/makeDirect3D/#kotlin.Int#kotlin.Int#org.jetbrains.skia.impl.NativePointer#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-backend-render-target/-companion/make-direct3-d.html
+$dokka.location:org.jetbrains.skia/BackendRenderTarget.Companion/makeGL/#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-backend-render-target/-companion/make-g-l.html
+$dokka.location:org.jetbrains.skia/BackendRenderTarget.Companion/makeMetal/#kotlin.Int#kotlin.Int#org.jetbrains.skia.impl.NativePointer/PointingToDeclaration/skiko/org.jetbrains.skia/-backend-render-target/-companion/make-metal.html
+$dokka.location:org.jetbrains.skia/BackendRenderTarget///PointingToDeclaration/skiko/org.jetbrains.skia/-backend-render-target/index.html
+$dokka.location:org.jetbrains.skia/Bitmap.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/-companion/index.html
+$dokka.location:org.jetbrains.skia/Bitmap.Companion/makeFromImage/#org.jetbrains.skia.Image#org.jetbrains.skia.DirectContext/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/-companion/make-from-image.html
+$dokka.location:org.jetbrains.skia/Bitmap.Companion/makeFromImage/#org.jetbrains.skia.Image/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/-companion/make-from-image.html
+$dokka.location:org.jetbrains.skia/Bitmap///PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/index.html
+$dokka.location:org.jetbrains.skia/Bitmap/Bitmap/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/-bitmap.html
+$dokka.location:org.jetbrains.skia/Bitmap/allocN32Pixels/#kotlin.Int#kotlin.Int#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/alloc-n32-pixels.html
+$dokka.location:org.jetbrains.skia/Bitmap/allocPixels/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/alloc-pixels.html
+$dokka.location:org.jetbrains.skia/Bitmap/allocPixels/#org.jetbrains.skia.ImageInfo#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/alloc-pixels.html
+$dokka.location:org.jetbrains.skia/Bitmap/allocPixels/#org.jetbrains.skia.ImageInfo/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/alloc-pixels.html
+$dokka.location:org.jetbrains.skia/Bitmap/allocPixelsFlags/#org.jetbrains.skia.ImageInfo#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/alloc-pixels-flags.html
+$dokka.location:org.jetbrains.skia/Bitmap/bounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/bounds.html
+$dokka.location:org.jetbrains.skia/Bitmap/computeByteSize/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/compute-byte-size.html
+$dokka.location:org.jetbrains.skia/Bitmap/computeIsOpaque/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/compute-is-opaque.html
+$dokka.location:org.jetbrains.skia/Bitmap/drawsNothing/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/draws-nothing.html
+$dokka.location:org.jetbrains.skia/Bitmap/erase/#kotlin.Int#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/erase.html
+$dokka.location:org.jetbrains.skia/Bitmap/erase/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/erase.html
+$dokka.location:org.jetbrains.skia/Bitmap/extractAlpha/#org.jetbrains.skia.Bitmap#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/extract-alpha.html
+$dokka.location:org.jetbrains.skia/Bitmap/extractAlpha/#org.jetbrains.skia.Bitmap/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/extract-alpha.html
+$dokka.location:org.jetbrains.skia/Bitmap/extractSubset/#org.jetbrains.skia.Bitmap#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/extract-subset.html
+$dokka.location:org.jetbrains.skia/Bitmap/generationId/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/generation-id.html
+$dokka.location:org.jetbrains.skia/Bitmap/getAlphaf/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/get-alphaf.html
+$dokka.location:org.jetbrains.skia/Bitmap/getColor/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/get-color.html
+$dokka.location:org.jetbrains.skia/Bitmap/imageInfo/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/image-info.html
+$dokka.location:org.jetbrains.skia/Bitmap/installPixels/#kotlin.ByteArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/install-pixels.html
+$dokka.location:org.jetbrains.skia/Bitmap/installPixels/#org.jetbrains.skia.ImageInfo#kotlin.ByteArray?#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/install-pixels.html
+$dokka.location:org.jetbrains.skia/Bitmap/isImmutable/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/is-immutable.html
+$dokka.location:org.jetbrains.skia/Bitmap/isNull/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/is-null.html
+$dokka.location:org.jetbrains.skia/Bitmap/isReadyToDraw/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/is-ready-to-draw.html
+$dokka.location:org.jetbrains.skia/Bitmap/makeClone/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/make-clone.html
+$dokka.location:org.jetbrains.skia/Bitmap/makeShader/#org.jetbrains.skia.FilterTileMode#org.jetbrains.skia.FilterTileMode#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/make-shader.html
+$dokka.location:org.jetbrains.skia/Bitmap/makeShader/#org.jetbrains.skia.FilterTileMode#org.jetbrains.skia.FilterTileMode#org.jetbrains.skia.SamplingMode#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/make-shader.html
+$dokka.location:org.jetbrains.skia/Bitmap/makeShader/#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/make-shader.html
+$dokka.location:org.jetbrains.skia/Bitmap/notifyPixelsChanged/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/notify-pixels-changed.html
+$dokka.location:org.jetbrains.skia/Bitmap/peekPixels/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/peek-pixels.html
+$dokka.location:org.jetbrains.skia/Bitmap/pixelRef/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/pixel-ref.html
+$dokka.location:org.jetbrains.skia/Bitmap/pixelRefOrigin/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/pixel-ref-origin.html
+$dokka.location:org.jetbrains.skia/Bitmap/readPixels/#org.jetbrains.skia.ImageInfo#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/read-pixels.html
+$dokka.location:org.jetbrains.skia/Bitmap/reset/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/reset.html
+$dokka.location:org.jetbrains.skia/Bitmap/rowBytes/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/row-bytes.html
+$dokka.location:org.jetbrains.skia/Bitmap/rowBytesAsPixels/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/row-bytes-as-pixels.html
+$dokka.location:org.jetbrains.skia/Bitmap/setAlphaType/#org.jetbrains.skia.ColorAlphaType/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/set-alpha-type.html
+$dokka.location:org.jetbrains.skia/Bitmap/setImageInfo/#org.jetbrains.skia.ImageInfo#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/set-image-info.html
+$dokka.location:org.jetbrains.skia/Bitmap/setImageInfo/#org.jetbrains.skia.ImageInfo/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/set-image-info.html
+$dokka.location:org.jetbrains.skia/Bitmap/setImmutable/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/set-immutable.html
+$dokka.location:org.jetbrains.skia/Bitmap/setPixelRef/#org.jetbrains.skia.PixelRef?#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/set-pixel-ref.html
+$dokka.location:org.jetbrains.skia/Bitmap/subset/#/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/subset.html
+$dokka.location:org.jetbrains.skia/Bitmap/swap/#org.jetbrains.skia.Bitmap/PointingToDeclaration/skiko/org.jetbrains.skia/-bitmap/swap.html
+$dokka.location:org.jetbrains.skia/BlendMode.CLEAR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-c-l-e-a-r/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.COLOR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-c-o-l-o-r/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.COLOR_BURN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-c-o-l-o-r_-b-u-r-n/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.COLOR_DODGE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-c-o-l-o-r_-d-o-d-g-e/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.DARKEN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-d-a-r-k-e-n/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.DIFFERENCE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-d-i-f-f-e-r-e-n-c-e/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.DST///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-d-s-t/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.DST_ATOP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-d-s-t_-a-t-o-p/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.DST_IN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-d-s-t_-i-n/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.DST_OUT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-d-s-t_-o-u-t/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.DST_OVER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-d-s-t_-o-v-e-r/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.EXCLUSION///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-e-x-c-l-u-s-i-o-n/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.HARD_LIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-h-a-r-d_-l-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.HUE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-h-u-e/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.LIGHTEN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-l-i-g-h-t-e-n/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.LUMINOSITY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-l-u-m-i-n-o-s-i-t-y/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.MODULATE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-m-o-d-u-l-a-t-e/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.MULTIPLY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-m-u-l-t-i-p-l-y/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.OVERLAY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-o-v-e-r-l-a-y/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.PLUS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-p-l-u-s/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.SATURATION///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-s-a-t-u-r-a-t-i-o-n/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.SCREEN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-s-c-r-e-e-n/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.SOFT_LIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-s-o-f-t_-l-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.SRC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-s-r-c/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.SRC_ATOP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-s-r-c_-a-t-o-p/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.SRC_IN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-s-r-c_-i-n/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.SRC_OUT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-s-r-c_-o-u-t/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.SRC_OVER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-s-r-c_-o-v-e-r/index.html
+$dokka.location:org.jetbrains.skia/BlendMode.XOR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-blend-mode/-x-o-r/index.html
+$dokka.location:org.jetbrains.skia/BlendMode///PointingToDeclaration/skiko/org.jetbrains.skia/-blend-mode/index.html
+$dokka.location:org.jetbrains.skia/BlendMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-blend-mode/value-of.html
+$dokka.location:org.jetbrains.skia/BlendMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-blend-mode/values.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/index.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/DONE/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/-d-o-n-e.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/WORD_IDEO/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/-w-o-r-d_-i-d-e-o.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/WORD_IDEO_LIMIT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/-w-o-r-d_-i-d-e-o_-l-i-m-i-t.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/WORD_KANA/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/-w-o-r-d_-k-a-n-a.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/WORD_KANA_LIMIT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/-w-o-r-d_-k-a-n-a_-l-i-m-i-t.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/WORD_LETTER/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/-w-o-r-d_-l-e-t-t-e-r.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/WORD_LETTER_LIMIT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/-w-o-r-d_-l-e-t-t-e-r_-l-i-m-i-t.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/WORD_NONE/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/-w-o-r-d_-n-o-n-e.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/WORD_NONE_LIMIT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/-w-o-r-d_-n-o-n-e_-l-i-m-i-t.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/WORD_NUMBER/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/-w-o-r-d_-n-u-m-b-e-r.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/WORD_NUMBER_LIMIT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/-w-o-r-d_-n-u-m-b-e-r_-l-i-m-i-t.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/makeCharacterInstance/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/make-character-instance.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/makeLineInstance/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/make-line-instance.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/makeSentenceInstance/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/make-sentence-instance.html
+$dokka.location:org.jetbrains.skia/BreakIterator.Companion/makeWordInstance/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/-companion/make-word-instance.html
+$dokka.location:org.jetbrains.skia/BreakIterator///PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/index.html
+$dokka.location:org.jetbrains.skia/BreakIterator/clone/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/clone.html
+$dokka.location:org.jetbrains.skia/BreakIterator/close/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/close.html
+$dokka.location:org.jetbrains.skia/BreakIterator/current/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/current.html
+$dokka.location:org.jetbrains.skia/BreakIterator/first/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/first.html
+$dokka.location:org.jetbrains.skia/BreakIterator/following/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/following.html
+$dokka.location:org.jetbrains.skia/BreakIterator/isBoundary/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/is-boundary.html
+$dokka.location:org.jetbrains.skia/BreakIterator/last/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/last.html
+$dokka.location:org.jetbrains.skia/BreakIterator/next/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/next.html
+$dokka.location:org.jetbrains.skia/BreakIterator/next/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/next.html
+$dokka.location:org.jetbrains.skia/BreakIterator/preceding/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/preceding.html
+$dokka.location:org.jetbrains.skia/BreakIterator/previous/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/previous.html
+$dokka.location:org.jetbrains.skia/BreakIterator/ruleStatus/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/rule-status.html
+$dokka.location:org.jetbrains.skia/BreakIterator/ruleStatuses/#/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/rule-statuses.html
+$dokka.location:org.jetbrains.skia/BreakIterator/setText/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia/-break-iterator/set-text.html
+$dokka.location:org.jetbrains.skia/Canvas.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/-companion/index.html
+$dokka.location:org.jetbrains.skia/Canvas///PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/index.html
+$dokka.location:org.jetbrains.skia/Canvas/Canvas/#org.jetbrains.skia.Bitmap#org.jetbrains.skia.SurfaceProps/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/-canvas.html
+$dokka.location:org.jetbrains.skia/Canvas/clear/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clear.html
+$dokka.location:org.jetbrains.skia/Canvas/clipPath/#org.jetbrains.skia.Path#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-path.html
+$dokka.location:org.jetbrains.skia/Canvas/clipPath/#org.jetbrains.skia.Path#org.jetbrains.skia.ClipMode#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-path.html
+$dokka.location:org.jetbrains.skia/Canvas/clipPath/#org.jetbrains.skia.Path#org.jetbrains.skia.ClipMode/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-path.html
+$dokka.location:org.jetbrains.skia/Canvas/clipPath/#org.jetbrains.skia.Path/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-path.html
+$dokka.location:org.jetbrains.skia/Canvas/clipRRect/#org.jetbrains.skia.RRect#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-r-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/clipRRect/#org.jetbrains.skia.RRect#org.jetbrains.skia.ClipMode#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-r-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/clipRRect/#org.jetbrains.skia.RRect#org.jetbrains.skia.ClipMode/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-r-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/clipRRect/#org.jetbrains.skia.RRect/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-r-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/clipRect/#org.jetbrains.skia.Rect#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/clipRect/#org.jetbrains.skia.Rect#org.jetbrains.skia.ClipMode#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/clipRect/#org.jetbrains.skia.Rect#org.jetbrains.skia.ClipMode/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/clipRect/#org.jetbrains.skia.Rect/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/clipRegion/#org.jetbrains.skia.Region#org.jetbrains.skia.ClipMode/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-region.html
+$dokka.location:org.jetbrains.skia/Canvas/clipRegion/#org.jetbrains.skia.Region/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/clip-region.html
+$dokka.location:org.jetbrains.skia/Canvas/concat/#org.jetbrains.skia.Matrix33/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/concat.html
+$dokka.location:org.jetbrains.skia/Canvas/concat/#org.jetbrains.skia.Matrix44/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/concat.html
+$dokka.location:org.jetbrains.skia/Canvas/drawArc/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Boolean#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-arc.html
+$dokka.location:org.jetbrains.skia/Canvas/drawCircle/#kotlin.Float#kotlin.Float#kotlin.Float#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-circle.html
+$dokka.location:org.jetbrains.skia/Canvas/drawDRRect/#org.jetbrains.skia.RRect#org.jetbrains.skia.RRect#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-d-r-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/drawDrawable/#org.jetbrains.skia.Drawable#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-drawable.html
+$dokka.location:org.jetbrains.skia/Canvas/drawDrawable/#org.jetbrains.skia.Drawable#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-drawable.html
+$dokka.location:org.jetbrains.skia/Canvas/drawDrawable/#org.jetbrains.skia.Drawable/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-drawable.html
+$dokka.location:org.jetbrains.skia/Canvas/drawImage/#org.jetbrains.skia.Image#kotlin.Float#kotlin.Float#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-image.html
+$dokka.location:org.jetbrains.skia/Canvas/drawImage/#org.jetbrains.skia.Image#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-image.html
+$dokka.location:org.jetbrains.skia/Canvas/drawImageNine/#org.jetbrains.skia.Image#org.jetbrains.skia.IRect#org.jetbrains.skia.Rect#org.jetbrains.skia.FilterMode#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-image-nine.html
+$dokka.location:org.jetbrains.skia/Canvas/drawImageRect/#org.jetbrains.skia.Image#org.jetbrains.skia.Rect#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-image-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/drawImageRect/#org.jetbrains.skia.Image#org.jetbrains.skia.Rect#org.jetbrains.skia.Rect#org.jetbrains.skia.Paint?#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-image-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/drawImageRect/#org.jetbrains.skia.Image#org.jetbrains.skia.Rect#org.jetbrains.skia.Rect#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-image-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/drawImageRect/#org.jetbrains.skia.Image#org.jetbrains.skia.Rect#org.jetbrains.skia.Rect#org.jetbrains.skia.SamplingMode#org.jetbrains.skia.Paint?#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-image-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/drawImageRect/#org.jetbrains.skia.Image#org.jetbrains.skia.Rect#org.jetbrains.skia.Rect/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-image-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/drawImageRect/#org.jetbrains.skia.Image#org.jetbrains.skia.Rect/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-image-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/drawLine/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-line.html
+$dokka.location:org.jetbrains.skia/Canvas/drawLines/#kotlin.Array[org.jetbrains.skia.Point]#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-lines.html
+$dokka.location:org.jetbrains.skia/Canvas/drawLines/#kotlin.FloatArray#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-lines.html
+$dokka.location:org.jetbrains.skia/Canvas/drawOval/#org.jetbrains.skia.Rect#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-oval.html
+$dokka.location:org.jetbrains.skia/Canvas/drawPaint/#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-paint.html
+$dokka.location:org.jetbrains.skia/Canvas/drawPatch/#kotlin.Array[org.jetbrains.skia.Point]#kotlin.IntArray#kotlin.Array[org.jetbrains.skia.Point]?#org.jetbrains.skia.BlendMode#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-patch.html
+$dokka.location:org.jetbrains.skia/Canvas/drawPath/#org.jetbrains.skia.Path#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-path.html
+$dokka.location:org.jetbrains.skia/Canvas/drawPicture/#org.jetbrains.skia.Picture#org.jetbrains.skia.Matrix33?#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-picture.html
+$dokka.location:org.jetbrains.skia/Canvas/drawPoint/#kotlin.Float#kotlin.Float#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-point.html
+$dokka.location:org.jetbrains.skia/Canvas/drawPoints/#kotlin.Array[org.jetbrains.skia.Point]#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-points.html
+$dokka.location:org.jetbrains.skia/Canvas/drawPoints/#kotlin.FloatArray#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-points.html
+$dokka.location:org.jetbrains.skia/Canvas/drawPolygon/#kotlin.Array[org.jetbrains.skia.Point]#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-polygon.html
+$dokka.location:org.jetbrains.skia/Canvas/drawPolygon/#kotlin.FloatArray#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-polygon.html
+$dokka.location:org.jetbrains.skia/Canvas/drawRRect/#org.jetbrains.skia.RRect#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-r-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/drawRect/#org.jetbrains.skia.Rect#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-rect.html
+$dokka.location:org.jetbrains.skia/Canvas/drawRectShadow/#org.jetbrains.skia.Rect#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-rect-shadow.html
+$dokka.location:org.jetbrains.skia/Canvas/drawRectShadow/#org.jetbrains.skia.Rect#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-rect-shadow.html
+$dokka.location:org.jetbrains.skia/Canvas/drawRectShadowNoclip/#org.jetbrains.skia.Rect#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-rect-shadow-noclip.html
+$dokka.location:org.jetbrains.skia/Canvas/drawRegion/#org.jetbrains.skia.Region#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-region.html
+$dokka.location:org.jetbrains.skia/Canvas/drawString/#kotlin.String#kotlin.Float#kotlin.Float#org.jetbrains.skia.Font?#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-string.html
+$dokka.location:org.jetbrains.skia/Canvas/drawTextBlob/#org.jetbrains.skia.TextBlob#kotlin.Float#kotlin.Float#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-text-blob.html
+$dokka.location:org.jetbrains.skia/Canvas/drawTextLine/#org.jetbrains.skia.TextLine#kotlin.Float#kotlin.Float#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-text-line.html
+$dokka.location:org.jetbrains.skia/Canvas/drawTriangleFan/#kotlin.Array[org.jetbrains.skia.Point]#kotlin.IntArray?#kotlin.Array[org.jetbrains.skia.Point]?#kotlin.ShortArray?#org.jetbrains.skia.BlendMode#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-triangle-fan.html
+$dokka.location:org.jetbrains.skia/Canvas/drawTriangleStrip/#kotlin.Array[org.jetbrains.skia.Point]#kotlin.IntArray?#kotlin.Array[org.jetbrains.skia.Point]?#kotlin.ShortArray?#org.jetbrains.skia.BlendMode#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-triangle-strip.html
+$dokka.location:org.jetbrains.skia/Canvas/drawTriangles/#kotlin.Array[org.jetbrains.skia.Point]#kotlin.IntArray?#kotlin.Array[org.jetbrains.skia.Point]?#kotlin.ShortArray?#org.jetbrains.skia.BlendMode#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-triangles.html
+$dokka.location:org.jetbrains.skia/Canvas/drawVertices/#org.jetbrains.skia.VertexMode#kotlin.FloatArray#kotlin.IntArray?#kotlin.FloatArray?#kotlin.ShortArray?#org.jetbrains.skia.BlendMode#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/draw-vertices.html
+$dokka.location:org.jetbrains.skia/Canvas/localToDevice/#/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/local-to-device.html
+$dokka.location:org.jetbrains.skia/Canvas/localToDeviceAsMatrix33/#/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/local-to-device-as-matrix33.html
+$dokka.location:org.jetbrains.skia/Canvas/readPixels/#org.jetbrains.skia.Bitmap#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/read-pixels.html
+$dokka.location:org.jetbrains.skia/Canvas/resetMatrix/#/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/reset-matrix.html
+$dokka.location:org.jetbrains.skia/Canvas/restore/#/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/restore.html
+$dokka.location:org.jetbrains.skia/Canvas/restoreToCount/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/restore-to-count.html
+$dokka.location:org.jetbrains.skia/Canvas/rotate/#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/rotate.html
+$dokka.location:org.jetbrains.skia/Canvas/rotate/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/rotate.html
+$dokka.location:org.jetbrains.skia/Canvas/save/#/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/save.html
+$dokka.location:org.jetbrains.skia/Canvas/saveCount/#/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/save-count.html
+$dokka.location:org.jetbrains.skia/Canvas/saveLayer/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/save-layer.html
+$dokka.location:org.jetbrains.skia/Canvas/saveLayer/#org.jetbrains.skia.Rect?#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/save-layer.html
+$dokka.location:org.jetbrains.skia/Canvas/scale/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/scale.html
+$dokka.location:org.jetbrains.skia/Canvas/setMatrix/#org.jetbrains.skia.Matrix33/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/set-matrix.html
+$dokka.location:org.jetbrains.skia/Canvas/skew/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/skew.html
+$dokka.location:org.jetbrains.skia/Canvas/translate/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/translate.html
+$dokka.location:org.jetbrains.skia/Canvas/writePixels/#org.jetbrains.skia.Bitmap#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-canvas/write-pixels.html
+$dokka.location:org.jetbrains.skia/ClipMode.DIFFERENCE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-clip-mode/-d-i-f-f-e-r-e-n-c-e/index.html
+$dokka.location:org.jetbrains.skia/ClipMode.INTERSECT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-clip-mode/-i-n-t-e-r-s-e-c-t/index.html
+$dokka.location:org.jetbrains.skia/ClipMode///PointingToDeclaration/skiko/org.jetbrains.skia/-clip-mode/index.html
+$dokka.location:org.jetbrains.skia/ClipMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-clip-mode/value-of.html
+$dokka.location:org.jetbrains.skia/ClipMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-clip-mode/values.html
+$dokka.location:org.jetbrains.skia/Codec.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-codec/-companion/index.html
+$dokka.location:org.jetbrains.skia/Codec.Companion/makeFromData/#org.jetbrains.skia.Data?/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/-companion/make-from-data.html
+$dokka.location:org.jetbrains.skia/Codec///PointingToDeclaration/skiko/org.jetbrains.skia/-codec/index.html
+$dokka.location:org.jetbrains.skia/Codec/encodedImageFormat/#/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/encoded-image-format.html
+$dokka.location:org.jetbrains.skia/Codec/encodedOrigin/#/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/encoded-origin.html
+$dokka.location:org.jetbrains.skia/Codec/frameCount/#/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/frame-count.html
+$dokka.location:org.jetbrains.skia/Codec/framesInfo/#/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/frames-info.html
+$dokka.location:org.jetbrains.skia/Codec/getFrameInfo/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/get-frame-info.html
+$dokka.location:org.jetbrains.skia/Codec/imageInfo/#/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/image-info.html
+$dokka.location:org.jetbrains.skia/Codec/readPixels/#/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/read-pixels.html
+$dokka.location:org.jetbrains.skia/Codec/readPixels/#org.jetbrains.skia.Bitmap?#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/read-pixels.html
+$dokka.location:org.jetbrains.skia/Codec/readPixels/#org.jetbrains.skia.Bitmap?#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/read-pixels.html
+$dokka.location:org.jetbrains.skia/Codec/readPixels/#org.jetbrains.skia.Bitmap?/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/read-pixels.html
+$dokka.location:org.jetbrains.skia/Codec/repetitionCount/#/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/repetition-count.html
+$dokka.location:org.jetbrains.skia/Codec/size/#/PointingToDeclaration/skiko/org.jetbrains.skia/-codec/size.html
+$dokka.location:org.jetbrains.skia/Color///PointingToDeclaration/skiko/org.jetbrains.skia/-color/index.html
+$dokka.location:org.jetbrains.skia/Color/BLACK/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color/-b-l-a-c-k.html
+$dokka.location:org.jetbrains.skia/Color/BLUE/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color/-b-l-u-e.html
+$dokka.location:org.jetbrains.skia/Color/CYAN/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color/-c-y-a-n.html
+$dokka.location:org.jetbrains.skia/Color/GREEN/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color/-g-r-e-e-n.html
+$dokka.location:org.jetbrains.skia/Color/MAGENTA/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color/-m-a-g-e-n-t-a.html
+$dokka.location:org.jetbrains.skia/Color/RED/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color/-r-e-d.html
+$dokka.location:org.jetbrains.skia/Color/TRANSPARENT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color/-t-r-a-n-s-p-a-r-e-n-t.html
+$dokka.location:org.jetbrains.skia/Color/WHITE/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color/-w-h-i-t-e.html
+$dokka.location:org.jetbrains.skia/Color/YELLOW/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color/-y-e-l-l-o-w.html
+$dokka.location:org.jetbrains.skia/Color/getA/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color/get-a.html
+$dokka.location:org.jetbrains.skia/Color/getB/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color/get-b.html
+$dokka.location:org.jetbrains.skia/Color/getG/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color/get-g.html
+$dokka.location:org.jetbrains.skia/Color/getR/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color/get-r.html
+$dokka.location:org.jetbrains.skia/Color/makeARGB/#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color/make-a-r-g-b.html
+$dokka.location:org.jetbrains.skia/Color/makeLerp/#kotlin.Int#kotlin.Int#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-color/make-lerp.html
+$dokka.location:org.jetbrains.skia/Color/makeRGB/#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color/make-r-g-b.html
+$dokka.location:org.jetbrains.skia/Color/withA/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color/with-a.html
+$dokka.location:org.jetbrains.skia/Color/withB/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color/with-b.html
+$dokka.location:org.jetbrains.skia/Color/withG/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color/with-g.html
+$dokka.location:org.jetbrains.skia/Color/withR/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color/with-r.html
+$dokka.location:org.jetbrains.skia/Color4f.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/-companion/index.html
+$dokka.location:org.jetbrains.skia/Color4f.Companion/flattenArray/#kotlin.Array[org.jetbrains.skia.Color4f]/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/-companion/flatten-array.html
+$dokka.location:org.jetbrains.skia/Color4f///PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/index.html
+$dokka.location:org.jetbrains.skia/Color4f/Color4f/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/-color4f.html
+$dokka.location:org.jetbrains.skia/Color4f/Color4f/#kotlin.FloatArray/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/-color4f.html
+$dokka.location:org.jetbrains.skia/Color4f/Color4f/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/-color4f.html
+$dokka.location:org.jetbrains.skia/Color4f/a/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/a.html
+$dokka.location:org.jetbrains.skia/Color4f/b/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/b.html
+$dokka.location:org.jetbrains.skia/Color4f/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/equals.html
+$dokka.location:org.jetbrains.skia/Color4f/flatten/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/flatten.html
+$dokka.location:org.jetbrains.skia/Color4f/g/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/g.html
+$dokka.location:org.jetbrains.skia/Color4f/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/hash-code.html
+$dokka.location:org.jetbrains.skia/Color4f/makeLerp/#org.jetbrains.skia.Color4f#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/make-lerp.html
+$dokka.location:org.jetbrains.skia/Color4f/r/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/r.html
+$dokka.location:org.jetbrains.skia/Color4f/toColor/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/to-color.html
+$dokka.location:org.jetbrains.skia/Color4f/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/to-string.html
+$dokka.location:org.jetbrains.skia/Color4f/withA/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/with-a.html
+$dokka.location:org.jetbrains.skia/Color4f/withB/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/with-b.html
+$dokka.location:org.jetbrains.skia/Color4f/withG/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/with-g.html
+$dokka.location:org.jetbrains.skia/Color4f/withR/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-color4f/with-r.html
+$dokka.location:org.jetbrains.skia/ColorAlphaType.OPAQUE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-alpha-type/-o-p-a-q-u-e/index.html
+$dokka.location:org.jetbrains.skia/ColorAlphaType.PREMUL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-alpha-type/-p-r-e-m-u-l/index.html
+$dokka.location:org.jetbrains.skia/ColorAlphaType.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-alpha-type/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skia/ColorAlphaType.UNPREMUL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-alpha-type/-u-n-p-r-e-m-u-l/index.html
+$dokka.location:org.jetbrains.skia/ColorAlphaType///PointingToDeclaration/skiko/org.jetbrains.skia/-color-alpha-type/index.html
+$dokka.location:org.jetbrains.skia/ColorAlphaType/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-color-alpha-type/value-of.html
+$dokka.location:org.jetbrains.skia/ColorAlphaType/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-alpha-type/values.html
+$dokka.location:org.jetbrains.skia/ColorChannel.A///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-channel/-a/index.html
+$dokka.location:org.jetbrains.skia/ColorChannel.B///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-channel/-b/index.html
+$dokka.location:org.jetbrains.skia/ColorChannel.G///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-channel/-g/index.html
+$dokka.location:org.jetbrains.skia/ColorChannel.R///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-channel/-r/index.html
+$dokka.location:org.jetbrains.skia/ColorChannel///PointingToDeclaration/skiko/org.jetbrains.skia/-color-channel/index.html
+$dokka.location:org.jetbrains.skia/ColorChannel/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-color-channel/value-of.html
+$dokka.location:org.jetbrains.skia/ColorChannel/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-channel/values.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/index.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/luma/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/luma.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/makeBlend/#kotlin.Int#org.jetbrains.skia.BlendMode/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/make-blend.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/makeComposed/#org.jetbrains.skia.ColorFilter?#org.jetbrains.skia.ColorFilter?/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/make-composed.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/makeHSLAMatrix/#org.jetbrains.skia.ColorMatrix/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/make-h-s-l-a-matrix.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/makeHighContrast/#kotlin.Boolean#org.jetbrains.skia.InversionMode#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/make-high-contrast.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/makeLerp/#org.jetbrains.skia.ColorFilter?#org.jetbrains.skia.ColorFilter?#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/make-lerp.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/makeLighting/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/make-lighting.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/makeMatrix/#org.jetbrains.skia.ColorMatrix/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/make-matrix.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/makeOverdraw/#kotlin.IntArray/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/make-overdraw.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/makeTable/#kotlin.ByteArray/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/make-table.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/makeTableARGB/#kotlin.ByteArray?#kotlin.ByteArray?#kotlin.ByteArray?#kotlin.ByteArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/make-table-a-r-g-b.html
+$dokka.location:org.jetbrains.skia/ColorFilter.Companion/sRGBToLinearGamma/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/-companion/s-r-g-b-to-linear-gamma.html
+$dokka.location:org.jetbrains.skia/ColorFilter///PointingToDeclaration/skiko/org.jetbrains.skia/-color-filter/index.html
+$dokka.location:org.jetbrains.skia/ColorInfo.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/-companion/index.html
+$dokka.location:org.jetbrains.skia/ColorInfo.Companion/DEFAULT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/-companion/-d-e-f-a-u-l-t.html
+$dokka.location:org.jetbrains.skia/ColorInfo///PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/index.html
+$dokka.location:org.jetbrains.skia/ColorInfo/ColorInfo/#org.jetbrains.skia.ColorType#org.jetbrains.skia.ColorAlphaType#org.jetbrains.skia.ColorSpace?/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/-color-info.html
+$dokka.location:org.jetbrains.skia/ColorInfo/alphaType/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/alpha-type.html
+$dokka.location:org.jetbrains.skia/ColorInfo/bytesPerPixel/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/bytes-per-pixel.html
+$dokka.location:org.jetbrains.skia/ColorInfo/colorSpace/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/color-space.html
+$dokka.location:org.jetbrains.skia/ColorInfo/colorType/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/color-type.html
+$dokka.location:org.jetbrains.skia/ColorInfo/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/equals.html
+$dokka.location:org.jetbrains.skia/ColorInfo/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/hash-code.html
+$dokka.location:org.jetbrains.skia/ColorInfo/isGammaCloseToSRGB/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/is-gamma-close-to-s-r-g-b.html
+$dokka.location:org.jetbrains.skia/ColorInfo/isOpaque/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/is-opaque.html
+$dokka.location:org.jetbrains.skia/ColorInfo/shiftPerPixel/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/shift-per-pixel.html
+$dokka.location:org.jetbrains.skia/ColorInfo/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/to-string.html
+$dokka.location:org.jetbrains.skia/ColorInfo/withAlphaType/#org.jetbrains.skia.ColorAlphaType/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/with-alpha-type.html
+$dokka.location:org.jetbrains.skia/ColorInfo/withColorSpace/#org.jetbrains.skia.ColorSpace?/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/with-color-space.html
+$dokka.location:org.jetbrains.skia/ColorInfo/withColorType/#org.jetbrains.skia.ColorType/PointingToDeclaration/skiko/org.jetbrains.skia/-color-info/with-color-type.html
+$dokka.location:org.jetbrains.skia/ColorMatrix///PointingToDeclaration/skiko/org.jetbrains.skia/-color-matrix/index.html
+$dokka.location:org.jetbrains.skia/ColorMatrix/ColorMatrix/#kotlin.FloatArray/PointingToDeclaration/skiko/org.jetbrains.skia/-color-matrix/-color-matrix.html
+$dokka.location:org.jetbrains.skia/ColorMatrix/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-color-matrix/equals.html
+$dokka.location:org.jetbrains.skia/ColorMatrix/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-matrix/hash-code.html
+$dokka.location:org.jetbrains.skia/ColorMatrix/mat/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-matrix/mat.html
+$dokka.location:org.jetbrains.skia/ColorMatrix/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-matrix/to-string.html
+$dokka.location:org.jetbrains.skia/ColorSpace.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-color-space/-companion/index.html
+$dokka.location:org.jetbrains.skia/ColorSpace.Companion/displayP3/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-space/-companion/display-p3.html
+$dokka.location:org.jetbrains.skia/ColorSpace.Companion/sRGB/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-space/-companion/s-r-g-b.html
+$dokka.location:org.jetbrains.skia/ColorSpace.Companion/sRGBLinear/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-space/-companion/s-r-g-b-linear.html
+$dokka.location:org.jetbrains.skia/ColorSpace///PointingToDeclaration/skiko/org.jetbrains.skia/-color-space/index.html
+$dokka.location:org.jetbrains.skia/ColorSpace/convert/#org.jetbrains.skia.ColorSpace?#org.jetbrains.skia.Color4f/PointingToDeclaration/skiko/org.jetbrains.skia/-color-space/convert.html
+$dokka.location:org.jetbrains.skia/ColorSpace/isGammaCloseToSRGB/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-space/is-gamma-close-to-s-r-g-b.html
+$dokka.location:org.jetbrains.skia/ColorSpace/isGammaLinear/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-space/is-gamma-linear.html
+$dokka.location:org.jetbrains.skia/ColorSpace/isSRGB/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-space/is-s-r-g-b.html
+$dokka.location:org.jetbrains.skia/ColorType.A16_FLOAT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-a16_-f-l-o-a-t/index.html
+$dokka.location:org.jetbrains.skia/ColorType.A16_UNORM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-a16_-u-n-o-r-m/index.html
+$dokka.location:org.jetbrains.skia/ColorType.ALPHA_8///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-a-l-p-h-a_8/index.html
+$dokka.location:org.jetbrains.skia/ColorType.ARGB_4444///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-a-r-g-b_4444/index.html
+$dokka.location:org.jetbrains.skia/ColorType.BGRA_1010102///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-b-g-r-a_1010102/index.html
+$dokka.location:org.jetbrains.skia/ColorType.BGRA_8888///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-b-g-r-a_8888/index.html
+$dokka.location:org.jetbrains.skia/ColorType.BGR_101010X///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-b-g-r_101010-x/index.html
+$dokka.location:org.jetbrains.skia/ColorType.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/-companion/index.html
+$dokka.location:org.jetbrains.skia/ColorType.Companion/N32/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/-companion/-n32.html
+$dokka.location:org.jetbrains.skia/ColorType.GRAY_8///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-g-r-a-y_8/index.html
+$dokka.location:org.jetbrains.skia/ColorType.R16G16B16A16_UNORM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r16-g16-b16-a16_-u-n-o-r-m/index.html
+$dokka.location:org.jetbrains.skia/ColorType.R16G16_FLOAT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r16-g16_-f-l-o-a-t/index.html
+$dokka.location:org.jetbrains.skia/ColorType.R16G16_UNORM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r16-g16_-u-n-o-r-m/index.html
+$dokka.location:org.jetbrains.skia/ColorType.R8G8_UNORM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r8-g8_-u-n-o-r-m/index.html
+$dokka.location:org.jetbrains.skia/ColorType.RGBA_1010102///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r-g-b-a_1010102/index.html
+$dokka.location:org.jetbrains.skia/ColorType.RGBA_8888///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r-g-b-a_8888/index.html
+$dokka.location:org.jetbrains.skia/ColorType.RGBA_F16///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r-g-b-a_-f16/index.html
+$dokka.location:org.jetbrains.skia/ColorType.RGBA_F16NORM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r-g-b-a_-f16-n-o-r-m/index.html
+$dokka.location:org.jetbrains.skia/ColorType.RGBA_F32///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r-g-b-a_-f32/index.html
+$dokka.location:org.jetbrains.skia/ColorType.RGB_101010X///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r-g-b_101010-x/index.html
+$dokka.location:org.jetbrains.skia/ColorType.RGB_565///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r-g-b_565/index.html
+$dokka.location:org.jetbrains.skia/ColorType.RGB_888X///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-r-g-b_888-x/index.html
+$dokka.location:org.jetbrains.skia/ColorType.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-color-type/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skia/ColorType///PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/index.html
+$dokka.location:org.jetbrains.skia/ColorType/bytesPerPixel/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/bytes-per-pixel.html
+$dokka.location:org.jetbrains.skia/ColorType/computeOffset/#kotlin.Int#kotlin.Int#kotlin.Long/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/compute-offset.html
+$dokka.location:org.jetbrains.skia/ColorType/getA/#kotlin.Byte/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-a.html
+$dokka.location:org.jetbrains.skia/ColorType/getA/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-a.html
+$dokka.location:org.jetbrains.skia/ColorType/getA/#kotlin.Short/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-a.html
+$dokka.location:org.jetbrains.skia/ColorType/getB/#kotlin.Byte/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-b.html
+$dokka.location:org.jetbrains.skia/ColorType/getB/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-b.html
+$dokka.location:org.jetbrains.skia/ColorType/getB/#kotlin.Short/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-b.html
+$dokka.location:org.jetbrains.skia/ColorType/getG/#kotlin.Byte/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-g.html
+$dokka.location:org.jetbrains.skia/ColorType/getG/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-g.html
+$dokka.location:org.jetbrains.skia/ColorType/getG/#kotlin.Short/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-g.html
+$dokka.location:org.jetbrains.skia/ColorType/getR/#kotlin.Byte/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-r.html
+$dokka.location:org.jetbrains.skia/ColorType/getR/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-r.html
+$dokka.location:org.jetbrains.skia/ColorType/getR/#kotlin.Short/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/get-r.html
+$dokka.location:org.jetbrains.skia/ColorType/isAlwaysOpaque/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/is-always-opaque.html
+$dokka.location:org.jetbrains.skia/ColorType/shiftPerPixel/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/shift-per-pixel.html
+$dokka.location:org.jetbrains.skia/ColorType/validateAlphaType/#org.jetbrains.skia.ColorAlphaType/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/validate-alpha-type.html
+$dokka.location:org.jetbrains.skia/ColorType/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/value-of.html
+$dokka.location:org.jetbrains.skia/ColorType/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-color-type/values.html
+$dokka.location:org.jetbrains.skia/ContentChangeMode.DISCARD///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-content-change-mode/-d-i-s-c-a-r-d/index.html
+$dokka.location:org.jetbrains.skia/ContentChangeMode.RETAIN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-content-change-mode/-r-e-t-a-i-n/index.html
+$dokka.location:org.jetbrains.skia/ContentChangeMode///PointingToDeclaration/skiko/org.jetbrains.skia/-content-change-mode/index.html
+$dokka.location:org.jetbrains.skia/ContentChangeMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-content-change-mode/value-of.html
+$dokka.location:org.jetbrains.skia/ContentChangeMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-content-change-mode/values.html
+$dokka.location:org.jetbrains.skia/CubicResampler///PointingToDeclaration/skiko/org.jetbrains.skia/-cubic-resampler/index.html
+$dokka.location:org.jetbrains.skia/CubicResampler/CubicResampler/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-cubic-resampler/-cubic-resampler.html
+$dokka.location:org.jetbrains.skia/CubicResampler/_pack/#/PointingToDeclaration/skiko/org.jetbrains.skia/-cubic-resampler/_pack.html
+$dokka.location:org.jetbrains.skia/CubicResampler/_packedInt1/#/PointingToDeclaration/skiko/org.jetbrains.skia/-cubic-resampler/_packed-int1.html
+$dokka.location:org.jetbrains.skia/CubicResampler/_packedInt2/#/PointingToDeclaration/skiko/org.jetbrains.skia/-cubic-resampler/_packed-int2.html
+$dokka.location:org.jetbrains.skia/CubicResampler/b/#/PointingToDeclaration/skiko/org.jetbrains.skia/-cubic-resampler/b.html
+$dokka.location:org.jetbrains.skia/CubicResampler/c/#/PointingToDeclaration/skiko/org.jetbrains.skia/-cubic-resampler/c.html
+$dokka.location:org.jetbrains.skia/CubicResampler/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-cubic-resampler/equals.html
+$dokka.location:org.jetbrains.skia/CubicResampler/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-cubic-resampler/hash-code.html
+$dokka.location:org.jetbrains.skia/CubicResampler/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-cubic-resampler/to-string.html
+$dokka.location:org.jetbrains.skia/Data.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-data/-companion/index.html
+$dokka.location:org.jetbrains.skia/Data.Companion/makeEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-data/-companion/make-empty.html
+$dokka.location:org.jetbrains.skia/Data.Companion/makeFromBytes/#kotlin.ByteArray#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-data/-companion/make-from-bytes.html
+$dokka.location:org.jetbrains.skia/Data.Companion/makeUninitialized/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-data/-companion/make-uninitialized.html
+$dokka.location:org.jetbrains.skia/Data.Companion/makeWithoutCopy/#org.jetbrains.skia.impl.NativePointer#kotlin.Int#org.jetbrains.skia.impl.Managed/PointingToDeclaration/skiko/org.jetbrains.skia/-data/-companion/make-without-copy.html
+$dokka.location:org.jetbrains.skia/Data///PointingToDeclaration/skiko/org.jetbrains.skia/-data/index.html
+$dokka.location:org.jetbrains.skia/Data/bytes/#/PointingToDeclaration/skiko/org.jetbrains.skia/-data/bytes.html
+$dokka.location:org.jetbrains.skia/Data/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-data/equals.html
+$dokka.location:org.jetbrains.skia/Data/getBytes/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-data/get-bytes.html
+$dokka.location:org.jetbrains.skia/Data/makeCopy/#/PointingToDeclaration/skiko/org.jetbrains.skia/-data/make-copy.html
+$dokka.location:org.jetbrains.skia/Data/makeSubset/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-data/make-subset.html
+$dokka.location:org.jetbrains.skia/Data/size/#/PointingToDeclaration/skiko/org.jetbrains.skia/-data/size.html
+$dokka.location:org.jetbrains.skia/Data/writableData/#/PointingToDeclaration/skiko/org.jetbrains.skia/-data/writable-data.html
+$dokka.location:org.jetbrains.skia/DirectContext.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-direct-context/-companion/index.html
+$dokka.location:org.jetbrains.skia/DirectContext.Companion/makeDirect3D/#org.jetbrains.skia.impl.NativePointer#org.jetbrains.skia.impl.NativePointer#org.jetbrains.skia.impl.NativePointer/PointingToDeclaration/skiko/org.jetbrains.skia/-direct-context/-companion/make-direct3-d.html
+$dokka.location:org.jetbrains.skia/DirectContext.Companion/makeGL/#/PointingToDeclaration/skiko/org.jetbrains.skia/-direct-context/-companion/make-g-l.html
+$dokka.location:org.jetbrains.skia/DirectContext.Companion/makeMetal/#org.jetbrains.skia.impl.NativePointer#org.jetbrains.skia.impl.NativePointer/PointingToDeclaration/skiko/org.jetbrains.skia/-direct-context/-companion/make-metal.html
+$dokka.location:org.jetbrains.skia/DirectContext///PointingToDeclaration/skiko/org.jetbrains.skia/-direct-context/index.html
+$dokka.location:org.jetbrains.skia/DirectContext/abandon/#/PointingToDeclaration/skiko/org.jetbrains.skia/-direct-context/abandon.html
+$dokka.location:org.jetbrains.skia/DirectContext/flush/#/PointingToDeclaration/skiko/org.jetbrains.skia/-direct-context/flush.html
+$dokka.location:org.jetbrains.skia/DirectContext/resetAll/#/PointingToDeclaration/skiko/org.jetbrains.skia/-direct-context/reset-all.html
+$dokka.location:org.jetbrains.skia/DirectContext/resetGL/#kotlin.Array[org.jetbrains.skia.GLBackendState]/PointingToDeclaration/skiko/org.jetbrains.skia/-direct-context/reset-g-l.html
+$dokka.location:org.jetbrains.skia/DirectContext/resetGLAll/#/PointingToDeclaration/skiko/org.jetbrains.skia/-direct-context/reset-g-l-all.html
+$dokka.location:org.jetbrains.skia/DirectContext/submit/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-direct-context/submit.html
+$dokka.location:org.jetbrains.skia/Drawable.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/-companion/index.html
+$dokka.location:org.jetbrains.skia/Drawable///PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/index.html
+$dokka.location:org.jetbrains.skia/Drawable/Drawable/#/PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/-drawable.html
+$dokka.location:org.jetbrains.skia/Drawable/bounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/bounds.html
+$dokka.location:org.jetbrains.skia/Drawable/draw/#org.jetbrains.skia.Canvas?#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/draw.html
+$dokka.location:org.jetbrains.skia/Drawable/draw/#org.jetbrains.skia.Canvas?#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/draw.html
+$dokka.location:org.jetbrains.skia/Drawable/draw/#org.jetbrains.skia.Canvas?/PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/draw.html
+$dokka.location:org.jetbrains.skia/Drawable/generationId/#/PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/generation-id.html
+$dokka.location:org.jetbrains.skia/Drawable/makePictureSnapshot/#/PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/make-picture-snapshot.html
+$dokka.location:org.jetbrains.skia/Drawable/notifyDrawingChanged/#/PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/notify-drawing-changed.html
+$dokka.location:org.jetbrains.skia/Drawable/onDraw/#org.jetbrains.skia.Canvas?/PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/on-draw.html
+$dokka.location:org.jetbrains.skia/Drawable/onGetBounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-drawable/on-get-bounds.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.ASTC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-a-s-t-c/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.BMP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-b-m-p/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.DNG///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-d-n-g/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.GIF///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-g-i-f/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.HEIF///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-h-e-i-f/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.ICO///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-i-c-o/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.JPEG///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-j-p-e-g/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.KTX///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-k-t-x/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.PKM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-p-k-m/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.PNG///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-p-n-g/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.WBMP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-w-b-m-p/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat.WEBP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-image-format/-w-e-b-p/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat///PointingToDeclaration/skiko/org.jetbrains.skia/-encoded-image-format/index.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-encoded-image-format/value-of.html
+$dokka.location:org.jetbrains.skia/EncodedImageFormat/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-encoded-image-format/values.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin.BOTTOM_LEFT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-origin/-b-o-t-t-o-m_-l-e-f-t/index.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin.BOTTOM_RIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-origin/-b-o-t-t-o-m_-r-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin.LEFT_BOTTOM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-origin/-l-e-f-t_-b-o-t-t-o-m/index.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin.LEFT_TOP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-origin/-l-e-f-t_-t-o-p/index.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin.RIGHT_BOTTOM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-origin/-r-i-g-h-t_-b-o-t-t-o-m/index.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin.RIGHT_TOP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-origin/-r-i-g-h-t_-t-o-p/index.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin.TOP_LEFT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-origin/-t-o-p_-l-e-f-t/index.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin.TOP_RIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-origin/-t-o-p_-r-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin.UNUSED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-encoded-origin/-u-n-u-s-e-d/index.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin///PointingToDeclaration/skiko/org.jetbrains.skia/-encoded-origin/index.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin/swapsWidthHeight/#/PointingToDeclaration/skiko/org.jetbrains.skia/-encoded-origin/swaps-width-height.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin/toMatrix/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-encoded-origin/to-matrix.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-encoded-origin/value-of.html
+$dokka.location:org.jetbrains.skia/EncodedOrigin/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-encoded-origin/values.html
+$dokka.location:org.jetbrains.skia/ExternalSymbolName///PointingToDeclaration/skiko/org.jetbrains.skia/-external-symbol-name/index.html
+$dokka.location:org.jetbrains.skia/ExternalSymbolName/name/#/PointingToDeclaration/skiko/org.jetbrains.skia/-external-symbol-name/name.html
+$dokka.location:org.jetbrains.skia/FilterBlurMode.INNER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-blur-mode/-i-n-n-e-r/index.html
+$dokka.location:org.jetbrains.skia/FilterBlurMode.NORMAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-blur-mode/-n-o-r-m-a-l/index.html
+$dokka.location:org.jetbrains.skia/FilterBlurMode.OUTER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-blur-mode/-o-u-t-e-r/index.html
+$dokka.location:org.jetbrains.skia/FilterBlurMode.SOLID///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-blur-mode/-s-o-l-i-d/index.html
+$dokka.location:org.jetbrains.skia/FilterBlurMode///PointingToDeclaration/skiko/org.jetbrains.skia/-filter-blur-mode/index.html
+$dokka.location:org.jetbrains.skia/FilterBlurMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-blur-mode/value-of.html
+$dokka.location:org.jetbrains.skia/FilterBlurMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-blur-mode/values.html
+$dokka.location:org.jetbrains.skia/FilterMipmap///PointingToDeclaration/skiko/org.jetbrains.skia/-filter-mipmap/index.html
+$dokka.location:org.jetbrains.skia/FilterMipmap/FilterMipmap/#org.jetbrains.skia.FilterMode#org.jetbrains.skia.MipmapMode/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-mipmap/-filter-mipmap.html
+$dokka.location:org.jetbrains.skia/FilterMipmap/_pack/#/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-mipmap/_pack.html
+$dokka.location:org.jetbrains.skia/FilterMipmap/_packedInt1/#/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-mipmap/_packed-int1.html
+$dokka.location:org.jetbrains.skia/FilterMipmap/_packedInt2/#/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-mipmap/_packed-int2.html
+$dokka.location:org.jetbrains.skia/FilterMipmap/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-mipmap/equals.html
+$dokka.location:org.jetbrains.skia/FilterMipmap/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-mipmap/hash-code.html
+$dokka.location:org.jetbrains.skia/FilterMipmap/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-mipmap/to-string.html
+$dokka.location:org.jetbrains.skia/FilterMode.LINEAR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-mode/-l-i-n-e-a-r/index.html
+$dokka.location:org.jetbrains.skia/FilterMode.NEAREST///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-mode/-n-e-a-r-e-s-t/index.html
+$dokka.location:org.jetbrains.skia/FilterMode///PointingToDeclaration/skiko/org.jetbrains.skia/-filter-mode/index.html
+$dokka.location:org.jetbrains.skia/FilterMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-mode/value-of.html
+$dokka.location:org.jetbrains.skia/FilterMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-mode/values.html
+$dokka.location:org.jetbrains.skia/FilterQuality.HIGH///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-quality/-h-i-g-h/index.html
+$dokka.location:org.jetbrains.skia/FilterQuality.LOW///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-quality/-l-o-w/index.html
+$dokka.location:org.jetbrains.skia/FilterQuality.MEDIUM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-quality/-m-e-d-i-u-m/index.html
+$dokka.location:org.jetbrains.skia/FilterQuality.NONE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-quality/-n-o-n-e/index.html
+$dokka.location:org.jetbrains.skia/FilterQuality///PointingToDeclaration/skiko/org.jetbrains.skia/-filter-quality/index.html
+$dokka.location:org.jetbrains.skia/FilterQuality/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-quality/value-of.html
+$dokka.location:org.jetbrains.skia/FilterQuality/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-quality/values.html
+$dokka.location:org.jetbrains.skia/FilterTileMode.CLAMP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-tile-mode/-c-l-a-m-p/index.html
+$dokka.location:org.jetbrains.skia/FilterTileMode.DECAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-tile-mode/-d-e-c-a-l/index.html
+$dokka.location:org.jetbrains.skia/FilterTileMode.MIRROR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-tile-mode/-m-i-r-r-o-r/index.html
+$dokka.location:org.jetbrains.skia/FilterTileMode.REPEAT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-filter-tile-mode/-r-e-p-e-a-t/index.html
+$dokka.location:org.jetbrains.skia/FilterTileMode///PointingToDeclaration/skiko/org.jetbrains.skia/-filter-tile-mode/index.html
+$dokka.location:org.jetbrains.skia/FilterTileMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-tile-mode/value-of.html
+$dokka.location:org.jetbrains.skia/FilterTileMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-filter-tile-mode/values.html
+$dokka.location:org.jetbrains.skia/Font.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-font/-companion/index.html
+$dokka.location:org.jetbrains.skia/Font///PointingToDeclaration/skiko/org.jetbrains.skia/-font/index.html
+$dokka.location:org.jetbrains.skia/Font/Font/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/-font.html
+$dokka.location:org.jetbrains.skia/Font/Font/#org.jetbrains.skia.Typeface?#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-font/-font.html
+$dokka.location:org.jetbrains.skia/Font/Font/#org.jetbrains.skia.Typeface?#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-font/-font.html
+$dokka.location:org.jetbrains.skia/Font/Font/#org.jetbrains.skia.Typeface?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/-font.html
+$dokka.location:org.jetbrains.skia/Font/areBitmapsEmbedded/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/are-bitmaps-embedded.html
+$dokka.location:org.jetbrains.skia/Font/areMetricsLinear/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/are-metrics-linear.html
+$dokka.location:org.jetbrains.skia/Font/edging/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/edging.html
+$dokka.location:org.jetbrains.skia/Font/getBounds/#kotlin.ShortArray?#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-bounds.html
+$dokka.location:org.jetbrains.skia/Font/getBounds/#kotlin.ShortArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-bounds.html
+$dokka.location:org.jetbrains.skia/Font/getPath/#kotlin.Short/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-path.html
+$dokka.location:org.jetbrains.skia/Font/getPaths/#kotlin.ShortArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-paths.html
+$dokka.location:org.jetbrains.skia/Font/getPositions/#kotlin.ShortArray?#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-positions.html
+$dokka.location:org.jetbrains.skia/Font/getPositions/#kotlin.ShortArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-positions.html
+$dokka.location:org.jetbrains.skia/Font/getStringGlyphs/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-string-glyphs.html
+$dokka.location:org.jetbrains.skia/Font/getStringGlyphsCount/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-string-glyphs-count.html
+$dokka.location:org.jetbrains.skia/Font/getUTF32Glyph/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-u-t-f32-glyph.html
+$dokka.location:org.jetbrains.skia/Font/getUTF32Glyphs/#kotlin.IntArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-u-t-f32-glyphs.html
+$dokka.location:org.jetbrains.skia/Font/getWidths/#kotlin.ShortArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-widths.html
+$dokka.location:org.jetbrains.skia/Font/getXPositions/#kotlin.ShortArray?#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-x-positions.html
+$dokka.location:org.jetbrains.skia/Font/getXPositions/#kotlin.ShortArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/get-x-positions.html
+$dokka.location:org.jetbrains.skia/Font/hinting/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/hinting.html
+$dokka.location:org.jetbrains.skia/Font/isAutoHintingForced/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/is-auto-hinting-forced.html
+$dokka.location:org.jetbrains.skia/Font/isBaselineSnapped/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/is-baseline-snapped.html
+$dokka.location:org.jetbrains.skia/Font/isEmboldened/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/is-emboldened.html
+$dokka.location:org.jetbrains.skia/Font/isSubpixel/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/is-subpixel.html
+$dokka.location:org.jetbrains.skia/Font/makeWithSize/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-font/make-with-size.html
+$dokka.location:org.jetbrains.skia/Font/measureText/#kotlin.String?#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/measure-text.html
+$dokka.location:org.jetbrains.skia/Font/measureTextWidth/#kotlin.String?#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/measure-text-width.html
+$dokka.location:org.jetbrains.skia/Font/measureTextWidth/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/measure-text-width.html
+$dokka.location:org.jetbrains.skia/Font/metrics/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/metrics.html
+$dokka.location:org.jetbrains.skia/Font/scaleX/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/scale-x.html
+$dokka.location:org.jetbrains.skia/Font/setBitmapsEmbedded/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-font/set-bitmaps-embedded.html
+$dokka.location:org.jetbrains.skia/Font/setTypeface/#org.jetbrains.skia.Typeface?/PointingToDeclaration/skiko/org.jetbrains.skia/-font/set-typeface.html
+$dokka.location:org.jetbrains.skia/Font/size/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/size.html
+$dokka.location:org.jetbrains.skia/Font/skewX/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/skew-x.html
+$dokka.location:org.jetbrains.skia/Font/spacing/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/spacing.html
+$dokka.location:org.jetbrains.skia/Font/typeface/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/typeface.html
+$dokka.location:org.jetbrains.skia/Font/typefaceOrDefault/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font/typeface-or-default.html
+$dokka.location:org.jetbrains.skia/FontEdging.ALIAS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-font-edging/-a-l-i-a-s/index.html
+$dokka.location:org.jetbrains.skia/FontEdging.ANTI_ALIAS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-font-edging/-a-n-t-i_-a-l-i-a-s/index.html
+$dokka.location:org.jetbrains.skia/FontEdging.SUBPIXEL_ANTI_ALIAS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-font-edging/-s-u-b-p-i-x-e-l_-a-n-t-i_-a-l-i-a-s/index.html
+$dokka.location:org.jetbrains.skia/FontEdging///PointingToDeclaration/skiko/org.jetbrains.skia/-font-edging/index.html
+$dokka.location:org.jetbrains.skia/FontEdging/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-font-edging/value-of.html
+$dokka.location:org.jetbrains.skia/FontEdging/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-edging/values.html
+$dokka.location:org.jetbrains.skia/FontExtents///PointingToDeclaration/skiko/org.jetbrains.skia/-font-extents/index.html
+$dokka.location:org.jetbrains.skia/FontExtents/FontExtents/#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-font-extents/-font-extents.html
+$dokka.location:org.jetbrains.skia/FontExtents/ascender/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-extents/ascender.html
+$dokka.location:org.jetbrains.skia/FontExtents/ascenderAbs/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-extents/ascender-abs.html
+$dokka.location:org.jetbrains.skia/FontExtents/descender/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-extents/descender.html
+$dokka.location:org.jetbrains.skia/FontExtents/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-font-extents/equals.html
+$dokka.location:org.jetbrains.skia/FontExtents/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-extents/hash-code.html
+$dokka.location:org.jetbrains.skia/FontExtents/lineGap/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-extents/line-gap.html
+$dokka.location:org.jetbrains.skia/FontExtents/lineHeight/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-extents/line-height.html
+$dokka.location:org.jetbrains.skia/FontExtents/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-extents/to-string.html
+$dokka.location:org.jetbrains.skia/FontFamilyName///PointingToDeclaration/skiko/org.jetbrains.skia/-font-family-name/index.html
+$dokka.location:org.jetbrains.skia/FontFamilyName/FontFamilyName/#kotlin.String#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-font-family-name/-font-family-name.html
+$dokka.location:org.jetbrains.skia/FontFamilyName/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-font-family-name/equals.html
+$dokka.location:org.jetbrains.skia/FontFamilyName/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-family-name/hash-code.html
+$dokka.location:org.jetbrains.skia/FontFamilyName/language/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-family-name/language.html
+$dokka.location:org.jetbrains.skia/FontFamilyName/name/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-family-name/name.html
+$dokka.location:org.jetbrains.skia/FontFamilyName/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-family-name/to-string.html
+$dokka.location:org.jetbrains.skia/FontFeature.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-companion/index.html
+$dokka.location:org.jetbrains.skia/FontFeature.Companion/EMPTY/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-companion/-e-m-p-t-y.html
+$dokka.location:org.jetbrains.skia/FontFeature.Companion/GLOBAL_END/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-companion/-g-l-o-b-a-l_-e-n-d.html
+$dokka.location:org.jetbrains.skia/FontFeature.Companion/GLOBAL_START/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-companion/-g-l-o-b-a-l_-s-t-a-r-t.html
+$dokka.location:org.jetbrains.skia/FontFeature.Companion/_featurePattern/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-companion/_feature-pattern.html
+$dokka.location:org.jetbrains.skia/FontFeature.Companion/_splitPattern/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-companion/_split-pattern.html
+$dokka.location:org.jetbrains.skia/FontFeature.Companion/parse/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-companion/parse.html
+$dokka.location:org.jetbrains.skia/FontFeature.Companion/parseOne/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-companion/parse-one.html
+$dokka.location:org.jetbrains.skia/FontFeature.Companion/parseW3/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-companion/parse-w3.html
+$dokka.location:org.jetbrains.skia/FontFeature///PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/index.html
+$dokka.location:org.jetbrains.skia/FontFeature/FontFeature/#kotlin.Int#kotlin.Int#kotlin.UInt#kotlin.UInt/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-font-feature.html
+$dokka.location:org.jetbrains.skia/FontFeature/FontFeature/#kotlin.String#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-font-feature.html
+$dokka.location:org.jetbrains.skia/FontFeature/FontFeature/#kotlin.String#kotlin.Int#kotlin.UInt#kotlin.UInt/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-font-feature.html
+$dokka.location:org.jetbrains.skia/FontFeature/FontFeature/#kotlin.String#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-font-feature.html
+$dokka.location:org.jetbrains.skia/FontFeature/FontFeature/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/-font-feature.html
+$dokka.location:org.jetbrains.skia/FontFeature/_tag/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/_tag.html
+$dokka.location:org.jetbrains.skia/FontFeature/end/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/end.html
+$dokka.location:org.jetbrains.skia/FontFeature/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/equals.html
+$dokka.location:org.jetbrains.skia/FontFeature/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/hash-code.html
+$dokka.location:org.jetbrains.skia/FontFeature/start/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/start.html
+$dokka.location:org.jetbrains.skia/FontFeature/tag/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/tag.html
+$dokka.location:org.jetbrains.skia/FontFeature/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/to-string.html
+$dokka.location:org.jetbrains.skia/FontFeature/value/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-feature/value.html
+$dokka.location:org.jetbrains.skia/FontHinting.FULL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-font-hinting/-f-u-l-l/index.html
+$dokka.location:org.jetbrains.skia/FontHinting.NONE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-font-hinting/-n-o-n-e/index.html
+$dokka.location:org.jetbrains.skia/FontHinting.NORMAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-font-hinting/-n-o-r-m-a-l/index.html
+$dokka.location:org.jetbrains.skia/FontHinting.SLIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-font-hinting/-s-l-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia/FontHinting///PointingToDeclaration/skiko/org.jetbrains.skia/-font-hinting/index.html
+$dokka.location:org.jetbrains.skia/FontHinting/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-font-hinting/value-of.html
+$dokka.location:org.jetbrains.skia/FontHinting/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-hinting/values.html
+$dokka.location:org.jetbrains.skia/FontMetrics.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/-companion/index.html
+$dokka.location:org.jetbrains.skia/FontMetrics///PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/index.html
+$dokka.location:org.jetbrains.skia/FontMetrics/FontMetrics/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float?#kotlin.Float?#kotlin.Float?#kotlin.Float?/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/-font-metrics.html
+$dokka.location:org.jetbrains.skia/FontMetrics/ascent/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/ascent.html
+$dokka.location:org.jetbrains.skia/FontMetrics/avgCharWidth/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/avg-char-width.html
+$dokka.location:org.jetbrains.skia/FontMetrics/bottom/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/bottom.html
+$dokka.location:org.jetbrains.skia/FontMetrics/capHeight/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/cap-height.html
+$dokka.location:org.jetbrains.skia/FontMetrics/descent/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/descent.html
+$dokka.location:org.jetbrains.skia/FontMetrics/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/equals.html
+$dokka.location:org.jetbrains.skia/FontMetrics/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/hash-code.html
+$dokka.location:org.jetbrains.skia/FontMetrics/height/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/height.html
+$dokka.location:org.jetbrains.skia/FontMetrics/leading/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/leading.html
+$dokka.location:org.jetbrains.skia/FontMetrics/maxCharWidth/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/max-char-width.html
+$dokka.location:org.jetbrains.skia/FontMetrics/strikeoutPosition/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/strikeout-position.html
+$dokka.location:org.jetbrains.skia/FontMetrics/strikeoutThickness/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/strikeout-thickness.html
+$dokka.location:org.jetbrains.skia/FontMetrics/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/to-string.html
+$dokka.location:org.jetbrains.skia/FontMetrics/top/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/top.html
+$dokka.location:org.jetbrains.skia/FontMetrics/underlinePosition/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/underline-position.html
+$dokka.location:org.jetbrains.skia/FontMetrics/underlineThickness/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/underline-thickness.html
+$dokka.location:org.jetbrains.skia/FontMetrics/xHeight/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/x-height.html
+$dokka.location:org.jetbrains.skia/FontMetrics/xMax/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/x-max.html
+$dokka.location:org.jetbrains.skia/FontMetrics/xMin/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-metrics/x-min.html
+$dokka.location:org.jetbrains.skia/FontMgr.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/-companion/index.html
+$dokka.location:org.jetbrains.skia/FontMgr.Companion/default/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/-companion/default.html
+$dokka.location:org.jetbrains.skia/FontMgr///PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/index.html
+$dokka.location:org.jetbrains.skia/FontMgr/familiesCount/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/families-count.html
+$dokka.location:org.jetbrains.skia/FontMgr/getFamilyName/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/get-family-name.html
+$dokka.location:org.jetbrains.skia/FontMgr/makeFromData/#org.jetbrains.skia.Data?#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/make-from-data.html
+$dokka.location:org.jetbrains.skia/FontMgr/makeStyleSet/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/make-style-set.html
+$dokka.location:org.jetbrains.skia/FontMgr/matchFamiliesStyle/#kotlin.Array[kotlin.String?]#org.jetbrains.skia.FontStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/match-families-style.html
+$dokka.location:org.jetbrains.skia/FontMgr/matchFamiliesStyleCharacter/#kotlin.Array[kotlin.String?]#org.jetbrains.skia.FontStyle#kotlin.Array[kotlin.String]?#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/match-families-style-character.html
+$dokka.location:org.jetbrains.skia/FontMgr/matchFamily/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/match-family.html
+$dokka.location:org.jetbrains.skia/FontMgr/matchFamilyStyle/#kotlin.String?#org.jetbrains.skia.FontStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/match-family-style.html
+$dokka.location:org.jetbrains.skia/FontMgr/matchFamilyStyleCharacter/#kotlin.String?#org.jetbrains.skia.FontStyle#kotlin.Array[kotlin.String]?#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font-mgr/match-family-style-character.html
+$dokka.location:org.jetbrains.skia/FontSlant.ITALIC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-font-slant/-i-t-a-l-i-c/index.html
+$dokka.location:org.jetbrains.skia/FontSlant.OBLIQUE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-font-slant/-o-b-l-i-q-u-e/index.html
+$dokka.location:org.jetbrains.skia/FontSlant.UPRIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-font-slant/-u-p-r-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skia/FontSlant///PointingToDeclaration/skiko/org.jetbrains.skia/-font-slant/index.html
+$dokka.location:org.jetbrains.skia/FontSlant/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-font-slant/value-of.html
+$dokka.location:org.jetbrains.skia/FontSlant/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-slant/values.html
+$dokka.location:org.jetbrains.skia/FontStyle.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/-companion/index.html
+$dokka.location:org.jetbrains.skia/FontStyle.Companion/BOLD/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/-companion/-b-o-l-d.html
+$dokka.location:org.jetbrains.skia/FontStyle.Companion/BOLD_ITALIC/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/-companion/-b-o-l-d_-i-t-a-l-i-c.html
+$dokka.location:org.jetbrains.skia/FontStyle.Companion/ITALIC/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/-companion/-i-t-a-l-i-c.html
+$dokka.location:org.jetbrains.skia/FontStyle.Companion/NORMAL/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/-companion/-n-o-r-m-a-l.html
+$dokka.location:org.jetbrains.skia/FontStyle///PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/index.html
+$dokka.location:org.jetbrains.skia/FontStyle/FontStyle/#kotlin.Int#kotlin.Int#org.jetbrains.skia.FontSlant/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/-font-style.html
+$dokka.location:org.jetbrains.skia/FontStyle/_value/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/_value.html
+$dokka.location:org.jetbrains.skia/FontStyle/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/equals.html
+$dokka.location:org.jetbrains.skia/FontStyle/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/hash-code.html
+$dokka.location:org.jetbrains.skia/FontStyle/slant/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/slant.html
+$dokka.location:org.jetbrains.skia/FontStyle/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/to-string.html
+$dokka.location:org.jetbrains.skia/FontStyle/weight/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/weight.html
+$dokka.location:org.jetbrains.skia/FontStyle/width/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/width.html
+$dokka.location:org.jetbrains.skia/FontStyle/withSlant/#org.jetbrains.skia.FontSlant/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/with-slant.html
+$dokka.location:org.jetbrains.skia/FontStyle/withWeight/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/with-weight.html
+$dokka.location:org.jetbrains.skia/FontStyle/withWidth/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style/with-width.html
+$dokka.location:org.jetbrains.skia/FontStyleSet.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-font-style-set/-companion/index.html
+$dokka.location:org.jetbrains.skia/FontStyleSet.Companion/makeEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style-set/-companion/make-empty.html
+$dokka.location:org.jetbrains.skia/FontStyleSet///PointingToDeclaration/skiko/org.jetbrains.skia/-font-style-set/index.html
+$dokka.location:org.jetbrains.skia/FontStyleSet/count/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style-set/count.html
+$dokka.location:org.jetbrains.skia/FontStyleSet/getStyle/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style-set/get-style.html
+$dokka.location:org.jetbrains.skia/FontStyleSet/getStyleName/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style-set/get-style-name.html
+$dokka.location:org.jetbrains.skia/FontStyleSet/getTypeface/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style-set/get-typeface.html
+$dokka.location:org.jetbrains.skia/FontStyleSet/matchStyle/#org.jetbrains.skia.FontStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-font-style-set/match-style.html
+$dokka.location:org.jetbrains.skia/FontVariation.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/-companion/index.html
+$dokka.location:org.jetbrains.skia/FontVariation.Companion/EMPTY/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/-companion/-e-m-p-t-y.html
+$dokka.location:org.jetbrains.skia/FontVariation.Companion/parse/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/-companion/parse.html
+$dokka.location:org.jetbrains.skia/FontVariation.Companion/parseOne/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/-companion/parse-one.html
+$dokka.location:org.jetbrains.skia/FontVariation///PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/index.html
+$dokka.location:org.jetbrains.skia/FontVariation/FontVariation/#kotlin.Int#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/-font-variation.html
+$dokka.location:org.jetbrains.skia/FontVariation/FontVariation/#kotlin.String#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/-font-variation.html
+$dokka.location:org.jetbrains.skia/FontVariation/_tag/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/_tag.html
+$dokka.location:org.jetbrains.skia/FontVariation/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/equals.html
+$dokka.location:org.jetbrains.skia/FontVariation/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/hash-code.html
+$dokka.location:org.jetbrains.skia/FontVariation/tag/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/tag.html
+$dokka.location:org.jetbrains.skia/FontVariation/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/to-string.html
+$dokka.location:org.jetbrains.skia/FontVariation/value/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation/value.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis///PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/index.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/FontVariationAxis/#kotlin.Int#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/-font-variation-axis.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/FontVariationAxis/#kotlin.String#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/-font-variation-axis.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/FontVariationAxis/#kotlin.String#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/-font-variation-axis.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/_tag/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/_tag.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/defaultValue/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/default-value.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/equals.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/hash-code.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/isHidden/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/is-hidden.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/maxValue/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/max-value.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/minValue/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/min-value.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/tag/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/tag.html
+$dokka.location:org.jetbrains.skia/FontVariationAxis/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-variation-axis/to-string.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/index.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion/BLACK/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/-b-l-a-c-k.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion/BOLD/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/-b-o-l-d.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion/EXTRA_BLACK/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/-e-x-t-r-a_-b-l-a-c-k.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion/EXTRA_BOLD/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/-e-x-t-r-a_-b-o-l-d.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion/EXTRA_LIGHT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/-e-x-t-r-a_-l-i-g-h-t.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion/INVISIBLE/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/-i-n-v-i-s-i-b-l-e.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion/LIGHT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/-l-i-g-h-t.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion/MEDIUM/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/-m-e-d-i-u-m.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion/NORMAL/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/-n-o-r-m-a-l.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion/SEMI_BOLD/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/-s-e-m-i_-b-o-l-d.html
+$dokka.location:org.jetbrains.skia/FontWeight.Companion/THIN/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/-companion/-t-h-i-n.html
+$dokka.location:org.jetbrains.skia/FontWeight///PointingToDeclaration/skiko/org.jetbrains.skia/-font-weight/index.html
+$dokka.location:org.jetbrains.skia/FontWidth.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-font-width/-companion/index.html
+$dokka.location:org.jetbrains.skia/FontWidth.Companion/CONDENSED/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-width/-companion/-c-o-n-d-e-n-s-e-d.html
+$dokka.location:org.jetbrains.skia/FontWidth.Companion/EXPANDED/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-width/-companion/-e-x-p-a-n-d-e-d.html
+$dokka.location:org.jetbrains.skia/FontWidth.Companion/EXTRA_CONDENSED/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-width/-companion/-e-x-t-r-a_-c-o-n-d-e-n-s-e-d.html
+$dokka.location:org.jetbrains.skia/FontWidth.Companion/EXTRA_EXPANDED/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-width/-companion/-e-x-t-r-a_-e-x-p-a-n-d-e-d.html
+$dokka.location:org.jetbrains.skia/FontWidth.Companion/NORMAL/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-width/-companion/-n-o-r-m-a-l.html
+$dokka.location:org.jetbrains.skia/FontWidth.Companion/SEMI_CONDENSED/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-width/-companion/-s-e-m-i_-c-o-n-d-e-n-s-e-d.html
+$dokka.location:org.jetbrains.skia/FontWidth.Companion/SEMI_EXPANDED/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-width/-companion/-s-e-m-i_-e-x-p-a-n-d-e-d.html
+$dokka.location:org.jetbrains.skia/FontWidth.Companion/ULTRA_CONDENSED/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-width/-companion/-u-l-t-r-a_-c-o-n-d-e-n-s-e-d.html
+$dokka.location:org.jetbrains.skia/FontWidth.Companion/ULTRA_EXPANDED/#/PointingToDeclaration/skiko/org.jetbrains.skia/-font-width/-companion/-u-l-t-r-a_-e-x-p-a-n-d-e-d.html
+$dokka.location:org.jetbrains.skia/FontWidth///PointingToDeclaration/skiko/org.jetbrains.skia/-font-width/index.html
+$dokka.location:org.jetbrains.skia/FourByteTag.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-four-byte-tag/-companion/index.html
+$dokka.location:org.jetbrains.skia/FourByteTag.Companion/fromString/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-four-byte-tag/-companion/from-string.html
+$dokka.location:org.jetbrains.skia/FourByteTag.Companion/toString/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-four-byte-tag/-companion/to-string.html
+$dokka.location:org.jetbrains.skia/FourByteTag///PointingToDeclaration/skiko/org.jetbrains.skia/-four-byte-tag/index.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/index.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_ALPHA/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-a-l-p-h-a.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_ALPHA16/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-a-l-p-h-a16.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_ALPHA16F/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-a-l-p-h-a16-f.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_ALPHA16I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-a-l-p-h-a16-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_ALPHA16UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-a-l-p-h-a16-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_ALPHA32F/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-a-l-p-h-a32-f.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_ALPHA32I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-a-l-p-h-a32-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_ALPHA32UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-a-l-p-h-a32-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_ALPHA8/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-a-l-p-h-a8.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_ALPHA8I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-a-l-p-h-a8-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_ALPHA8UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-a-l-p-h-a8-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_BGRA/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-b-g-r-a.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_BGRA8/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-b-g-r-a8.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_BLUE/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-b-l-u-e.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_DEPTH24_STENCIL8/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-d-e-p-t-h24_-s-t-e-n-c-i-l8.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_DEPTH_COMPONENT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-d-e-p-t-h_-c-o-m-p-o-n-e-n-t.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_DEPTH_COMPONENT16/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-d-e-p-t-h_-c-o-m-p-o-n-e-n-t16.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_DEPTH_STENCIL/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-d-e-p-t-h_-s-t-e-n-c-i-l.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_GREEN/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-g-r-e-e-n.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_LUMINANCE/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-l-u-m-i-n-a-n-c-e.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_LUMINANCE16F/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-l-u-m-i-n-a-n-c-e16-f.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_LUMINANCE8/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-l-u-m-i-n-a-n-c-e8.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_LUMINANCE_ALPHA/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-l-u-m-i-n-a-n-c-e_-a-l-p-h-a.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_R16/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r16.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_R16F/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r16-f.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_R16I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r16-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_R16UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r16-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_R32F/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r32-f.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_R32I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r32-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_R32UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r32-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_R8/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r8.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_R8I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r8-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_R8UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r8-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RED/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-e-d.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RED_INTEGER/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-e-d_-i-n-t-e-g-e-r.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG16/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g16.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG16F/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g16-f.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG16I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g16-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG16UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g16-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG32F/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g32-f.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG32I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g32-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG32UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g32-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG8/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g8.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG8I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g8-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG8UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g8-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB10_A2/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b10_-a2.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB16I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b16-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB16UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b16-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB32I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b32-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB32UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b32-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB5/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b5.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB565/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b565.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB5_A1/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b5_-a1.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB8/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b8.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB8I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b8-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB8UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b8-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA16/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a16.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA16F/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a16-f.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA16I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a16-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA16UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a16-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA32F/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a32-f.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA32I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a32-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA32UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a32-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA4/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a4.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA8/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a8.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA8I/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a8-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA8UI/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a8-u-i.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGBA_INTEGER/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b-a_-i-n-t-e-g-e-r.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RGB_INTEGER/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g-b_-i-n-t-e-g-e-r.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_RG_INTEGER/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-r-g_-i-n-t-e-g-e-r.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_SRGB/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-s-r-g-b.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_SRGB8/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-s-r-g-b8.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_SRGB8_ALPHA8/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-s-r-g-b8_-a-l-p-h-a8.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_SRGB_ALPHA/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-s-r-g-b_-a-l-p-h-a.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_STENCIL_INDEX/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-s-t-e-n-c-i-l_-i-n-d-e-x.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_STENCIL_INDEX16/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-s-t-e-n-c-i-l_-i-n-d-e-x16.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_STENCIL_INDEX4/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-s-t-e-n-c-i-l_-i-n-d-e-x4.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat.Companion/GR_GL_STENCIL_INDEX8/#/PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/-companion/-g-r_-g-l_-s-t-e-n-c-i-l_-i-n-d-e-x8.html
+$dokka.location:org.jetbrains.skia/FramebufferFormat///PointingToDeclaration/skiko/org.jetbrains.skia/-framebuffer-format/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.BLEND///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-b-l-e-n-d/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.FIXED_FUNCTION///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-f-i-x-e-d_-f-u-n-c-t-i-o-n/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.MISC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-m-i-s-c/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.MSAA_ENABLE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-m-s-a-a_-e-n-a-b-l-e/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.PATH_RENDERING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-p-a-t-h_-r-e-n-d-e-r-i-n-g/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.PIXEL_STORE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-p-i-x-e-l_-s-t-o-r-e/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.PROGRAM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-p-r-o-g-r-a-m/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.RENDER_TARGET///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-r-e-n-d-e-r_-t-a-r-g-e-t/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.STENCIL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-s-t-e-n-c-i-l/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.TEXTURE_BINDING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-t-e-x-t-u-r-e_-b-i-n-d-i-n-g/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.VERTEX///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-v-e-r-t-e-x/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState.VIEW///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-g-l-backend-state/-v-i-e-w/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState///PointingToDeclaration/skiko/org.jetbrains.skia/-g-l-backend-state/index.html
+$dokka.location:org.jetbrains.skia/GLBackendState/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-g-l-backend-state/value-of.html
+$dokka.location:org.jetbrains.skia/GLBackendState/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-g-l-backend-state/values.html
+$dokka.location:org.jetbrains.skia/GradientStyle.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/-companion/index.html
+$dokka.location:org.jetbrains.skia/GradientStyle.Companion/DEFAULT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/-companion/-d-e-f-a-u-l-t.html
+$dokka.location:org.jetbrains.skia/GradientStyle///PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/index.html
+$dokka.location:org.jetbrains.skia/GradientStyle/GradientStyle/#org.jetbrains.skia.FilterTileMode#kotlin.Boolean#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/-gradient-style.html
+$dokka.location:org.jetbrains.skia/GradientStyle/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/equals.html
+$dokka.location:org.jetbrains.skia/GradientStyle/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/hash-code.html
+$dokka.location:org.jetbrains.skia/GradientStyle/isPremul/#/PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/is-premul.html
+$dokka.location:org.jetbrains.skia/GradientStyle/localMatrix/#/PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/local-matrix.html
+$dokka.location:org.jetbrains.skia/GradientStyle/tileMode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/tile-mode.html
+$dokka.location:org.jetbrains.skia/GradientStyle/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/to-string.html
+$dokka.location:org.jetbrains.skia/GradientStyle/withLocalMatrix/#org.jetbrains.skia.Matrix33/PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/with-local-matrix.html
+$dokka.location:org.jetbrains.skia/GradientStyle/withPremul/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/with-premul.html
+$dokka.location:org.jetbrains.skia/GradientStyle/withTileMode/#org.jetbrains.skia.FilterTileMode/PointingToDeclaration/skiko/org.jetbrains.skia/-gradient-style/with-tile-mode.html
+$dokka.location:org.jetbrains.skia/Graphics.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-companion/index.html
+$dokka.location:org.jetbrains.skia/Graphics.Companion/fontCacheCountLimit/#/PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-companion/font-cache-count-limit.html
+$dokka.location:org.jetbrains.skia/Graphics.Companion/fontCacheCountUsed/#/PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-companion/font-cache-count-used.html
+$dokka.location:org.jetbrains.skia/Graphics.Companion/fontCacheLimit/#/PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-companion/font-cache-limit.html
+$dokka.location:org.jetbrains.skia/Graphics.Companion/fontCacheUsed/#/PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-companion/font-cache-used.html
+$dokka.location:org.jetbrains.skia/Graphics.Companion/purgeAllCaches/#/PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-companion/purge-all-caches.html
+$dokka.location:org.jetbrains.skia/Graphics.Companion/purgeFontCache/#/PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-companion/purge-font-cache.html
+$dokka.location:org.jetbrains.skia/Graphics.Companion/purgeResourceCache/#/PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-companion/purge-resource-cache.html
+$dokka.location:org.jetbrains.skia/Graphics.Companion/resourceCacheSingleAllocationByteLimit/#/PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-companion/resource-cache-single-allocation-byte-limit.html
+$dokka.location:org.jetbrains.skia/Graphics.Companion/resourceCacheTotalLimit/#/PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-companion/resource-cache-total-limit.html
+$dokka.location:org.jetbrains.skia/Graphics.Companion/resourceCacheTotalUsed/#/PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-companion/resource-cache-total-used.html
+$dokka.location:org.jetbrains.skia/Graphics///PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/index.html
+$dokka.location:org.jetbrains.skia/Graphics/Graphics/#/PointingToDeclaration/skiko/org.jetbrains.skia/-graphics/-graphics.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo///PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/index.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo/alphaType/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/alpha-type.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo/bytesPerPixel/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/bytes-per-pixel.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo/colorInfo/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/color-info.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo/colorSpace/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/color-space.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo/colorType/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/color-type.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo/height/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/height.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo/imageInfo/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/image-info.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo/isEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/is-empty.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo/isOpaque/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/is-opaque.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo/shiftPerPixel/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/shift-per-pixel.html
+$dokka.location:org.jetbrains.skia/IHasImageInfo/width/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-has-image-info/width.html
+$dokka.location:org.jetbrains.skia/IPoint.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/-companion/index.html
+$dokka.location:org.jetbrains.skia/IPoint.Companion/ZERO/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/-companion/-z-e-r-o.html
+$dokka.location:org.jetbrains.skia/IPoint///PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/index.html
+$dokka.location:org.jetbrains.skia/IPoint/IPoint/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/-i-point.html
+$dokka.location:org.jetbrains.skia/IPoint/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/equals.html
+$dokka.location:org.jetbrains.skia/IPoint/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/hash-code.html
+$dokka.location:org.jetbrains.skia/IPoint/isEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/is-empty.html
+$dokka.location:org.jetbrains.skia/IPoint/offset/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/offset.html
+$dokka.location:org.jetbrains.skia/IPoint/offset/#org.jetbrains.skia.IPoint/PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/offset.html
+$dokka.location:org.jetbrains.skia/IPoint/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/to-string.html
+$dokka.location:org.jetbrains.skia/IPoint/x/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/x.html
+$dokka.location:org.jetbrains.skia/IPoint/y/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-point/y.html
+$dokka.location:org.jetbrains.skia/IRange.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-i-range/-companion/index.html
+$dokka.location:org.jetbrains.skia/IRange///PointingToDeclaration/skiko/org.jetbrains.skia/-i-range/index.html
+$dokka.location:org.jetbrains.skia/IRange/IRange/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-i-range/-i-range.html
+$dokka.location:org.jetbrains.skia/IRange/end/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-range/end.html
+$dokka.location:org.jetbrains.skia/IRange/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-i-range/equals.html
+$dokka.location:org.jetbrains.skia/IRange/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-range/hash-code.html
+$dokka.location:org.jetbrains.skia/IRange/start/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-range/start.html
+$dokka.location:org.jetbrains.skia/IRange/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-range/to-string.html
+$dokka.location:org.jetbrains.skia/IRect.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/-companion/index.html
+$dokka.location:org.jetbrains.skia/IRect.Companion/makeLTRB/#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/-companion/make-l-t-r-b.html
+$dokka.location:org.jetbrains.skia/IRect.Companion/makeWH/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/-companion/make-w-h.html
+$dokka.location:org.jetbrains.skia/IRect.Companion/makeXYWH/#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/-companion/make-x-y-w-h.html
+$dokka.location:org.jetbrains.skia/IRect///PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/index.html
+$dokka.location:org.jetbrains.skia/IRect/bottom/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/bottom.html
+$dokka.location:org.jetbrains.skia/IRect/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/equals.html
+$dokka.location:org.jetbrains.skia/IRect/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/hash-code.html
+$dokka.location:org.jetbrains.skia/IRect/height/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/height.html
+$dokka.location:org.jetbrains.skia/IRect/intersect/#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/intersect.html
+$dokka.location:org.jetbrains.skia/IRect/left/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/left.html
+$dokka.location:org.jetbrains.skia/IRect/offset/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/offset.html
+$dokka.location:org.jetbrains.skia/IRect/offset/#org.jetbrains.skia.IPoint/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/offset.html
+$dokka.location:org.jetbrains.skia/IRect/right/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/right.html
+$dokka.location:org.jetbrains.skia/IRect/toRect/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/to-rect.html
+$dokka.location:org.jetbrains.skia/IRect/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/to-string.html
+$dokka.location:org.jetbrains.skia/IRect/top/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/top.html
+$dokka.location:org.jetbrains.skia/IRect/width/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-rect/width.html
+$dokka.location:org.jetbrains.skia/ISize.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/-companion/index.html
+$dokka.location:org.jetbrains.skia/ISize.Companion/make/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/-companion/make.html
+$dokka.location:org.jetbrains.skia/ISize.Companion/makeEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/-companion/make-empty.html
+$dokka.location:org.jetbrains.skia/ISize///PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/index.html
+$dokka.location:org.jetbrains.skia/ISize/area/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/area.html
+$dokka.location:org.jetbrains.skia/ISize/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/equals.html
+$dokka.location:org.jetbrains.skia/ISize/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/hash-code.html
+$dokka.location:org.jetbrains.skia/ISize/height/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/height.html
+$dokka.location:org.jetbrains.skia/ISize/isEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/is-empty.html
+$dokka.location:org.jetbrains.skia/ISize/isZero/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/is-zero.html
+$dokka.location:org.jetbrains.skia/ISize/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/to-string.html
+$dokka.location:org.jetbrains.skia/ISize/width/#/PointingToDeclaration/skiko/org.jetbrains.skia/-i-size/width.html
+$dokka.location:org.jetbrains.skia/Image.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-image/-companion/index.html
+$dokka.location:org.jetbrains.skia/Image.Companion/makeFromBitmap/#org.jetbrains.skia.Bitmap/PointingToDeclaration/skiko/org.jetbrains.skia/-image/-companion/make-from-bitmap.html
+$dokka.location:org.jetbrains.skia/Image.Companion/makeFromEncoded/#kotlin.ByteArray/PointingToDeclaration/skiko/org.jetbrains.skia/-image/-companion/make-from-encoded.html
+$dokka.location:org.jetbrains.skia/Image.Companion/makeFromPixmap/#org.jetbrains.skia.Pixmap/PointingToDeclaration/skiko/org.jetbrains.skia/-image/-companion/make-from-pixmap.html
+$dokka.location:org.jetbrains.skia/Image.Companion/makeRaster/#org.jetbrains.skia.ImageInfo#kotlin.ByteArray#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image/-companion/make-raster.html
+$dokka.location:org.jetbrains.skia/Image.Companion/makeRaster/#org.jetbrains.skia.ImageInfo#org.jetbrains.skia.Data#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image/-companion/make-raster.html
+$dokka.location:org.jetbrains.skia/Image///PointingToDeclaration/skiko/org.jetbrains.skia/-image/index.html
+$dokka.location:org.jetbrains.skia/Image/encodeToData/#org.jetbrains.skia.EncodedImageFormat#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image/encode-to-data.html
+$dokka.location:org.jetbrains.skia/Image/imageInfo/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image/image-info.html
+$dokka.location:org.jetbrains.skia/Image/makeShader/#org.jetbrains.skia.FilterTileMode#org.jetbrains.skia.FilterTileMode#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia/-image/make-shader.html
+$dokka.location:org.jetbrains.skia/Image/makeShader/#org.jetbrains.skia.FilterTileMode#org.jetbrains.skia.FilterTileMode#org.jetbrains.skia.SamplingMode#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia/-image/make-shader.html
+$dokka.location:org.jetbrains.skia/Image/makeShader/#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia/-image/make-shader.html
+$dokka.location:org.jetbrains.skia/Image/peekPixels/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image/peek-pixels.html
+$dokka.location:org.jetbrains.skia/Image/peekPixels/#org.jetbrains.skia.Pixmap?/PointingToDeclaration/skiko/org.jetbrains.skia/-image/peek-pixels.html
+$dokka.location:org.jetbrains.skia/Image/readPixels/#org.jetbrains.skia.Bitmap#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image/read-pixels.html
+$dokka.location:org.jetbrains.skia/Image/readPixels/#org.jetbrains.skia.Bitmap/PointingToDeclaration/skiko/org.jetbrains.skia/-image/read-pixels.html
+$dokka.location:org.jetbrains.skia/Image/readPixels/#org.jetbrains.skia.DirectContext#org.jetbrains.skia.Bitmap#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image/read-pixels.html
+$dokka.location:org.jetbrains.skia/Image/readPixels/#org.jetbrains.skia.DirectContext#org.jetbrains.skia.Bitmap/PointingToDeclaration/skiko/org.jetbrains.skia/-image/read-pixels.html
+$dokka.location:org.jetbrains.skia/Image/readPixels/#org.jetbrains.skia.DirectContext?#org.jetbrains.skia.Bitmap#kotlin.Int#kotlin.Int#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-image/read-pixels.html
+$dokka.location:org.jetbrains.skia/Image/readPixels/#org.jetbrains.skia.Pixmap#kotlin.Int#kotlin.Int#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-image/read-pixels.html
+$dokka.location:org.jetbrains.skia/Image/scalePixels/#org.jetbrains.skia.Pixmap#org.jetbrains.skia.SamplingMode#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-image/scale-pixels.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/index.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeAlphaThreshold/#org.jetbrains.skia.Region?#kotlin.Float#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-alpha-threshold.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeArithmetic/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Boolean#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-arithmetic.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeBlend/#org.jetbrains.skia.BlendMode#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-blend.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeBlur/#kotlin.Float#kotlin.Float#org.jetbrains.skia.FilterTileMode#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-blur.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeColorFilter/#org.jetbrains.skia.ColorFilter?#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-color-filter.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeCompose/#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.ImageFilter?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-compose.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeDilate/#kotlin.Float#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-dilate.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeDisplacementMap/#org.jetbrains.skia.ColorChannel#org.jetbrains.skia.ColorChannel#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-displacement-map.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeDistantLitDiffuse/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int#kotlin.Float#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-distant-lit-diffuse.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeDistantLitSpecular/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int#kotlin.Float#kotlin.Float#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-distant-lit-specular.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeDropShadow/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-drop-shadow.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeDropShadowOnly/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-drop-shadow-only.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeErode/#kotlin.Float#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-erode.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeImage/#org.jetbrains.skia.Image/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-image.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeImage/#org.jetbrains.skia.Image?#org.jetbrains.skia.Rect#org.jetbrains.skia.Rect#org.jetbrains.skia.SamplingMode/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-image.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeMagnifier/#org.jetbrains.skia.Rect#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-magnifier.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeMatrixConvolution/#kotlin.Int#kotlin.Int#kotlin.FloatArray?#kotlin.Float#kotlin.Float#kotlin.Int#kotlin.Int#org.jetbrains.skia.FilterTileMode#kotlin.Boolean#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-matrix-convolution.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeMatrixTransform/#org.jetbrains.skia.Matrix33#org.jetbrains.skia.SamplingMode#org.jetbrains.skia.ImageFilter?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-matrix-transform.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeMerge/#kotlin.Array[org.jetbrains.skia.ImageFilter?]#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-merge.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeOffset/#kotlin.Float#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-offset.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makePointLitDiffuse/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int#kotlin.Float#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-point-lit-diffuse.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makePointLitSpecular/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int#kotlin.Float#kotlin.Float#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-point-lit-specular.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeRuntimeShader/#org.jetbrains.skia.RuntimeShaderBuilder#kotlin.Array[kotlin.String]#kotlin.Array[org.jetbrains.skia.ImageFilter?]/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-runtime-shader.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeRuntimeShader/#org.jetbrains.skia.RuntimeShaderBuilder#kotlin.String#org.jetbrains.skia.ImageFilter?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-runtime-shader.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeShader/#org.jetbrains.skia.Shader#kotlin.Boolean#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-shader.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeSpotLitDiffuse/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int#kotlin.Float#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-spot-lit-diffuse.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeSpotLitSpecular/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Int#kotlin.Float#kotlin.Float#kotlin.Float#org.jetbrains.skia.ImageFilter?#org.jetbrains.skia.IRect?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-spot-lit-specular.html
+$dokka.location:org.jetbrains.skia/ImageFilter.Companion/makeTile/#org.jetbrains.skia.Rect#org.jetbrains.skia.Rect#org.jetbrains.skia.ImageFilter?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/-companion/make-tile.html
+$dokka.location:org.jetbrains.skia/ImageFilter///PointingToDeclaration/skiko/org.jetbrains.skia/-image-filter/index.html
+$dokka.location:org.jetbrains.skia/ImageInfo.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-companion/index.html
+$dokka.location:org.jetbrains.skia/ImageInfo.Companion/DEFAULT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-companion/-d-e-f-a-u-l-t.html
+$dokka.location:org.jetbrains.skia/ImageInfo.Companion/createUsing/#org.jetbrains.skia.impl.NativePointer#kotlin.Function3[org.jetbrains.skia.impl.NativePointer,org.jetbrains.skia.impl.InteropPointer,org.jetbrains.skia.impl.InteropPointer,kotlin.Unit]/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-companion/create-using.html
+$dokka.location:org.jetbrains.skia/ImageInfo.Companion/makeA8/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-companion/make-a8.html
+$dokka.location:org.jetbrains.skia/ImageInfo.Companion/makeN32/#kotlin.Int#kotlin.Int#org.jetbrains.skia.ColorAlphaType#org.jetbrains.skia.ColorSpace?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-companion/make-n32.html
+$dokka.location:org.jetbrains.skia/ImageInfo.Companion/makeN32/#kotlin.Int#kotlin.Int#org.jetbrains.skia.ColorAlphaType/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-companion/make-n32.html
+$dokka.location:org.jetbrains.skia/ImageInfo.Companion/makeN32Premul/#kotlin.Int#kotlin.Int#org.jetbrains.skia.ColorSpace?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-companion/make-n32-premul.html
+$dokka.location:org.jetbrains.skia/ImageInfo.Companion/makeN32Premul/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-companion/make-n32-premul.html
+$dokka.location:org.jetbrains.skia/ImageInfo.Companion/makeS32/#kotlin.Int#kotlin.Int#org.jetbrains.skia.ColorAlphaType/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-companion/make-s32.html
+$dokka.location:org.jetbrains.skia/ImageInfo.Companion/makeUnknown/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-companion/make-unknown.html
+$dokka.location:org.jetbrains.skia/ImageInfo///PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/index.html
+$dokka.location:org.jetbrains.skia/ImageInfo/ImageInfo/#kotlin.Int#kotlin.Int#org.jetbrains.skia.ColorType#org.jetbrains.skia.ColorAlphaType#org.jetbrains.skia.ColorSpace?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-image-info.html
+$dokka.location:org.jetbrains.skia/ImageInfo/ImageInfo/#kotlin.Int#kotlin.Int#org.jetbrains.skia.ColorType#org.jetbrains.skia.ColorAlphaType/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-image-info.html
+$dokka.location:org.jetbrains.skia/ImageInfo/ImageInfo/#org.jetbrains.skia.ColorInfo#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/-image-info.html
+$dokka.location:org.jetbrains.skia/ImageInfo/bounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/bounds.html
+$dokka.location:org.jetbrains.skia/ImageInfo/bytesPerPixel/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/bytes-per-pixel.html
+$dokka.location:org.jetbrains.skia/ImageInfo/colorAlphaType/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/color-alpha-type.html
+$dokka.location:org.jetbrains.skia/ImageInfo/colorInfo/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/color-info.html
+$dokka.location:org.jetbrains.skia/ImageInfo/colorSpace/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/color-space.html
+$dokka.location:org.jetbrains.skia/ImageInfo/colorType/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/color-type.html
+$dokka.location:org.jetbrains.skia/ImageInfo/computeByteSize/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/compute-byte-size.html
+$dokka.location:org.jetbrains.skia/ImageInfo/computeMinByteSize/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/compute-min-byte-size.html
+$dokka.location:org.jetbrains.skia/ImageInfo/computeOffset/#kotlin.Int#kotlin.Int#kotlin.Long/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/compute-offset.html
+$dokka.location:org.jetbrains.skia/ImageInfo/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/equals.html
+$dokka.location:org.jetbrains.skia/ImageInfo/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/hash-code.html
+$dokka.location:org.jetbrains.skia/ImageInfo/height/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/height.html
+$dokka.location:org.jetbrains.skia/ImageInfo/isEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/is-empty.html
+$dokka.location:org.jetbrains.skia/ImageInfo/isGammaCloseToSRGB/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/is-gamma-close-to-s-r-g-b.html
+$dokka.location:org.jetbrains.skia/ImageInfo/isOpaque/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/is-opaque.html
+$dokka.location:org.jetbrains.skia/ImageInfo/isRowBytesValid/#kotlin.Long/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/is-row-bytes-valid.html
+$dokka.location:org.jetbrains.skia/ImageInfo/minRowBytes/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/min-row-bytes.html
+$dokka.location:org.jetbrains.skia/ImageInfo/shiftPerPixel/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/shift-per-pixel.html
+$dokka.location:org.jetbrains.skia/ImageInfo/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/to-string.html
+$dokka.location:org.jetbrains.skia/ImageInfo/width/#/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/width.html
+$dokka.location:org.jetbrains.skia/ImageInfo/withColorAlphaType/#org.jetbrains.skia.ColorAlphaType/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/with-color-alpha-type.html
+$dokka.location:org.jetbrains.skia/ImageInfo/withColorInfo/#org.jetbrains.skia.ColorInfo/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/with-color-info.html
+$dokka.location:org.jetbrains.skia/ImageInfo/withColorSpace/#org.jetbrains.skia.ColorSpace/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/with-color-space.html
+$dokka.location:org.jetbrains.skia/ImageInfo/withColorType/#org.jetbrains.skia.ColorType/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/with-color-type.html
+$dokka.location:org.jetbrains.skia/ImageInfo/withHeight/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/with-height.html
+$dokka.location:org.jetbrains.skia/ImageInfo/withWidth/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/with-width.html
+$dokka.location:org.jetbrains.skia/ImageInfo/withWidthHeight/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-image-info/with-width-height.html
+$dokka.location:org.jetbrains.skia/InversionMode.BRIGHTNESS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-inversion-mode/-b-r-i-g-h-t-n-e-s-s/index.html
+$dokka.location:org.jetbrains.skia/InversionMode.LIGHTNESS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-inversion-mode/-l-i-g-h-t-n-e-s-s/index.html
+$dokka.location:org.jetbrains.skia/InversionMode.NO///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-inversion-mode/-n-o/index.html
+$dokka.location:org.jetbrains.skia/InversionMode///PointingToDeclaration/skiko/org.jetbrains.skia/-inversion-mode/index.html
+$dokka.location:org.jetbrains.skia/InversionMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-inversion-mode/value-of.html
+$dokka.location:org.jetbrains.skia/InversionMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-inversion-mode/values.html
+$dokka.location:org.jetbrains.skia/ManagedString.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-managed-string/-companion/index.html
+$dokka.location:org.jetbrains.skia/ManagedString///PointingToDeclaration/skiko/org.jetbrains.skia/-managed-string/index.html
+$dokka.location:org.jetbrains.skia/ManagedString/ManagedString/#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skia/-managed-string/-managed-string.html
+$dokka.location:org.jetbrains.skia/ManagedString/append/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-managed-string/append.html
+$dokka.location:org.jetbrains.skia/ManagedString/insert/#kotlin.Int#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-managed-string/insert.html
+$dokka.location:org.jetbrains.skia/ManagedString/remove/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-managed-string/remove.html
+$dokka.location:org.jetbrains.skia/ManagedString/remove/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-managed-string/remove.html
+$dokka.location:org.jetbrains.skia/ManagedString/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-managed-string/to-string.html
+$dokka.location:org.jetbrains.skia/MaskFilter.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-mask-filter/-companion/index.html
+$dokka.location:org.jetbrains.skia/MaskFilter.Companion/makeBlur/#org.jetbrains.skia.FilterBlurMode#kotlin.Float#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-mask-filter/-companion/make-blur.html
+$dokka.location:org.jetbrains.skia/MaskFilter.Companion/makeClip/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-mask-filter/-companion/make-clip.html
+$dokka.location:org.jetbrains.skia/MaskFilter.Companion/makeGamma/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-mask-filter/-companion/make-gamma.html
+$dokka.location:org.jetbrains.skia/MaskFilter.Companion/makeShader/#org.jetbrains.skia.Shader?/PointingToDeclaration/skiko/org.jetbrains.skia/-mask-filter/-companion/make-shader.html
+$dokka.location:org.jetbrains.skia/MaskFilter.Companion/makeTable/#kotlin.ByteArray/PointingToDeclaration/skiko/org.jetbrains.skia/-mask-filter/-companion/make-table.html
+$dokka.location:org.jetbrains.skia/MaskFilter///PointingToDeclaration/skiko/org.jetbrains.skia/-mask-filter/index.html
+$dokka.location:org.jetbrains.skia/Matcher///PointingToDeclaration/skiko/org.jetbrains.skia/-matcher/index.html
+$dokka.location:org.jetbrains.skia/Matcher/Matcher/#kotlin.text.Regex#kotlin.CharSequence/PointingToDeclaration/skiko/org.jetbrains.skia/-matcher/-matcher.html
+$dokka.location:org.jetbrains.skia/Matcher/group/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-matcher/group.html
+$dokka.location:org.jetbrains.skia/Matcher/matches/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matcher/matches.html
+$dokka.location:org.jetbrains.skia/Matrix22.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-matrix22/-companion/index.html
+$dokka.location:org.jetbrains.skia/Matrix22.Companion/IDENTITY/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix22/-companion/-i-d-e-n-t-i-t-y.html
+$dokka.location:org.jetbrains.skia/Matrix22///PointingToDeclaration/skiko/org.jetbrains.skia/-matrix22/index.html
+$dokka.location:org.jetbrains.skia/Matrix22/Matrix22/#kotlin.FloatArray/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix22/-matrix22.html
+$dokka.location:org.jetbrains.skia/Matrix22/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix22/equals.html
+$dokka.location:org.jetbrains.skia/Matrix22/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix22/hash-code.html
+$dokka.location:org.jetbrains.skia/Matrix22/mat/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix22/mat.html
+$dokka.location:org.jetbrains.skia/Matrix22/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix22/to-string.html
+$dokka.location:org.jetbrains.skia/Matrix33.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/-companion/index.html
+$dokka.location:org.jetbrains.skia/Matrix33.Companion/IDENTITY/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/-companion/-i-d-e-n-t-i-t-y.html
+$dokka.location:org.jetbrains.skia/Matrix33.Companion/makeRotate/#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/-companion/make-rotate.html
+$dokka.location:org.jetbrains.skia/Matrix33.Companion/makeRotate/#kotlin.Float#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/-companion/make-rotate.html
+$dokka.location:org.jetbrains.skia/Matrix33.Companion/makeRotate/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/-companion/make-rotate.html
+$dokka.location:org.jetbrains.skia/Matrix33.Companion/makeScale/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/-companion/make-scale.html
+$dokka.location:org.jetbrains.skia/Matrix33.Companion/makeScale/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/-companion/make-scale.html
+$dokka.location:org.jetbrains.skia/Matrix33.Companion/makeSkew/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/-companion/make-skew.html
+$dokka.location:org.jetbrains.skia/Matrix33.Companion/makeTranslate/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/-companion/make-translate.html
+$dokka.location:org.jetbrains.skia/Matrix33///PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/index.html
+$dokka.location:org.jetbrains.skia/Matrix33/Matrix33/#kotlin.FloatArray/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/-matrix33.html
+$dokka.location:org.jetbrains.skia/Matrix33/asMatrix44/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/as-matrix44.html
+$dokka.location:org.jetbrains.skia/Matrix33/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/equals.html
+$dokka.location:org.jetbrains.skia/Matrix33/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/hash-code.html
+$dokka.location:org.jetbrains.skia/Matrix33/makeConcat/#org.jetbrains.skia.Matrix33/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/make-concat.html
+$dokka.location:org.jetbrains.skia/Matrix33/makePreScale/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/make-pre-scale.html
+$dokka.location:org.jetbrains.skia/Matrix33/mat/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/mat.html
+$dokka.location:org.jetbrains.skia/Matrix33/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix33/to-string.html
+$dokka.location:org.jetbrains.skia/Matrix44.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-matrix44/-companion/index.html
+$dokka.location:org.jetbrains.skia/Matrix44.Companion/IDENTITY/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix44/-companion/-i-d-e-n-t-i-t-y.html
+$dokka.location:org.jetbrains.skia/Matrix44///PointingToDeclaration/skiko/org.jetbrains.skia/-matrix44/index.html
+$dokka.location:org.jetbrains.skia/Matrix44/Matrix44/#kotlin.FloatArray/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix44/-matrix44.html
+$dokka.location:org.jetbrains.skia/Matrix44/asMatrix33/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix44/as-matrix33.html
+$dokka.location:org.jetbrains.skia/Matrix44/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix44/equals.html
+$dokka.location:org.jetbrains.skia/Matrix44/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix44/hash-code.html
+$dokka.location:org.jetbrains.skia/Matrix44/mat/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix44/mat.html
+$dokka.location:org.jetbrains.skia/Matrix44/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-matrix44/to-string.html
+$dokka.location:org.jetbrains.skia/MipmapMode.LINEAR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-mipmap-mode/-l-i-n-e-a-r/index.html
+$dokka.location:org.jetbrains.skia/MipmapMode.NEAREST///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-mipmap-mode/-n-e-a-r-e-s-t/index.html
+$dokka.location:org.jetbrains.skia/MipmapMode.NONE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-mipmap-mode/-n-o-n-e/index.html
+$dokka.location:org.jetbrains.skia/MipmapMode///PointingToDeclaration/skiko/org.jetbrains.skia/-mipmap-mode/index.html
+$dokka.location:org.jetbrains.skia/MipmapMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-mipmap-mode/value-of.html
+$dokka.location:org.jetbrains.skia/MipmapMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-mipmap-mode/values.html
+$dokka.location:org.jetbrains.skia/OutputStream///PointingToDeclaration/skiko/org.jetbrains.skia/-output-stream/index.html
+$dokka.location:org.jetbrains.skia/OutputStream/OutputStream/#/PointingToDeclaration/skiko/org.jetbrains.skia/-output-stream/-output-stream.html
+$dokka.location:org.jetbrains.skia/OutputWStream.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-output-w-stream/-companion/index.html
+$dokka.location:org.jetbrains.skia/OutputWStream///PointingToDeclaration/skiko/org.jetbrains.skia/-output-w-stream/index.html
+$dokka.location:org.jetbrains.skia/OutputWStream/OutputWStream/#org.jetbrains.skia.OutputStream?/PointingToDeclaration/skiko/org.jetbrains.skia/-output-w-stream/-output-w-stream.html
+$dokka.location:org.jetbrains.skia/Paint.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-paint/-companion/index.html
+$dokka.location:org.jetbrains.skia/Paint///PointingToDeclaration/skiko/org.jetbrains.skia/-paint/index.html
+$dokka.location:org.jetbrains.skia/Paint/Paint/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/-paint.html
+$dokka.location:org.jetbrains.skia/Paint/alpha/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/alpha.html
+$dokka.location:org.jetbrains.skia/Paint/alphaf/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/alphaf.html
+$dokka.location:org.jetbrains.skia/Paint/blendMode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/blend-mode.html
+$dokka.location:org.jetbrains.skia/Paint/color/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/color.html
+$dokka.location:org.jetbrains.skia/Paint/color4f/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/color4f.html
+$dokka.location:org.jetbrains.skia/Paint/colorFilter/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/color-filter.html
+$dokka.location:org.jetbrains.skia/Paint/hasNothingToDraw/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/has-nothing-to-draw.html
+$dokka.location:org.jetbrains.skia/Paint/imageFilter/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/image-filter.html
+$dokka.location:org.jetbrains.skia/Paint/isAntiAlias/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/is-anti-alias.html
+$dokka.location:org.jetbrains.skia/Paint/isDither/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/is-dither.html
+$dokka.location:org.jetbrains.skia/Paint/isSrcOver/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/is-src-over.html
+$dokka.location:org.jetbrains.skia/Paint/makeClone/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/make-clone.html
+$dokka.location:org.jetbrains.skia/Paint/maskFilter/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/mask-filter.html
+$dokka.location:org.jetbrains.skia/Paint/mode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/mode.html
+$dokka.location:org.jetbrains.skia/Paint/pathEffect/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/path-effect.html
+$dokka.location:org.jetbrains.skia/Paint/reset/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/reset.html
+$dokka.location:org.jetbrains.skia/Paint/setARGB/#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/set-a-r-g-b.html
+$dokka.location:org.jetbrains.skia/Paint/setAlphaf/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/set-alphaf.html
+$dokka.location:org.jetbrains.skia/Paint/setColor4f/#org.jetbrains.skia.Color4f#org.jetbrains.skia.ColorSpace?/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/set-color4f.html
+$dokka.location:org.jetbrains.skia/Paint/setStroke/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/set-stroke.html
+$dokka.location:org.jetbrains.skia/Paint/shader/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/shader.html
+$dokka.location:org.jetbrains.skia/Paint/strokeCap/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/stroke-cap.html
+$dokka.location:org.jetbrains.skia/Paint/strokeJoin/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/stroke-join.html
+$dokka.location:org.jetbrains.skia/Paint/strokeMiter/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/stroke-miter.html
+$dokka.location:org.jetbrains.skia/Paint/strokeWidth/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint/stroke-width.html
+$dokka.location:org.jetbrains.skia/PaintFilterCanvas.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-paint-filter-canvas/-companion/index.html
+$dokka.location:org.jetbrains.skia/PaintFilterCanvas///PointingToDeclaration/skiko/org.jetbrains.skia/-paint-filter-canvas/index.html
+$dokka.location:org.jetbrains.skia/PaintFilterCanvas/PaintFilterCanvas/#org.jetbrains.skia.Canvas#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-paint-filter-canvas/-paint-filter-canvas.html
+$dokka.location:org.jetbrains.skia/PaintFilterCanvas/onFilter/#org.jetbrains.skia.Paint/PointingToDeclaration/skiko/org.jetbrains.skia/-paint-filter-canvas/on-filter.html
+$dokka.location:org.jetbrains.skia/PaintFilterCanvas/onFilter/#org.jetbrains.skia.impl.NativePointer/PointingToDeclaration/skiko/org.jetbrains.skia/-paint-filter-canvas/on-filter.html
+$dokka.location:org.jetbrains.skia/PaintMode.FILL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-paint-mode/-f-i-l-l/index.html
+$dokka.location:org.jetbrains.skia/PaintMode.STROKE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-paint-mode/-s-t-r-o-k-e/index.html
+$dokka.location:org.jetbrains.skia/PaintMode.STROKE_AND_FILL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-paint-mode/-s-t-r-o-k-e_-a-n-d_-f-i-l-l/index.html
+$dokka.location:org.jetbrains.skia/PaintMode///PointingToDeclaration/skiko/org.jetbrains.skia/-paint-mode/index.html
+$dokka.location:org.jetbrains.skia/PaintMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-paint-mode/value-of.html
+$dokka.location:org.jetbrains.skia/PaintMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint-mode/values.html
+$dokka.location:org.jetbrains.skia/PaintStrokeCap.BUTT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-paint-stroke-cap/-b-u-t-t/index.html
+$dokka.location:org.jetbrains.skia/PaintStrokeCap.ROUND///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-paint-stroke-cap/-r-o-u-n-d/index.html
+$dokka.location:org.jetbrains.skia/PaintStrokeCap.SQUARE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-paint-stroke-cap/-s-q-u-a-r-e/index.html
+$dokka.location:org.jetbrains.skia/PaintStrokeCap///PointingToDeclaration/skiko/org.jetbrains.skia/-paint-stroke-cap/index.html
+$dokka.location:org.jetbrains.skia/PaintStrokeCap/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-paint-stroke-cap/value-of.html
+$dokka.location:org.jetbrains.skia/PaintStrokeCap/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint-stroke-cap/values.html
+$dokka.location:org.jetbrains.skia/PaintStrokeJoin.BEVEL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-paint-stroke-join/-b-e-v-e-l/index.html
+$dokka.location:org.jetbrains.skia/PaintStrokeJoin.MITER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-paint-stroke-join/-m-i-t-e-r/index.html
+$dokka.location:org.jetbrains.skia/PaintStrokeJoin.ROUND///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-paint-stroke-join/-r-o-u-n-d/index.html
+$dokka.location:org.jetbrains.skia/PaintStrokeJoin///PointingToDeclaration/skiko/org.jetbrains.skia/-paint-stroke-join/index.html
+$dokka.location:org.jetbrains.skia/PaintStrokeJoin/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-paint-stroke-join/value-of.html
+$dokka.location:org.jetbrains.skia/PaintStrokeJoin/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-paint-stroke-join/values.html
+$dokka.location:org.jetbrains.skia/Path.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-path/-companion/index.html
+$dokka.location:org.jetbrains.skia/Path.Companion/convertConicToQuads/#org.jetbrains.skia.Point#org.jetbrains.skia.Point#org.jetbrains.skia.Point#kotlin.Float#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-path/-companion/convert-conic-to-quads.html
+$dokka.location:org.jetbrains.skia/Path.Companion/isCubicDegenerate/#org.jetbrains.skia.Point#org.jetbrains.skia.Point#org.jetbrains.skia.Point#org.jetbrains.skia.Point#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/-companion/is-cubic-degenerate.html
+$dokka.location:org.jetbrains.skia/Path.Companion/isLineDegenerate/#org.jetbrains.skia.Point#org.jetbrains.skia.Point#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/-companion/is-line-degenerate.html
+$dokka.location:org.jetbrains.skia/Path.Companion/isQuadDegenerate/#org.jetbrains.skia.Point#org.jetbrains.skia.Point#org.jetbrains.skia.Point#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/-companion/is-quad-degenerate.html
+$dokka.location:org.jetbrains.skia/Path.Companion/makeCombining/#org.jetbrains.skia.Path#org.jetbrains.skia.Path#org.jetbrains.skia.PathOp/PointingToDeclaration/skiko/org.jetbrains.skia/-path/-companion/make-combining.html
+$dokka.location:org.jetbrains.skia/Path.Companion/makeFromBytes/#kotlin.ByteArray/PointingToDeclaration/skiko/org.jetbrains.skia/-path/-companion/make-from-bytes.html
+$dokka.location:org.jetbrains.skia/Path.Companion/makeFromSVGString/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-path/-companion/make-from-s-v-g-string.html
+$dokka.location:org.jetbrains.skia/Path///PointingToDeclaration/skiko/org.jetbrains.skia/-path/index.html
+$dokka.location:org.jetbrains.skia/Path/Path/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/-path.html
+$dokka.location:org.jetbrains.skia/Path/addArc/#org.jetbrains.skia.Rect#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/add-arc.html
+$dokka.location:org.jetbrains.skia/Path/addCircle/#kotlin.Float#kotlin.Float#kotlin.Float#org.jetbrains.skia.PathDirection/PointingToDeclaration/skiko/org.jetbrains.skia/-path/add-circle.html
+$dokka.location:org.jetbrains.skia/Path/addOval/#org.jetbrains.skia.Rect#org.jetbrains.skia.PathDirection#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-path/add-oval.html
+$dokka.location:org.jetbrains.skia/Path/addPath/#org.jetbrains.skia.Path?#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/add-path.html
+$dokka.location:org.jetbrains.skia/Path/addPath/#org.jetbrains.skia.Path?#kotlin.Float#kotlin.Float#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/add-path.html
+$dokka.location:org.jetbrains.skia/Path/addPath/#org.jetbrains.skia.Path?#org.jetbrains.skia.Matrix33#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/add-path.html
+$dokka.location:org.jetbrains.skia/Path/addPoly/#kotlin.Array[org.jetbrains.skia.Point]#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/add-poly.html
+$dokka.location:org.jetbrains.skia/Path/addPoly/#kotlin.FloatArray#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/add-poly.html
+$dokka.location:org.jetbrains.skia/Path/addRRect/#org.jetbrains.skia.RRect#org.jetbrains.skia.PathDirection#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-path/add-r-rect.html
+$dokka.location:org.jetbrains.skia/Path/addRect/#org.jetbrains.skia.Rect#org.jetbrains.skia.PathDirection#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-path/add-rect.html
+$dokka.location:org.jetbrains.skia/Path/approximateBytesUsed/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/approximate-bytes-used.html
+$dokka.location:org.jetbrains.skia/Path/arcTo/#org.jetbrains.skia.Rect#kotlin.Float#kotlin.Float#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/arc-to.html
+$dokka.location:org.jetbrains.skia/Path/asLine/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/as-line.html
+$dokka.location:org.jetbrains.skia/Path/bounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/bounds.html
+$dokka.location:org.jetbrains.skia/Path/closePath/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/close-path.html
+$dokka.location:org.jetbrains.skia/Path/computeTightBounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/compute-tight-bounds.html
+$dokka.location:org.jetbrains.skia/Path/conicTo/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/conic-to.html
+$dokka.location:org.jetbrains.skia/Path/conicTo/#org.jetbrains.skia.Point#org.jetbrains.skia.Point#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/conic-to.html
+$dokka.location:org.jetbrains.skia/Path/conservativelyContainsRect/#org.jetbrains.skia.Rect/PointingToDeclaration/skiko/org.jetbrains.skia/-path/conservatively-contains-rect.html
+$dokka.location:org.jetbrains.skia/Path/contains/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/contains.html
+$dokka.location:org.jetbrains.skia/Path/contains/#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia/-path/contains.html
+$dokka.location:org.jetbrains.skia/Path/cubicTo/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/cubic-to.html
+$dokka.location:org.jetbrains.skia/Path/cubicTo/#org.jetbrains.skia.Point#org.jetbrains.skia.Point#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia/-path/cubic-to.html
+$dokka.location:org.jetbrains.skia/Path/dump/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/dump.html
+$dokka.location:org.jetbrains.skia/Path/dumpHex/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/dump-hex.html
+$dokka.location:org.jetbrains.skia/Path/ellipticalArcTo/#kotlin.Float#kotlin.Float#kotlin.Float#org.jetbrains.skia.PathEllipseArc#org.jetbrains.skia.PathDirection#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/elliptical-arc-to.html
+$dokka.location:org.jetbrains.skia/Path/ellipticalArcTo/#org.jetbrains.skia.Point#kotlin.Float#org.jetbrains.skia.PathEllipseArc#org.jetbrains.skia.PathDirection#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia/-path/elliptical-arc-to.html
+$dokka.location:org.jetbrains.skia/Path/fillMode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/fill-mode.html
+$dokka.location:org.jetbrains.skia/Path/generationId/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/generation-id.html
+$dokka.location:org.jetbrains.skia/Path/getPoint/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-path/get-point.html
+$dokka.location:org.jetbrains.skia/Path/getPoints/#kotlin.Array[org.jetbrains.skia.Point?]?#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-path/get-points.html
+$dokka.location:org.jetbrains.skia/Path/getVerbs/#kotlin.Array[org.jetbrains.skia.PathVerb?]?#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-path/get-verbs.html
+$dokka.location:org.jetbrains.skia/Path/incReserve/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-path/inc-reserve.html
+$dokka.location:org.jetbrains.skia/Path/isConvex/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/is-convex.html
+$dokka.location:org.jetbrains.skia/Path/isEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/is-empty.html
+$dokka.location:org.jetbrains.skia/Path/isFinite/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/is-finite.html
+$dokka.location:org.jetbrains.skia/Path/isInterpolatable/#org.jetbrains.skia.Path?/PointingToDeclaration/skiko/org.jetbrains.skia/-path/is-interpolatable.html
+$dokka.location:org.jetbrains.skia/Path/isLastContourClosed/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/is-last-contour-closed.html
+$dokka.location:org.jetbrains.skia/Path/isOval/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/is-oval.html
+$dokka.location:org.jetbrains.skia/Path/isRRect/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/is-r-rect.html
+$dokka.location:org.jetbrains.skia/Path/isRect/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/is-rect.html
+$dokka.location:org.jetbrains.skia/Path/isValid/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/is-valid.html
+$dokka.location:org.jetbrains.skia/Path/isVolatile/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/is-volatile.html
+$dokka.location:org.jetbrains.skia/Path/iterator/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/iterator.html
+$dokka.location:org.jetbrains.skia/Path/iterator/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/iterator.html
+$dokka.location:org.jetbrains.skia/Path/lastPt/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/last-pt.html
+$dokka.location:org.jetbrains.skia/Path/lineTo/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/line-to.html
+$dokka.location:org.jetbrains.skia/Path/lineTo/#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia/-path/line-to.html
+$dokka.location:org.jetbrains.skia/Path/makeLerp/#org.jetbrains.skia.Path?#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/make-lerp.html
+$dokka.location:org.jetbrains.skia/Path/moveTo/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/move-to.html
+$dokka.location:org.jetbrains.skia/Path/moveTo/#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia/-path/move-to.html
+$dokka.location:org.jetbrains.skia/Path/offset/#kotlin.Float#kotlin.Float#org.jetbrains.skia.Path?/PointingToDeclaration/skiko/org.jetbrains.skia/-path/offset.html
+$dokka.location:org.jetbrains.skia/Path/points/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/points.html
+$dokka.location:org.jetbrains.skia/Path/pointsCount/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/points-count.html
+$dokka.location:org.jetbrains.skia/Path/quadTo/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/quad-to.html
+$dokka.location:org.jetbrains.skia/Path/quadTo/#org.jetbrains.skia.Point#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia/-path/quad-to.html
+$dokka.location:org.jetbrains.skia/Path/rConicTo/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/r-conic-to.html
+$dokka.location:org.jetbrains.skia/Path/rCubicTo/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/r-cubic-to.html
+$dokka.location:org.jetbrains.skia/Path/rEllipticalArcTo/#kotlin.Float#kotlin.Float#kotlin.Float#org.jetbrains.skia.PathEllipseArc#org.jetbrains.skia.PathDirection#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/r-elliptical-arc-to.html
+$dokka.location:org.jetbrains.skia/Path/rLineTo/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/r-line-to.html
+$dokka.location:org.jetbrains.skia/Path/rMoveTo/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/r-move-to.html
+$dokka.location:org.jetbrains.skia/Path/rQuadTo/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/r-quad-to.html
+$dokka.location:org.jetbrains.skia/Path/reset/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/reset.html
+$dokka.location:org.jetbrains.skia/Path/reverseAddPath/#org.jetbrains.skia.Path?/PointingToDeclaration/skiko/org.jetbrains.skia/-path/reverse-add-path.html
+$dokka.location:org.jetbrains.skia/Path/rewind/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/rewind.html
+$dokka.location:org.jetbrains.skia/Path/segmentMasks/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/segment-masks.html
+$dokka.location:org.jetbrains.skia/Path/serializeToBytes/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/serialize-to-bytes.html
+$dokka.location:org.jetbrains.skia/Path/setLastPt/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/set-last-pt.html
+$dokka.location:org.jetbrains.skia/Path/setVolatile/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/set-volatile.html
+$dokka.location:org.jetbrains.skia/Path/swap/#org.jetbrains.skia.Path?/PointingToDeclaration/skiko/org.jetbrains.skia/-path/swap.html
+$dokka.location:org.jetbrains.skia/Path/tangentArcTo/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/tangent-arc-to.html
+$dokka.location:org.jetbrains.skia/Path/tangentArcTo/#org.jetbrains.skia.Point#org.jetbrains.skia.Point#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path/tangent-arc-to.html
+$dokka.location:org.jetbrains.skia/Path/transform/#org.jetbrains.skia.Matrix33#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/transform.html
+$dokka.location:org.jetbrains.skia/Path/transform/#org.jetbrains.skia.Matrix33#org.jetbrains.skia.Path?#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path/transform.html
+$dokka.location:org.jetbrains.skia/Path/updateBoundsCache/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/update-bounds-cache.html
+$dokka.location:org.jetbrains.skia/Path/verbs/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/verbs.html
+$dokka.location:org.jetbrains.skia/Path/verbsCount/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path/verbs-count.html
+$dokka.location:org.jetbrains.skia/PathDirection.CLOCKWISE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-direction/-c-l-o-c-k-w-i-s-e/index.html
+$dokka.location:org.jetbrains.skia/PathDirection.COUNTER_CLOCKWISE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-direction/-c-o-u-n-t-e-r_-c-l-o-c-k-w-i-s-e/index.html
+$dokka.location:org.jetbrains.skia/PathDirection///PointingToDeclaration/skiko/org.jetbrains.skia/-path-direction/index.html
+$dokka.location:org.jetbrains.skia/PathDirection/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-path-direction/value-of.html
+$dokka.location:org.jetbrains.skia/PathDirection/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-direction/values.html
+$dokka.location:org.jetbrains.skia/PathEffect.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/-companion/index.html
+$dokka.location:org.jetbrains.skia/PathEffect.Companion/makeCorner/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/-companion/make-corner.html
+$dokka.location:org.jetbrains.skia/PathEffect.Companion/makeDash/#kotlin.FloatArray#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/-companion/make-dash.html
+$dokka.location:org.jetbrains.skia/PathEffect.Companion/makeDiscrete/#kotlin.Float#kotlin.Float#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/-companion/make-discrete.html
+$dokka.location:org.jetbrains.skia/PathEffect.Companion/makeLine2D/#kotlin.Float#org.jetbrains.skia.Matrix33/PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/-companion/make-line2-d.html
+$dokka.location:org.jetbrains.skia/PathEffect.Companion/makePath1D/#org.jetbrains.skia.Path#kotlin.Float#kotlin.Float#org.jetbrains.skia.PathEffect.Style/PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/-companion/make-path1-d.html
+$dokka.location:org.jetbrains.skia/PathEffect.Companion/makePath2D/#org.jetbrains.skia.Matrix33#org.jetbrains.skia.Path/PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/-companion/make-path2-d.html
+$dokka.location:org.jetbrains.skia/PathEffect.Style.MORPH///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-effect/-style/-m-o-r-p-h/index.html
+$dokka.location:org.jetbrains.skia/PathEffect.Style.ROTATE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-effect/-style/-r-o-t-a-t-e/index.html
+$dokka.location:org.jetbrains.skia/PathEffect.Style.TRANSLATE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-effect/-style/-t-r-a-n-s-l-a-t-e/index.html
+$dokka.location:org.jetbrains.skia/PathEffect.Style///PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/-style/index.html
+$dokka.location:org.jetbrains.skia/PathEffect.Style/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/-style/value-of.html
+$dokka.location:org.jetbrains.skia/PathEffect.Style/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/-style/values.html
+$dokka.location:org.jetbrains.skia/PathEffect///PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/index.html
+$dokka.location:org.jetbrains.skia/PathEffect/makeCompose/#org.jetbrains.skia.PathEffect?/PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/make-compose.html
+$dokka.location:org.jetbrains.skia/PathEffect/makeSum/#org.jetbrains.skia.PathEffect?/PointingToDeclaration/skiko/org.jetbrains.skia/-path-effect/make-sum.html
+$dokka.location:org.jetbrains.skia/PathEllipseArc.LARGER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-ellipse-arc/-l-a-r-g-e-r/index.html
+$dokka.location:org.jetbrains.skia/PathEllipseArc.SMALLER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-ellipse-arc/-s-m-a-l-l-e-r/index.html
+$dokka.location:org.jetbrains.skia/PathEllipseArc///PointingToDeclaration/skiko/org.jetbrains.skia/-path-ellipse-arc/index.html
+$dokka.location:org.jetbrains.skia/PathEllipseArc/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-path-ellipse-arc/value-of.html
+$dokka.location:org.jetbrains.skia/PathEllipseArc/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-ellipse-arc/values.html
+$dokka.location:org.jetbrains.skia/PathFillMode.EVEN_ODD///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-fill-mode/-e-v-e-n_-o-d-d/index.html
+$dokka.location:org.jetbrains.skia/PathFillMode.INVERSE_EVEN_ODD///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-fill-mode/-i-n-v-e-r-s-e_-e-v-e-n_-o-d-d/index.html
+$dokka.location:org.jetbrains.skia/PathFillMode.INVERSE_WINDING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-fill-mode/-i-n-v-e-r-s-e_-w-i-n-d-i-n-g/index.html
+$dokka.location:org.jetbrains.skia/PathFillMode.WINDING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-fill-mode/-w-i-n-d-i-n-g/index.html
+$dokka.location:org.jetbrains.skia/PathFillMode///PointingToDeclaration/skiko/org.jetbrains.skia/-path-fill-mode/index.html
+$dokka.location:org.jetbrains.skia/PathFillMode/inverse/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-fill-mode/inverse.html
+$dokka.location:org.jetbrains.skia/PathFillMode/isInverse/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-fill-mode/is-inverse.html
+$dokka.location:org.jetbrains.skia/PathFillMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-path-fill-mode/value-of.html
+$dokka.location:org.jetbrains.skia/PathFillMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-fill-mode/values.html
+$dokka.location:org.jetbrains.skia/PathMeasure.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/-companion/index.html
+$dokka.location:org.jetbrains.skia/PathMeasure///PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/index.html
+$dokka.location:org.jetbrains.skia/PathMeasure/PathMeasure/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/-path-measure.html
+$dokka.location:org.jetbrains.skia/PathMeasure/PathMeasure/#org.jetbrains.skia.Path?#kotlin.Boolean#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/-path-measure.html
+$dokka.location:org.jetbrains.skia/PathMeasure/getMatrix/#kotlin.Float#kotlin.Boolean#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/get-matrix.html
+$dokka.location:org.jetbrains.skia/PathMeasure/getPosition/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/get-position.html
+$dokka.location:org.jetbrains.skia/PathMeasure/getRSXform/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/get-r-s-xform.html
+$dokka.location:org.jetbrains.skia/PathMeasure/getSegment/#kotlin.Float#kotlin.Float#org.jetbrains.skia.Path#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/get-segment.html
+$dokka.location:org.jetbrains.skia/PathMeasure/getTangent/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/get-tangent.html
+$dokka.location:org.jetbrains.skia/PathMeasure/isClosed/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/is-closed.html
+$dokka.location:org.jetbrains.skia/PathMeasure/length/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/length.html
+$dokka.location:org.jetbrains.skia/PathMeasure/nextContour/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/next-contour.html
+$dokka.location:org.jetbrains.skia/PathMeasure/setPath/#org.jetbrains.skia.Path?#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path-measure/set-path.html
+$dokka.location:org.jetbrains.skia/PathOp.DIFFERENCE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-op/-d-i-f-f-e-r-e-n-c-e/index.html
+$dokka.location:org.jetbrains.skia/PathOp.INTERSECT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-op/-i-n-t-e-r-s-e-c-t/index.html
+$dokka.location:org.jetbrains.skia/PathOp.REVERSE_DIFFERENCE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-op/-r-e-v-e-r-s-e_-d-i-f-f-e-r-e-n-c-e/index.html
+$dokka.location:org.jetbrains.skia/PathOp.UNION///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-op/-u-n-i-o-n/index.html
+$dokka.location:org.jetbrains.skia/PathOp.XOR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-op/-x-o-r/index.html
+$dokka.location:org.jetbrains.skia/PathOp///PointingToDeclaration/skiko/org.jetbrains.skia/-path-op/index.html
+$dokka.location:org.jetbrains.skia/PathOp/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-path-op/value-of.html
+$dokka.location:org.jetbrains.skia/PathOp/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-op/values.html
+$dokka.location:org.jetbrains.skia/PathSegment///PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/index.html
+$dokka.location:org.jetbrains.skia/PathSegment/PathSegment/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Boolean#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/-path-segment.html
+$dokka.location:org.jetbrains.skia/PathSegment/PathSegment/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/-path-segment.html
+$dokka.location:org.jetbrains.skia/PathSegment/PathSegment/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/-path-segment.html
+$dokka.location:org.jetbrains.skia/PathSegment/PathSegment/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/-path-segment.html
+$dokka.location:org.jetbrains.skia/PathSegment/PathSegment/#kotlin.Int#kotlin.Float#kotlin.Float#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/-path-segment.html
+$dokka.location:org.jetbrains.skia/PathSegment/PathSegment/#org.jetbrains.skia.PathVerb#org.jetbrains.skia.Point?#org.jetbrains.skia.Point?#org.jetbrains.skia.Point?#org.jetbrains.skia.Point?#kotlin.Float#kotlin.Boolean#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/-path-segment.html
+$dokka.location:org.jetbrains.skia/PathSegment/conicWeight/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/conic-weight.html
+$dokka.location:org.jetbrains.skia/PathSegment/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/equals.html
+$dokka.location:org.jetbrains.skia/PathSegment/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/hash-code.html
+$dokka.location:org.jetbrains.skia/PathSegment/isCloseLine/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/is-close-line.html
+$dokka.location:org.jetbrains.skia/PathSegment/isClosedContour/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/is-closed-contour.html
+$dokka.location:org.jetbrains.skia/PathSegment/p0/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/p0.html
+$dokka.location:org.jetbrains.skia/PathSegment/p1/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/p1.html
+$dokka.location:org.jetbrains.skia/PathSegment/p2/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/p2.html
+$dokka.location:org.jetbrains.skia/PathSegment/p3/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/p3.html
+$dokka.location:org.jetbrains.skia/PathSegment/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/to-string.html
+$dokka.location:org.jetbrains.skia/PathSegment/verb/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment/verb.html
+$dokka.location:org.jetbrains.skia/PathSegmentIterator.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-iterator/-companion/index.html
+$dokka.location:org.jetbrains.skia/PathSegmentIterator.Companion/make/#org.jetbrains.skia.Path?#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-iterator/-companion/make.html
+$dokka.location:org.jetbrains.skia/PathSegmentIterator///PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-iterator/index.html
+$dokka.location:org.jetbrains.skia/PathSegmentIterator/_nextSegment/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-iterator/_next-segment.html
+$dokka.location:org.jetbrains.skia/PathSegmentIterator/_path/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-iterator/_path.html
+$dokka.location:org.jetbrains.skia/PathSegmentIterator/hasNext/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-iterator/has-next.html
+$dokka.location:org.jetbrains.skia/PathSegmentIterator/next/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-iterator/next.html
+$dokka.location:org.jetbrains.skia/PathSegmentIterator/remove/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-iterator/remove.html
+$dokka.location:org.jetbrains.skia/PathSegmentMask.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-mask/-companion/index.html
+$dokka.location:org.jetbrains.skia/PathSegmentMask.Companion/CONIC/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-mask/-companion/-c-o-n-i-c.html
+$dokka.location:org.jetbrains.skia/PathSegmentMask.Companion/CUBIC/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-mask/-companion/-c-u-b-i-c.html
+$dokka.location:org.jetbrains.skia/PathSegmentMask.Companion/LINE/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-mask/-companion/-l-i-n-e.html
+$dokka.location:org.jetbrains.skia/PathSegmentMask.Companion/QUAD/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-mask/-companion/-q-u-a-d.html
+$dokka.location:org.jetbrains.skia/PathSegmentMask///PointingToDeclaration/skiko/org.jetbrains.skia/-path-segment-mask/index.html
+$dokka.location:org.jetbrains.skia/PathVerb.CLOSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-verb/-c-l-o-s-e/index.html
+$dokka.location:org.jetbrains.skia/PathVerb.CONIC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-verb/-c-o-n-i-c/index.html
+$dokka.location:org.jetbrains.skia/PathVerb.CUBIC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-verb/-c-u-b-i-c/index.html
+$dokka.location:org.jetbrains.skia/PathVerb.DONE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-verb/-d-o-n-e/index.html
+$dokka.location:org.jetbrains.skia/PathVerb.LINE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-verb/-l-i-n-e/index.html
+$dokka.location:org.jetbrains.skia/PathVerb.MOVE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-verb/-m-o-v-e/index.html
+$dokka.location:org.jetbrains.skia/PathVerb.QUAD///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-path-verb/-q-u-a-d/index.html
+$dokka.location:org.jetbrains.skia/PathVerb///PointingToDeclaration/skiko/org.jetbrains.skia/-path-verb/index.html
+$dokka.location:org.jetbrains.skia/PathVerb/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-path-verb/value-of.html
+$dokka.location:org.jetbrains.skia/PathVerb/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-path-verb/values.html
+$dokka.location:org.jetbrains.skia/Pattern///PointingToDeclaration/skiko/org.jetbrains.skia/-pattern/index.html
+$dokka.location:org.jetbrains.skia/Pattern/Pattern/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-pattern/-pattern.html
+$dokka.location:org.jetbrains.skia/Pattern/matcher/#kotlin.CharSequence/PointingToDeclaration/skiko/org.jetbrains.skia/-pattern/matcher.html
+$dokka.location:org.jetbrains.skia/Pattern/split/#kotlin.CharSequence/PointingToDeclaration/skiko/org.jetbrains.skia/-pattern/split.html
+$dokka.location:org.jetbrains.skia/Picture.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-picture/-companion/index.html
+$dokka.location:org.jetbrains.skia/Picture.Companion/makeFromData/#org.jetbrains.skia.Data?/PointingToDeclaration/skiko/org.jetbrains.skia/-picture/-companion/make-from-data.html
+$dokka.location:org.jetbrains.skia/Picture.Companion/makePlaceholder/#org.jetbrains.skia.Rect/PointingToDeclaration/skiko/org.jetbrains.skia/-picture/-companion/make-placeholder.html
+$dokka.location:org.jetbrains.skia/Picture///PointingToDeclaration/skiko/org.jetbrains.skia/-picture/index.html
+$dokka.location:org.jetbrains.skia/Picture/approximateBytesUsed/#/PointingToDeclaration/skiko/org.jetbrains.skia/-picture/approximate-bytes-used.html
+$dokka.location:org.jetbrains.skia/Picture/approximateOpCount/#/PointingToDeclaration/skiko/org.jetbrains.skia/-picture/approximate-op-count.html
+$dokka.location:org.jetbrains.skia/Picture/cullRect/#/PointingToDeclaration/skiko/org.jetbrains.skia/-picture/cull-rect.html
+$dokka.location:org.jetbrains.skia/Picture/makeShader/#org.jetbrains.skia.FilterTileMode#org.jetbrains.skia.FilterTileMode#org.jetbrains.skia.FilterMode#org.jetbrains.skia.Matrix33?#org.jetbrains.skia.Rect?/PointingToDeclaration/skiko/org.jetbrains.skia/-picture/make-shader.html
+$dokka.location:org.jetbrains.skia/Picture/playback/#org.jetbrains.skia.Canvas?#kotlin.Function0[kotlin.Boolean]?/PointingToDeclaration/skiko/org.jetbrains.skia/-picture/playback.html
+$dokka.location:org.jetbrains.skia/Picture/serializeToData/#/PointingToDeclaration/skiko/org.jetbrains.skia/-picture/serialize-to-data.html
+$dokka.location:org.jetbrains.skia/Picture/uniqueId/#/PointingToDeclaration/skiko/org.jetbrains.skia/-picture/unique-id.html
+$dokka.location:org.jetbrains.skia/PictureRecorder.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-picture-recorder/-companion/index.html
+$dokka.location:org.jetbrains.skia/PictureRecorder///PointingToDeclaration/skiko/org.jetbrains.skia/-picture-recorder/index.html
+$dokka.location:org.jetbrains.skia/PictureRecorder/PictureRecorder/#/PointingToDeclaration/skiko/org.jetbrains.skia/-picture-recorder/-picture-recorder.html
+$dokka.location:org.jetbrains.skia/PictureRecorder/beginRecording/#org.jetbrains.skia.Rect/PointingToDeclaration/skiko/org.jetbrains.skia/-picture-recorder/begin-recording.html
+$dokka.location:org.jetbrains.skia/PictureRecorder/finishRecordingAsPicture/#/PointingToDeclaration/skiko/org.jetbrains.skia/-picture-recorder/finish-recording-as-picture.html
+$dokka.location:org.jetbrains.skia/PictureRecorder/finishRecordingAsPicture/#org.jetbrains.skia.Rect/PointingToDeclaration/skiko/org.jetbrains.skia/-picture-recorder/finish-recording-as-picture.html
+$dokka.location:org.jetbrains.skia/PictureRecorder/recordingCanvas/#/PointingToDeclaration/skiko/org.jetbrains.skia/-picture-recorder/recording-canvas.html
+$dokka.location:org.jetbrains.skia/PixelGeometry.BGR_H///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-pixel-geometry/-b-g-r_-h/index.html
+$dokka.location:org.jetbrains.skia/PixelGeometry.BGR_V///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-pixel-geometry/-b-g-r_-v/index.html
+$dokka.location:org.jetbrains.skia/PixelGeometry.RGB_H///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-pixel-geometry/-r-g-b_-h/index.html
+$dokka.location:org.jetbrains.skia/PixelGeometry.RGB_V///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-pixel-geometry/-r-g-b_-v/index.html
+$dokka.location:org.jetbrains.skia/PixelGeometry.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-pixel-geometry/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skia/PixelGeometry///PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-geometry/index.html
+$dokka.location:org.jetbrains.skia/PixelGeometry/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-geometry/value-of.html
+$dokka.location:org.jetbrains.skia/PixelGeometry/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-geometry/values.html
+$dokka.location:org.jetbrains.skia/PixelRef.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-ref/-companion/index.html
+$dokka.location:org.jetbrains.skia/PixelRef///PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-ref/index.html
+$dokka.location:org.jetbrains.skia/PixelRef/generationId/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-ref/generation-id.html
+$dokka.location:org.jetbrains.skia/PixelRef/height/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-ref/height.html
+$dokka.location:org.jetbrains.skia/PixelRef/isImmutable/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-ref/is-immutable.html
+$dokka.location:org.jetbrains.skia/PixelRef/notifyPixelsChanged/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-ref/notify-pixels-changed.html
+$dokka.location:org.jetbrains.skia/PixelRef/rowBytes/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-ref/row-bytes.html
+$dokka.location:org.jetbrains.skia/PixelRef/setImmutable/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-ref/set-immutable.html
+$dokka.location:org.jetbrains.skia/PixelRef/width/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixel-ref/width.html
+$dokka.location:org.jetbrains.skia/Pixmap.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/-companion/index.html
+$dokka.location:org.jetbrains.skia/Pixmap.Companion/make/#org.jetbrains.skia.ImageInfo#org.jetbrains.skia.Data#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/-companion/make.html
+$dokka.location:org.jetbrains.skia/Pixmap.Companion/make/#org.jetbrains.skia.ImageInfo#org.jetbrains.skia.impl.NativePointer#kotlin.Int#org.jetbrains.skia.impl.Managed?/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/-companion/make.html
+$dokka.location:org.jetbrains.skia/Pixmap///PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/index.html
+$dokka.location:org.jetbrains.skia/Pixmap/Pixmap/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/-pixmap.html
+$dokka.location:org.jetbrains.skia/Pixmap/addr/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/addr.html
+$dokka.location:org.jetbrains.skia/Pixmap/buffer/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/buffer.html
+$dokka.location:org.jetbrains.skia/Pixmap/computeByteSize/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/compute-byte-size.html
+$dokka.location:org.jetbrains.skia/Pixmap/computeIsOpaque/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/compute-is-opaque.html
+$dokka.location:org.jetbrains.skia/Pixmap/erase/#kotlin.Int#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/erase.html
+$dokka.location:org.jetbrains.skia/Pixmap/erase/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/erase.html
+$dokka.location:org.jetbrains.skia/Pixmap/extractSubset/#org.jetbrains.skia.Pixmap#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/extract-subset.html
+$dokka.location:org.jetbrains.skia/Pixmap/extractSubset/#org.jetbrains.skia.impl.NativePointer#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/extract-subset.html
+$dokka.location:org.jetbrains.skia/Pixmap/getAddr/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/get-addr.html
+$dokka.location:org.jetbrains.skia/Pixmap/getAlphaF/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/get-alpha-f.html
+$dokka.location:org.jetbrains.skia/Pixmap/getColor/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/get-color.html
+$dokka.location:org.jetbrains.skia/Pixmap/info/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/info.html
+$dokka.location:org.jetbrains.skia/Pixmap/readPixels/#org.jetbrains.skia.ImageInfo#org.jetbrains.skia.impl.NativePointer#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/read-pixels.html
+$dokka.location:org.jetbrains.skia/Pixmap/readPixels/#org.jetbrains.skia.ImageInfo#org.jetbrains.skia.impl.NativePointer#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/read-pixels.html
+$dokka.location:org.jetbrains.skia/Pixmap/readPixels/#org.jetbrains.skia.Pixmap#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/read-pixels.html
+$dokka.location:org.jetbrains.skia/Pixmap/readPixels/#org.jetbrains.skia.Pixmap?/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/read-pixels.html
+$dokka.location:org.jetbrains.skia/Pixmap/reset/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/reset.html
+$dokka.location:org.jetbrains.skia/Pixmap/reset/#org.jetbrains.skia.ImageInfo#org.jetbrains.skia.Data#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/reset.html
+$dokka.location:org.jetbrains.skia/Pixmap/reset/#org.jetbrains.skia.ImageInfo#org.jetbrains.skia.impl.NativePointer#kotlin.Int#org.jetbrains.skia.impl.Managed?/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/reset.html
+$dokka.location:org.jetbrains.skia/Pixmap/rowBytes/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/row-bytes.html
+$dokka.location:org.jetbrains.skia/Pixmap/rowBytesAsPixels/#/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/row-bytes-as-pixels.html
+$dokka.location:org.jetbrains.skia/Pixmap/scalePixels/#org.jetbrains.skia.Pixmap?#org.jetbrains.skia.SamplingMode/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/scale-pixels.html
+$dokka.location:org.jetbrains.skia/Pixmap/setColorSpace/#org.jetbrains.skia.ColorSpace?/PointingToDeclaration/skiko/org.jetbrains.skia/-pixmap/set-color-space.html
+$dokka.location:org.jetbrains.skia/Point.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-point/-companion/index.html
+$dokka.location:org.jetbrains.skia/Point.Companion/ZERO/#/PointingToDeclaration/skiko/org.jetbrains.skia/-point/-companion/-z-e-r-o.html
+$dokka.location:org.jetbrains.skia/Point.Companion/flattenArray/#kotlin.Array[org.jetbrains.skia.Point]?/PointingToDeclaration/skiko/org.jetbrains.skia/-point/-companion/flatten-array.html
+$dokka.location:org.jetbrains.skia/Point.Companion/fromArray/#kotlin.FloatArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-point/-companion/from-array.html
+$dokka.location:org.jetbrains.skia/Point///PointingToDeclaration/skiko/org.jetbrains.skia/-point/index.html
+$dokka.location:org.jetbrains.skia/Point/Point/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-point/-point.html
+$dokka.location:org.jetbrains.skia/Point/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-point/equals.html
+$dokka.location:org.jetbrains.skia/Point/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-point/hash-code.html
+$dokka.location:org.jetbrains.skia/Point/isEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-point/is-empty.html
+$dokka.location:org.jetbrains.skia/Point/offset/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-point/offset.html
+$dokka.location:org.jetbrains.skia/Point/offset/#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia/-point/offset.html
+$dokka.location:org.jetbrains.skia/Point/scale/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-point/scale.html
+$dokka.location:org.jetbrains.skia/Point/scale/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-point/scale.html
+$dokka.location:org.jetbrains.skia/Point/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-point/to-string.html
+$dokka.location:org.jetbrains.skia/Point/x/#/PointingToDeclaration/skiko/org.jetbrains.skia/-point/x.html
+$dokka.location:org.jetbrains.skia/Point/y/#/PointingToDeclaration/skiko/org.jetbrains.skia/-point/y.html
+$dokka.location:org.jetbrains.skia/Point3///PointingToDeclaration/skiko/org.jetbrains.skia/-point3/index.html
+$dokka.location:org.jetbrains.skia/Point3/Point3/#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-point3/-point3.html
+$dokka.location:org.jetbrains.skia/Point3/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-point3/equals.html
+$dokka.location:org.jetbrains.skia/Point3/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-point3/hash-code.html
+$dokka.location:org.jetbrains.skia/Point3/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-point3/to-string.html
+$dokka.location:org.jetbrains.skia/Point3/x/#/PointingToDeclaration/skiko/org.jetbrains.skia/-point3/x.html
+$dokka.location:org.jetbrains.skia/Point3/y/#/PointingToDeclaration/skiko/org.jetbrains.skia/-point3/y.html
+$dokka.location:org.jetbrains.skia/Point3/z/#/PointingToDeclaration/skiko/org.jetbrains.skia/-point3/z.html
+$dokka.location:org.jetbrains.skia/RRect.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/index.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeComplexLTRB/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.FloatArray/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-complex-l-t-r-b.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeComplexXYWH/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.FloatArray/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-complex-x-y-w-h.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeLTRB/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-l-t-r-b.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeLTRB/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-l-t-r-b.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeLTRB/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-l-t-r-b.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeNinePatchLTRB/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-nine-patch-l-t-r-b.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeNinePatchXYWH/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-nine-patch-x-y-w-h.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeOvalLTRB/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-oval-l-t-r-b.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeOvalXYWH/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-oval-x-y-w-h.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makePillLTRB/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-pill-l-t-r-b.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makePillXYWH/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-pill-x-y-w-h.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeXYWH/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-x-y-w-h.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeXYWH/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-x-y-w-h.html
+$dokka.location:org.jetbrains.skia/RRect.Companion/makeXYWH/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/-companion/make-x-y-w-h.html
+$dokka.location:org.jetbrains.skia/RRect///PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/index.html
+$dokka.location:org.jetbrains.skia/RRect/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/equals.html
+$dokka.location:org.jetbrains.skia/RRect/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/hash-code.html
+$dokka.location:org.jetbrains.skia/RRect/inflate/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/inflate.html
+$dokka.location:org.jetbrains.skia/RRect/radii/#/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/radii.html
+$dokka.location:org.jetbrains.skia/RRect/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-r-rect/to-string.html
+$dokka.location:org.jetbrains.skia/RSXform.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-r-s-xform/-companion/index.html
+$dokka.location:org.jetbrains.skia/RSXform.Companion/makeFromRadians/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-s-xform/-companion/make-from-radians.html
+$dokka.location:org.jetbrains.skia/RSXform///PointingToDeclaration/skiko/org.jetbrains.skia/-r-s-xform/index.html
+$dokka.location:org.jetbrains.skia/RSXform/RSXform/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-r-s-xform/-r-s-xform.html
+$dokka.location:org.jetbrains.skia/RSXform/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-r-s-xform/equals.html
+$dokka.location:org.jetbrains.skia/RSXform/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-r-s-xform/hash-code.html
+$dokka.location:org.jetbrains.skia/RSXform/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-r-s-xform/to-string.html
+$dokka.location:org.jetbrains.skia/Rect.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-rect/-companion/index.html
+$dokka.location:org.jetbrains.skia/Rect.Companion/makeLTRB/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/-companion/make-l-t-r-b.html
+$dokka.location:org.jetbrains.skia/Rect.Companion/makeWH/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/-companion/make-w-h.html
+$dokka.location:org.jetbrains.skia/Rect.Companion/makeWH/#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/-companion/make-w-h.html
+$dokka.location:org.jetbrains.skia/Rect.Companion/makeXYWH/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/-companion/make-x-y-w-h.html
+$dokka.location:org.jetbrains.skia/Rect///PointingToDeclaration/skiko/org.jetbrains.skia/-rect/index.html
+$dokka.location:org.jetbrains.skia/Rect/Rect/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/-rect.html
+$dokka.location:org.jetbrains.skia/Rect/bottom/#/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/bottom.html
+$dokka.location:org.jetbrains.skia/Rect/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/equals.html
+$dokka.location:org.jetbrains.skia/Rect/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/hash-code.html
+$dokka.location:org.jetbrains.skia/Rect/height/#/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/height.html
+$dokka.location:org.jetbrains.skia/Rect/inflate/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/inflate.html
+$dokka.location:org.jetbrains.skia/Rect/intersect/#org.jetbrains.skia.Rect/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/intersect.html
+$dokka.location:org.jetbrains.skia/Rect/isEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/is-empty.html
+$dokka.location:org.jetbrains.skia/Rect/left/#/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/left.html
+$dokka.location:org.jetbrains.skia/Rect/offset/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/offset.html
+$dokka.location:org.jetbrains.skia/Rect/offset/#org.jetbrains.skia.Point/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/offset.html
+$dokka.location:org.jetbrains.skia/Rect/right/#/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/right.html
+$dokka.location:org.jetbrains.skia/Rect/scale/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/scale.html
+$dokka.location:org.jetbrains.skia/Rect/scale/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/scale.html
+$dokka.location:org.jetbrains.skia/Rect/toIRect/#/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/to-i-rect.html
+$dokka.location:org.jetbrains.skia/Rect/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/to-string.html
+$dokka.location:org.jetbrains.skia/Rect/top/#/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/top.html
+$dokka.location:org.jetbrains.skia/Rect/width/#/PointingToDeclaration/skiko/org.jetbrains.skia/-rect/width.html
+$dokka.location:org.jetbrains.skia/Region.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-region/-companion/index.html
+$dokka.location:org.jetbrains.skia/Region.Op.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-region/-op/-companion/index.html
+$dokka.location:org.jetbrains.skia/Region.Op.DIFFERENCE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-region/-op/-d-i-f-f-e-r-e-n-c-e/index.html
+$dokka.location:org.jetbrains.skia/Region.Op.INTERSECT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-region/-op/-i-n-t-e-r-s-e-c-t/index.html
+$dokka.location:org.jetbrains.skia/Region.Op.REPLACE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-region/-op/-r-e-p-l-a-c-e/index.html
+$dokka.location:org.jetbrains.skia/Region.Op.REVERSE_DIFFERENCE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-region/-op/-r-e-v-e-r-s-e_-d-i-f-f-e-r-e-n-c-e/index.html
+$dokka.location:org.jetbrains.skia/Region.Op.UNION///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-region/-op/-u-n-i-o-n/index.html
+$dokka.location:org.jetbrains.skia/Region.Op.XOR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-region/-op/-x-o-r/index.html
+$dokka.location:org.jetbrains.skia/Region.Op///PointingToDeclaration/skiko/org.jetbrains.skia/-region/-op/index.html
+$dokka.location:org.jetbrains.skia/Region.Op/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-region/-op/value-of.html
+$dokka.location:org.jetbrains.skia/Region.Op/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-region/-op/values.html
+$dokka.location:org.jetbrains.skia/Region///PointingToDeclaration/skiko/org.jetbrains.skia/-region/index.html
+$dokka.location:org.jetbrains.skia/Region/Region/#/PointingToDeclaration/skiko/org.jetbrains.skia/-region/-region.html
+$dokka.location:org.jetbrains.skia/Region/bounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-region/bounds.html
+$dokka.location:org.jetbrains.skia/Region/computeRegionComplexity/#/PointingToDeclaration/skiko/org.jetbrains.skia/-region/compute-region-complexity.html
+$dokka.location:org.jetbrains.skia/Region/contains/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-region/contains.html
+$dokka.location:org.jetbrains.skia/Region/contains/#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-region/contains.html
+$dokka.location:org.jetbrains.skia/Region/contains/#org.jetbrains.skia.Region?/PointingToDeclaration/skiko/org.jetbrains.skia/-region/contains.html
+$dokka.location:org.jetbrains.skia/Region/getBoundaryPath/#org.jetbrains.skia.Path?/PointingToDeclaration/skiko/org.jetbrains.skia/-region/get-boundary-path.html
+$dokka.location:org.jetbrains.skia/Region/intersects/#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-region/intersects.html
+$dokka.location:org.jetbrains.skia/Region/intersects/#org.jetbrains.skia.Region?/PointingToDeclaration/skiko/org.jetbrains.skia/-region/intersects.html
+$dokka.location:org.jetbrains.skia/Region/isComplex/#/PointingToDeclaration/skiko/org.jetbrains.skia/-region/is-complex.html
+$dokka.location:org.jetbrains.skia/Region/isEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-region/is-empty.html
+$dokka.location:org.jetbrains.skia/Region/isRect/#/PointingToDeclaration/skiko/org.jetbrains.skia/-region/is-rect.html
+$dokka.location:org.jetbrains.skia/Region/op/#org.jetbrains.skia.IRect#org.jetbrains.skia.Region.Op/PointingToDeclaration/skiko/org.jetbrains.skia/-region/op.html
+$dokka.location:org.jetbrains.skia/Region/op/#org.jetbrains.skia.IRect#org.jetbrains.skia.Region?#org.jetbrains.skia.Region.Op/PointingToDeclaration/skiko/org.jetbrains.skia/-region/op.html
+$dokka.location:org.jetbrains.skia/Region/op/#org.jetbrains.skia.Region?#org.jetbrains.skia.IRect#org.jetbrains.skia.Region.Op/PointingToDeclaration/skiko/org.jetbrains.skia/-region/op.html
+$dokka.location:org.jetbrains.skia/Region/op/#org.jetbrains.skia.Region?#org.jetbrains.skia.Region.Op/PointingToDeclaration/skiko/org.jetbrains.skia/-region/op.html
+$dokka.location:org.jetbrains.skia/Region/op/#org.jetbrains.skia.Region?#org.jetbrains.skia.Region?#org.jetbrains.skia.Region.Op/PointingToDeclaration/skiko/org.jetbrains.skia/-region/op.html
+$dokka.location:org.jetbrains.skia/Region/quickContains/#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-region/quick-contains.html
+$dokka.location:org.jetbrains.skia/Region/quickReject/#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-region/quick-reject.html
+$dokka.location:org.jetbrains.skia/Region/quickReject/#org.jetbrains.skia.Region?/PointingToDeclaration/skiko/org.jetbrains.skia/-region/quick-reject.html
+$dokka.location:org.jetbrains.skia/Region/set/#org.jetbrains.skia.Region?/PointingToDeclaration/skiko/org.jetbrains.skia/-region/set.html
+$dokka.location:org.jetbrains.skia/Region/setEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-region/set-empty.html
+$dokka.location:org.jetbrains.skia/Region/setPath/#org.jetbrains.skia.Path?#org.jetbrains.skia.Region?/PointingToDeclaration/skiko/org.jetbrains.skia/-region/set-path.html
+$dokka.location:org.jetbrains.skia/Region/setRect/#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-region/set-rect.html
+$dokka.location:org.jetbrains.skia/Region/setRects/#kotlin.Array[org.jetbrains.skia.IRect]/PointingToDeclaration/skiko/org.jetbrains.skia/-region/set-rects.html
+$dokka.location:org.jetbrains.skia/Region/setRegion/#org.jetbrains.skia.Region?/PointingToDeclaration/skiko/org.jetbrains.skia/-region/set-region.html
+$dokka.location:org.jetbrains.skia/Region/translate/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-region/translate.html
+$dokka.location:org.jetbrains.skia/RuntimeEffect.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-effect/-companion/index.html
+$dokka.location:org.jetbrains.skia/RuntimeEffect.Companion/makeForColorFilter/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-effect/-companion/make-for-color-filter.html
+$dokka.location:org.jetbrains.skia/RuntimeEffect.Companion/makeForShader/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-effect/-companion/make-for-shader.html
+$dokka.location:org.jetbrains.skia/RuntimeEffect///PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-effect/index.html
+$dokka.location:org.jetbrains.skia/RuntimeEffect/makeShader/#org.jetbrains.skia.Data?#kotlin.Array[org.jetbrains.skia.Shader?]?#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-effect/make-shader.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/-companion/index.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder///PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/index.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/RuntimeShaderBuilder/#org.jetbrains.skia.RuntimeEffect/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/-runtime-shader-builder.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/child/#kotlin.String#org.jetbrains.skia.ColorFilter/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/child.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/child/#kotlin.String#org.jetbrains.skia.Shader/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/child.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/makeShader/#org.jetbrains.skia.Matrix33?/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/make-shader.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/uniform/#kotlin.String#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/uniform.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/uniform/#kotlin.String#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/uniform.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/uniform/#kotlin.String#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/uniform.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/uniform/#kotlin.String#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/uniform.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/uniform/#kotlin.String#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/uniform.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/uniform/#kotlin.String#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/uniform.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/uniform/#kotlin.String#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/uniform.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/uniform/#kotlin.String#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/uniform.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/uniform/#kotlin.String#org.jetbrains.skia.Matrix22/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/uniform.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/uniform/#kotlin.String#org.jetbrains.skia.Matrix33/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/uniform.html
+$dokka.location:org.jetbrains.skia/RuntimeShaderBuilder/uniform/#kotlin.String#org.jetbrains.skia.Matrix44/PointingToDeclaration/skiko/org.jetbrains.skia/-runtime-shader-builder/uniform.html
+$dokka.location:org.jetbrains.skia/SamplingMode.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-sampling-mode/-companion/index.html
+$dokka.location:org.jetbrains.skia/SamplingMode.Companion/CATMULL_ROM/#/PointingToDeclaration/skiko/org.jetbrains.skia/-sampling-mode/-companion/-c-a-t-m-u-l-l_-r-o-m.html
+$dokka.location:org.jetbrains.skia/SamplingMode.Companion/DEFAULT/#/PointingToDeclaration/skiko/org.jetbrains.skia/-sampling-mode/-companion/-d-e-f-a-u-l-t.html
+$dokka.location:org.jetbrains.skia/SamplingMode.Companion/LINEAR/#/PointingToDeclaration/skiko/org.jetbrains.skia/-sampling-mode/-companion/-l-i-n-e-a-r.html
+$dokka.location:org.jetbrains.skia/SamplingMode.Companion/MITCHELL/#/PointingToDeclaration/skiko/org.jetbrains.skia/-sampling-mode/-companion/-m-i-t-c-h-e-l-l.html
+$dokka.location:org.jetbrains.skia/SamplingMode///PointingToDeclaration/skiko/org.jetbrains.skia/-sampling-mode/index.html
+$dokka.location:org.jetbrains.skia/SamplingMode/_pack/#/PointingToDeclaration/skiko/org.jetbrains.skia/-sampling-mode/_pack.html
+$dokka.location:org.jetbrains.skia/SamplingMode/_packedInt1/#/PointingToDeclaration/skiko/org.jetbrains.skia/-sampling-mode/_packed-int1.html
+$dokka.location:org.jetbrains.skia/SamplingMode/_packedInt2/#/PointingToDeclaration/skiko/org.jetbrains.skia/-sampling-mode/_packed-int2.html
+$dokka.location:org.jetbrains.skia/Shader.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/index.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeBlend/#org.jetbrains.skia.BlendMode#org.jetbrains.skia.Shader?#org.jetbrains.skia.Shader?/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-blend.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeColor/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-color.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeColor/#org.jetbrains.skia.Color4f#org.jetbrains.skia.ColorSpace?/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-color.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeEmpty/#/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-empty.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeFractalNoise/#kotlin.Float#kotlin.Float#kotlin.Int#kotlin.Float#org.jetbrains.skia.ISize/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-fractal-noise.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeLinearGradient/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Array[org.jetbrains.skia.Color4f]#org.jetbrains.skia.ColorSpace?#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-linear-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeLinearGradient/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.IntArray#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-linear-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeLinearGradient/#org.jetbrains.skia.Point#org.jetbrains.skia.Point#kotlin.Array[org.jetbrains.skia.Color4f]#org.jetbrains.skia.ColorSpace?#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-linear-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeLinearGradient/#org.jetbrains.skia.Point#org.jetbrains.skia.Point#kotlin.IntArray#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-linear-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeLinearGradient/#org.jetbrains.skia.Point#org.jetbrains.skia.Point#kotlin.IntArray#kotlin.FloatArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-linear-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeLinearGradient/#org.jetbrains.skia.Point#org.jetbrains.skia.Point#kotlin.IntArray/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-linear-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeRadialGradient/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Array[org.jetbrains.skia.Color4f]#org.jetbrains.skia.ColorSpace?#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-radial-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeRadialGradient/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.IntArray#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-radial-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeRadialGradient/#org.jetbrains.skia.Point#kotlin.Float#kotlin.Array[org.jetbrains.skia.Color4f]#org.jetbrains.skia.ColorSpace?#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-radial-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeRadialGradient/#org.jetbrains.skia.Point#kotlin.Float#kotlin.IntArray#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-radial-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeRadialGradient/#org.jetbrains.skia.Point#kotlin.Float#kotlin.IntArray#kotlin.FloatArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-radial-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeRadialGradient/#org.jetbrains.skia.Point#kotlin.Float#kotlin.IntArray/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-radial-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeSweepGradient/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Array[org.jetbrains.skia.Color4f]#org.jetbrains.skia.ColorSpace?#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-sweep-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeSweepGradient/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.IntArray#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-sweep-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeSweepGradient/#kotlin.Float#kotlin.Float#kotlin.IntArray#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-sweep-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeSweepGradient/#kotlin.Float#kotlin.Float#kotlin.IntArray#kotlin.FloatArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-sweep-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeSweepGradient/#kotlin.Float#kotlin.Float#kotlin.IntArray/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-sweep-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeSweepGradient/#org.jetbrains.skia.Point#kotlin.Float#kotlin.Float#kotlin.Array[org.jetbrains.skia.Color4f]#org.jetbrains.skia.ColorSpace?#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-sweep-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeSweepGradient/#org.jetbrains.skia.Point#kotlin.Float#kotlin.Float#kotlin.IntArray#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-sweep-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeSweepGradient/#org.jetbrains.skia.Point#kotlin.IntArray#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-sweep-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeSweepGradient/#org.jetbrains.skia.Point#kotlin.IntArray#kotlin.FloatArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-sweep-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeSweepGradient/#org.jetbrains.skia.Point#kotlin.IntArray/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-sweep-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeTurbulence/#kotlin.Float#kotlin.Float#kotlin.Int#kotlin.Float#org.jetbrains.skia.ISize/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-turbulence.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeTwoPointConicalGradient/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Array[org.jetbrains.skia.Color4f]#org.jetbrains.skia.ColorSpace?#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-two-point-conical-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeTwoPointConicalGradient/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.IntArray#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-two-point-conical-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeTwoPointConicalGradient/#org.jetbrains.skia.Point#kotlin.Float#org.jetbrains.skia.Point#kotlin.Float#kotlin.Array[org.jetbrains.skia.Color4f]#org.jetbrains.skia.ColorSpace?#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-two-point-conical-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeTwoPointConicalGradient/#org.jetbrains.skia.Point#kotlin.Float#org.jetbrains.skia.Point#kotlin.Float#kotlin.IntArray#kotlin.FloatArray?#org.jetbrains.skia.GradientStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-two-point-conical-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeTwoPointConicalGradient/#org.jetbrains.skia.Point#kotlin.Float#org.jetbrains.skia.Point#kotlin.Float#kotlin.IntArray#kotlin.FloatArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-two-point-conical-gradient.html
+$dokka.location:org.jetbrains.skia/Shader.Companion/makeTwoPointConicalGradient/#org.jetbrains.skia.Point#kotlin.Float#org.jetbrains.skia.Point#kotlin.Float#kotlin.IntArray/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/-companion/make-two-point-conical-gradient.html
+$dokka.location:org.jetbrains.skia/Shader///PointingToDeclaration/skiko/org.jetbrains.skia/-shader/index.html
+$dokka.location:org.jetbrains.skia/Shader/makeWithColorFilter/#org.jetbrains.skia.ColorFilter?/PointingToDeclaration/skiko/org.jetbrains.skia/-shader/make-with-color-filter.html
+$dokka.location:org.jetbrains.skia/ShadowUtils///PointingToDeclaration/skiko/org.jetbrains.skia/-shadow-utils/index.html
+$dokka.location:org.jetbrains.skia/ShadowUtils/computeTonalAmbientColor/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-shadow-utils/compute-tonal-ambient-color.html
+$dokka.location:org.jetbrains.skia/ShadowUtils/computeTonalSpotColor/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-shadow-utils/compute-tonal-spot-color.html
+$dokka.location:org.jetbrains.skia/ShadowUtils/drawShadow/#org.jetbrains.skia.Canvas#org.jetbrains.skia.Path#org.jetbrains.skia.Point3#org.jetbrains.skia.Point3#kotlin.Float#kotlin.Int#kotlin.Int#kotlin.Boolean#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-shadow-utils/draw-shadow.html
+$dokka.location:org.jetbrains.skia/Surface.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/index.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeFromBackendRenderTarget/#org.jetbrains.skia.DirectContext#org.jetbrains.skia.BackendRenderTarget#org.jetbrains.skia.SurfaceOrigin#org.jetbrains.skia.SurfaceColorFormat#org.jetbrains.skia.ColorSpace?#org.jetbrains.skia.SurfaceProps?/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-from-backend-render-target.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeFromMTKView/#org.jetbrains.skia.DirectContext#org.jetbrains.skia.impl.NativePointer#org.jetbrains.skia.SurfaceOrigin#kotlin.Int#org.jetbrains.skia.SurfaceColorFormat#org.jetbrains.skia.ColorSpace?#org.jetbrains.skia.SurfaceProps?/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-from-m-t-k-view.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeNull/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-null.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRaster/#org.jetbrains.skia.ImageInfo#kotlin.Int#org.jetbrains.skia.SurfaceProps?/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-raster.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRaster/#org.jetbrains.skia.ImageInfo#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-raster.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRaster/#org.jetbrains.skia.ImageInfo/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-raster.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRasterDirect/#org.jetbrains.skia.ImageInfo#org.jetbrains.skia.impl.NativePointer#kotlin.Int#org.jetbrains.skia.SurfaceProps?/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-raster-direct.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRasterDirect/#org.jetbrains.skia.ImageInfo#org.jetbrains.skia.impl.NativePointer#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-raster-direct.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRasterDirect/#org.jetbrains.skia.Pixmap#org.jetbrains.skia.SurfaceProps?/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-raster-direct.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRasterDirect/#org.jetbrains.skia.Pixmap/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-raster-direct.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRasterN32Premul/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-raster-n32-premul.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRenderTarget/#org.jetbrains.skia.DirectContext#kotlin.Boolean#org.jetbrains.skia.ImageInfo#kotlin.Int#org.jetbrains.skia.SurfaceOrigin#org.jetbrains.skia.SurfaceProps?#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-render-target.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRenderTarget/#org.jetbrains.skia.DirectContext#kotlin.Boolean#org.jetbrains.skia.ImageInfo#kotlin.Int#org.jetbrains.skia.SurfaceOrigin#org.jetbrains.skia.SurfaceProps?/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-render-target.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRenderTarget/#org.jetbrains.skia.DirectContext#kotlin.Boolean#org.jetbrains.skia.ImageInfo#kotlin.Int#org.jetbrains.skia.SurfaceProps?/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-render-target.html
+$dokka.location:org.jetbrains.skia/Surface.Companion/makeRenderTarget/#org.jetbrains.skia.DirectContext#kotlin.Boolean#org.jetbrains.skia.ImageInfo/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/-companion/make-render-target.html
+$dokka.location:org.jetbrains.skia/Surface///PointingToDeclaration/skiko/org.jetbrains.skia/-surface/index.html
+$dokka.location:org.jetbrains.skia/Surface/canvas/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/canvas.html
+$dokka.location:org.jetbrains.skia/Surface/draw/#org.jetbrains.skia.Canvas?#kotlin.Int#kotlin.Int#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/draw.html
+$dokka.location:org.jetbrains.skia/Surface/draw/#org.jetbrains.skia.Canvas?#kotlin.Int#kotlin.Int#org.jetbrains.skia.SamplingMode#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/draw.html
+$dokka.location:org.jetbrains.skia/Surface/flush/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/flush.html
+$dokka.location:org.jetbrains.skia/Surface/flushAndSubmit/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/flush-and-submit.html
+$dokka.location:org.jetbrains.skia/Surface/flushAndSubmit/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/flush-and-submit.html
+$dokka.location:org.jetbrains.skia/Surface/generationId/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/generation-id.html
+$dokka.location:org.jetbrains.skia/Surface/height/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/height.html
+$dokka.location:org.jetbrains.skia/Surface/imageInfo/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/image-info.html
+$dokka.location:org.jetbrains.skia/Surface/isUnique/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/is-unique.html
+$dokka.location:org.jetbrains.skia/Surface/makeImageSnapshot/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/make-image-snapshot.html
+$dokka.location:org.jetbrains.skia/Surface/makeImageSnapshot/#org.jetbrains.skia.IRect/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/make-image-snapshot.html
+$dokka.location:org.jetbrains.skia/Surface/makeSurface/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/make-surface.html
+$dokka.location:org.jetbrains.skia/Surface/makeSurface/#org.jetbrains.skia.ImageInfo/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/make-surface.html
+$dokka.location:org.jetbrains.skia/Surface/notifyContentWillChange/#org.jetbrains.skia.ContentChangeMode/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/notify-content-will-change.html
+$dokka.location:org.jetbrains.skia/Surface/peekPixels/#org.jetbrains.skia.Pixmap/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/peek-pixels.html
+$dokka.location:org.jetbrains.skia/Surface/readPixels/#org.jetbrains.skia.Bitmap?#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/read-pixels.html
+$dokka.location:org.jetbrains.skia/Surface/readPixels/#org.jetbrains.skia.Pixmap?#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/read-pixels.html
+$dokka.location:org.jetbrains.skia/Surface/recordingContext/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/recording-context.html
+$dokka.location:org.jetbrains.skia/Surface/width/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/width.html
+$dokka.location:org.jetbrains.skia/Surface/writePixels/#org.jetbrains.skia.Bitmap?#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/write-pixels.html
+$dokka.location:org.jetbrains.skia/Surface/writePixels/#org.jetbrains.skia.Pixmap?#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-surface/write-pixels.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.A16_FLOAT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-a16_-f-l-o-a-t/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.A16_UNORM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-a16_-u-n-o-r-m/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.ALPHA_8///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-a-l-p-h-a_8/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.ARGB_4444///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-a-r-g-b_4444/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.BGRA_8888///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-b-g-r-a_8888/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.GRAY_8///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-g-r-a-y_8/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.R16G16B16A16_UNORM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r16-g16-b16-a16_-u-n-o-r-m/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.R16G16_FLOAT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r16-g16_-f-l-o-a-t/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.R16G16_UNORM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r16-g16_-u-n-o-r-m/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.R8G8_UNORM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r8-g8_-u-n-o-r-m/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.RGBA_1010102///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r-g-b-a_1010102/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.RGBA_8888///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r-g-b-a_8888/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.RGBA_F16///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r-g-b-a_-f16/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.RGBA_F16_NORM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r-g-b-a_-f16_-n-o-r-m/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.RGBA_F32///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r-g-b-a_-f32/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.RGB_101010x///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r-g-b_101010x/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.RGB_565///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r-g-b_565/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.RGB_888x///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-r-g-b_888x/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-color-format/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat///PointingToDeclaration/skiko/org.jetbrains.skia/-surface-color-format/index.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-color-format/value-of.html
+$dokka.location:org.jetbrains.skia/SurfaceColorFormat/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-color-format/values.html
+$dokka.location:org.jetbrains.skia/SurfaceOrigin.BOTTOM_LEFT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-origin/-b-o-t-t-o-m_-l-e-f-t/index.html
+$dokka.location:org.jetbrains.skia/SurfaceOrigin.TOP_LEFT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-surface-origin/-t-o-p_-l-e-f-t/index.html
+$dokka.location:org.jetbrains.skia/SurfaceOrigin///PointingToDeclaration/skiko/org.jetbrains.skia/-surface-origin/index.html
+$dokka.location:org.jetbrains.skia/SurfaceOrigin/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-origin/value-of.html
+$dokka.location:org.jetbrains.skia/SurfaceOrigin/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-origin/values.html
+$dokka.location:org.jetbrains.skia/SurfaceProps///PointingToDeclaration/skiko/org.jetbrains.skia/-surface-props/index.html
+$dokka.location:org.jetbrains.skia/SurfaceProps/SurfaceProps/#kotlin.Boolean#org.jetbrains.skia.PixelGeometry/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-props/-surface-props.html
+$dokka.location:org.jetbrains.skia/SurfaceProps/SurfaceProps/#org.jetbrains.skia.PixelGeometry/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-props/-surface-props.html
+$dokka.location:org.jetbrains.skia/SurfaceProps/_getFlags/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-props/_get-flags.html
+$dokka.location:org.jetbrains.skia/SurfaceProps/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-props/equals.html
+$dokka.location:org.jetbrains.skia/SurfaceProps/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-props/hash-code.html
+$dokka.location:org.jetbrains.skia/SurfaceProps/toString/#/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-props/to-string.html
+$dokka.location:org.jetbrains.skia/SurfaceProps/withDeviceIndependentFonts/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-props/with-device-independent-fonts.html
+$dokka.location:org.jetbrains.skia/SurfaceProps/withPixelGeometry/#org.jetbrains.skia.PixelGeometry/PointingToDeclaration/skiko/org.jetbrains.skia/-surface-props/with-pixel-geometry.html
+$dokka.location:org.jetbrains.skia/TextBlob.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-companion/index.html
+$dokka.location:org.jetbrains.skia/TextBlob.Companion/makeFromData/#org.jetbrains.skia.Data?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-companion/make-from-data.html
+$dokka.location:org.jetbrains.skia/TextBlob.Companion/makeFromPos/#kotlin.ShortArray#kotlin.Array[org.jetbrains.skia.Point]#org.jetbrains.skia.Font?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-companion/make-from-pos.html
+$dokka.location:org.jetbrains.skia/TextBlob.Companion/makeFromPosH/#kotlin.ShortArray#kotlin.FloatArray#kotlin.Float#org.jetbrains.skia.Font?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-companion/make-from-pos-h.html
+$dokka.location:org.jetbrains.skia/TextBlob.Companion/makeFromRSXform/#kotlin.ShortArray#kotlin.Array[org.jetbrains.skia.RSXform]#org.jetbrains.skia.Font?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-companion/make-from-r-s-xform.html
+$dokka.location:org.jetbrains.skia/TextBlob.TextBlobIter.Run///PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-text-blob-iter/-run/index.html
+$dokka.location:org.jetbrains.skia/TextBlob.TextBlobIter.Run/Run/#org.jetbrains.skia.Typeface#kotlin.ShortArray/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-text-blob-iter/-run/-run.html
+$dokka.location:org.jetbrains.skia/TextBlob.TextBlobIter.Run/equals/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-text-blob-iter/-run/equals.html
+$dokka.location:org.jetbrains.skia/TextBlob.TextBlobIter.Run/glyphs/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-text-blob-iter/-run/glyphs.html
+$dokka.location:org.jetbrains.skia/TextBlob.TextBlobIter.Run/hashCode/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-text-blob-iter/-run/hash-code.html
+$dokka.location:org.jetbrains.skia/TextBlob.TextBlobIter.Run/typeface/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-text-blob-iter/-run/typeface.html
+$dokka.location:org.jetbrains.skia/TextBlob.TextBlobIter///PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-text-blob-iter/index.html
+$dokka.location:org.jetbrains.skia/TextBlob.TextBlobIter/TextBlobIter/#org.jetbrains.skia.TextBlob/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-text-blob-iter/-text-blob-iter.html
+$dokka.location:org.jetbrains.skia/TextBlob.TextBlobIter/hasNext/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-text-blob-iter/has-next.html
+$dokka.location:org.jetbrains.skia/TextBlob.TextBlobIter/next/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-text-blob-iter/next.html
+$dokka.location:org.jetbrains.skia/TextBlob.TextBlobIter/textBlob/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/-text-blob-iter/text-blob.html
+$dokka.location:org.jetbrains.skia/TextBlob///PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/index.html
+$dokka.location:org.jetbrains.skia/TextBlob/blockBounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/block-bounds.html
+$dokka.location:org.jetbrains.skia/TextBlob/bounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/bounds.html
+$dokka.location:org.jetbrains.skia/TextBlob/clusters/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/clusters.html
+$dokka.location:org.jetbrains.skia/TextBlob/firstBaseline/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/first-baseline.html
+$dokka.location:org.jetbrains.skia/TextBlob/getIntercepts/#kotlin.Float#kotlin.Float#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/get-intercepts.html
+$dokka.location:org.jetbrains.skia/TextBlob/getIntercepts/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/get-intercepts.html
+$dokka.location:org.jetbrains.skia/TextBlob/glyphs/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/glyphs.html
+$dokka.location:org.jetbrains.skia/TextBlob/iterator/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/iterator.html
+$dokka.location:org.jetbrains.skia/TextBlob/lastBaseline/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/last-baseline.html
+$dokka.location:org.jetbrains.skia/TextBlob/positions/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/positions.html
+$dokka.location:org.jetbrains.skia/TextBlob/serializeToData/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/serialize-to-data.html
+$dokka.location:org.jetbrains.skia/TextBlob/tightBounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/tight-bounds.html
+$dokka.location:org.jetbrains.skia/TextBlob/uniqueId/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob/unique-id.html
+$dokka.location:org.jetbrains.skia/TextBlobBuilder.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob-builder/-companion/index.html
+$dokka.location:org.jetbrains.skia/TextBlobBuilder///PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob-builder/index.html
+$dokka.location:org.jetbrains.skia/TextBlobBuilder/TextBlobBuilder/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob-builder/-text-blob-builder.html
+$dokka.location:org.jetbrains.skia/TextBlobBuilder/appendRun/#org.jetbrains.skia.Font#kotlin.String#kotlin.Float#kotlin.Float#org.jetbrains.skia.Rect?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob-builder/append-run.html
+$dokka.location:org.jetbrains.skia/TextBlobBuilder/appendRun/#org.jetbrains.skia.Font?#kotlin.ShortArray?#kotlin.Float#kotlin.Float#org.jetbrains.skia.Rect?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob-builder/append-run.html
+$dokka.location:org.jetbrains.skia/TextBlobBuilder/appendRunPos/#org.jetbrains.skia.Font?#kotlin.ShortArray#kotlin.Array[org.jetbrains.skia.Point]#org.jetbrains.skia.Rect?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob-builder/append-run-pos.html
+$dokka.location:org.jetbrains.skia/TextBlobBuilder/appendRunPosH/#org.jetbrains.skia.Font?#kotlin.ShortArray#kotlin.FloatArray#kotlin.Float#org.jetbrains.skia.Rect?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob-builder/append-run-pos-h.html
+$dokka.location:org.jetbrains.skia/TextBlobBuilder/appendRunRSXform/#org.jetbrains.skia.Font?#kotlin.ShortArray#kotlin.Array[org.jetbrains.skia.RSXform]/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob-builder/append-run-r-s-xform.html
+$dokka.location:org.jetbrains.skia/TextBlobBuilder/build/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-blob-builder/build.html
+$dokka.location:org.jetbrains.skia/TextLine.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/-companion/index.html
+$dokka.location:org.jetbrains.skia/TextLine.Companion/make/#kotlin.String?#org.jetbrains.skia.Font?#org.jetbrains.skia.shaper.ShapingOptions?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/-companion/make.html
+$dokka.location:org.jetbrains.skia/TextLine.Companion/make/#kotlin.String?#org.jetbrains.skia.Font?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/-companion/make.html
+$dokka.location:org.jetbrains.skia/TextLine///PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/index.html
+$dokka.location:org.jetbrains.skia/TextLine/ascent/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/ascent.html
+$dokka.location:org.jetbrains.skia/TextLine/capHeight/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/cap-height.html
+$dokka.location:org.jetbrains.skia/TextLine/descent/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/descent.html
+$dokka.location:org.jetbrains.skia/TextLine/getCoordAtOffset/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/get-coord-at-offset.html
+$dokka.location:org.jetbrains.skia/TextLine/getIntercepts/#kotlin.Float#kotlin.Float#org.jetbrains.skia.Paint?/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/get-intercepts.html
+$dokka.location:org.jetbrains.skia/TextLine/getIntercepts/#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/get-intercepts.html
+$dokka.location:org.jetbrains.skia/TextLine/getLeftOffsetAtCoord/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/get-left-offset-at-coord.html
+$dokka.location:org.jetbrains.skia/TextLine/getOffsetAtCoord/#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/get-offset-at-coord.html
+$dokka.location:org.jetbrains.skia/TextLine/glyphs/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/glyphs.html
+$dokka.location:org.jetbrains.skia/TextLine/height/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/height.html
+$dokka.location:org.jetbrains.skia/TextLine/leading/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/leading.html
+$dokka.location:org.jetbrains.skia/TextLine/positions/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/positions.html
+$dokka.location:org.jetbrains.skia/TextLine/textBlob/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/text-blob.html
+$dokka.location:org.jetbrains.skia/TextLine/width/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/width.html
+$dokka.location:org.jetbrains.skia/TextLine/xHeight/#/PointingToDeclaration/skiko/org.jetbrains.skia/-text-line/x-height.html
+$dokka.location:org.jetbrains.skia/Typeface.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/-companion/index.html
+$dokka.location:org.jetbrains.skia/Typeface.Companion/makeDefault/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/-companion/make-default.html
+$dokka.location:org.jetbrains.skia/Typeface.Companion/makeFromData/#org.jetbrains.skia.Data#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/-companion/make-from-data.html
+$dokka.location:org.jetbrains.skia/Typeface.Companion/makeFromName/#kotlin.String?#org.jetbrains.skia.FontStyle/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/-companion/make-from-name.html
+$dokka.location:org.jetbrains.skia/Typeface///PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/index.html
+$dokka.location:org.jetbrains.skia/Typeface/bounds/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/bounds.html
+$dokka.location:org.jetbrains.skia/Typeface/familyName/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/family-name.html
+$dokka.location:org.jetbrains.skia/Typeface/familyNames/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/family-names.html
+$dokka.location:org.jetbrains.skia/Typeface/fontStyle/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/font-style.html
+$dokka.location:org.jetbrains.skia/Typeface/getKerningPairAdjustments/#kotlin.ShortArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/get-kerning-pair-adjustments.html
+$dokka.location:org.jetbrains.skia/Typeface/getStringGlyphs/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/get-string-glyphs.html
+$dokka.location:org.jetbrains.skia/Typeface/getTableData/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/get-table-data.html
+$dokka.location:org.jetbrains.skia/Typeface/getTableSize/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/get-table-size.html
+$dokka.location:org.jetbrains.skia/Typeface/getUTF32Glyph/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/get-u-t-f32-glyph.html
+$dokka.location:org.jetbrains.skia/Typeface/getUTF32Glyphs/#kotlin.IntArray?/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/get-u-t-f32-glyphs.html
+$dokka.location:org.jetbrains.skia/Typeface/glyphsCount/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/glyphs-count.html
+$dokka.location:org.jetbrains.skia/Typeface/isBold/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/is-bold.html
+$dokka.location:org.jetbrains.skia/Typeface/isFixedPitch/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/is-fixed-pitch.html
+$dokka.location:org.jetbrains.skia/Typeface/isItalic/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/is-italic.html
+$dokka.location:org.jetbrains.skia/Typeface/makeClone/#kotlin.Array[org.jetbrains.skia.FontVariation]#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/make-clone.html
+$dokka.location:org.jetbrains.skia/Typeface/makeClone/#org.jetbrains.skia.FontVariation/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/make-clone.html
+$dokka.location:org.jetbrains.skia/Typeface/tableTags/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/table-tags.html
+$dokka.location:org.jetbrains.skia/Typeface/tablesCount/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/tables-count.html
+$dokka.location:org.jetbrains.skia/Typeface/uniqueId/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/unique-id.html
+$dokka.location:org.jetbrains.skia/Typeface/unitsPerEm/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/units-per-em.html
+$dokka.location:org.jetbrains.skia/Typeface/variationAxes/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/variation-axes.html
+$dokka.location:org.jetbrains.skia/Typeface/variations/#/PointingToDeclaration/skiko/org.jetbrains.skia/-typeface/variations.html
+$dokka.location:org.jetbrains.skia/U16String.Companion///PointingToDeclaration/skiko/org.jetbrains.skia/-u16-string/-companion/index.html
+$dokka.location:org.jetbrains.skia/U16String///PointingToDeclaration/skiko/org.jetbrains.skia/-u16-string/index.html
+$dokka.location:org.jetbrains.skia/VertexMode.TRIANGLES///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-vertex-mode/-t-r-i-a-n-g-l-e-s/index.html
+$dokka.location:org.jetbrains.skia/VertexMode.TRIANGLE_FAN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-vertex-mode/-t-r-i-a-n-g-l-e_-f-a-n/index.html
+$dokka.location:org.jetbrains.skia/VertexMode.TRIANGLE_STRIP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skia/-vertex-mode/-t-r-i-a-n-g-l-e_-s-t-r-i-p/index.html
+$dokka.location:org.jetbrains.skia/VertexMode///PointingToDeclaration/skiko/org.jetbrains.skia/-vertex-mode/index.html
+$dokka.location:org.jetbrains.skia/VertexMode/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skia/-vertex-mode/value-of.html
+$dokka.location:org.jetbrains.skia/VertexMode/values/#/PointingToDeclaration/skiko/org.jetbrains.skia/-vertex-mode/values.html
+$dokka.location:org.jetbrains.skia/WStream///PointingToDeclaration/skiko/org.jetbrains.skia/-w-stream/index.html
+$dokka.location:org.jetbrains.skia/WStream/WStream/#org.jetbrains.skia.impl.NativePointer#org.jetbrains.skia.impl.NativePointer#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skia/-w-stream/-w-stream.html
+$dokka.location:org.jetbrains.skia/WStream/WStream/#org.jetbrains.skia.impl.NativePointer#org.jetbrains.skia.impl.NativePointer/PointingToDeclaration/skiko/org.jetbrains.skia/-w-stream/-w-stream.html
+$dokka.location:org.jetbrains.skiko.wasm////PointingToDeclaration/skiko/org.jetbrains.skiko.wasm/index.html
+$dokka.location:org.jetbrains.skiko.wasm//onWasmReady/#kotlin.Function0[kotlin.Unit]/PointingToDeclaration/skiko/org.jetbrains.skiko.wasm/on-wasm-ready.html
+$dokka.location:org.jetbrains.skiko////PointingToDeclaration/skiko/org.jetbrains.skiko/index.html
+$dokka.location:org.jetbrains.skiko//MainUIDispatcher/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-main-u-i-dispatcher.html
+$dokka.location:org.jetbrains.skiko//currentNanoTime/#/PointingToDeclaration/skiko/org.jetbrains.skiko/current-nano-time.html
+$dokka.location:org.jetbrains.skiko//currentSystemTheme/#/PointingToDeclaration/skiko/org.jetbrains.skiko/current-system-theme.html
+$dokka.location:org.jetbrains.skiko//disableTitleBar/org.jetbrains.skiko.SkiaLayer#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skiko/disable-title-bar.html
+$dokka.location:org.jetbrains.skiko//hostArch/#/PointingToDeclaration/skiko/org.jetbrains.skiko/host-arch.html
+$dokka.location:org.jetbrains.skiko//hostId/#/PointingToDeclaration/skiko/org.jetbrains.skiko/host-id.html
+$dokka.location:org.jetbrains.skiko//hostOs/#/PointingToDeclaration/skiko/org.jetbrains.skiko/host-os.html
+$dokka.location:org.jetbrains.skiko//isLeftClick/org.jetbrains.skiko.SkikoPointerEvent#/PointingToDeclaration/skiko/org.jetbrains.skiko/is-left-click.html
+$dokka.location:org.jetbrains.skiko//isMiddleClick/org.jetbrains.skiko.SkikoPointerEvent#/PointingToDeclaration/skiko/org.jetbrains.skiko/is-middle-click.html
+$dokka.location:org.jetbrains.skiko//isRightClick/org.jetbrains.skiko.SkikoPointerEvent#/PointingToDeclaration/skiko/org.jetbrains.skiko/is-right-click.html
+$dokka.location:org.jetbrains.skiko//kotlinBackend/#/PointingToDeclaration/skiko/org.jetbrains.skiko/kotlin-backend.html
+$dokka.location:org.jetbrains.skiko//loadBytesFromPath/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/load-bytes-from-path.html
+$dokka.location:org.jetbrains.skiko//onContentScaleChanged/#/PointingToDeclaration/skiko/org.jetbrains.skiko/on-content-scale-changed.html
+$dokka.location:org.jetbrains.skiko//orderEmojiAndSymbolsPopup/#/PointingToDeclaration/skiko/org.jetbrains.skiko/order-emoji-and-symbols-popup.html
+$dokka.location:org.jetbrains.skiko//setSystemLookAndFeel/#/PointingToDeclaration/skiko/org.jetbrains.skiko/set-system-look-and-feel.html
+$dokka.location:org.jetbrains.skiko//setupSkikoLoggerFactory/#kotlin.Function0[org.jetbrains.skiko.SkikoLoggerInterface]/PointingToDeclaration/skiko/org.jetbrains.skiko/setup-skiko-logger-factory.html
+$dokka.location:org.jetbrains.skiko//toBitmap/java.awt.image.BufferedImage#/PointingToDeclaration/skiko/org.jetbrains.skiko/to-bitmap.html
+$dokka.location:org.jetbrains.skiko//toBufferedImage/org.jetbrains.skia.Bitmap#/PointingToDeclaration/skiko/org.jetbrains.skiko/to-buffered-image.html
+$dokka.location:org.jetbrains.skiko//toImage/java.awt.image.BufferedImage#/PointingToDeclaration/skiko/org.jetbrains.skiko/to-image.html
+$dokka.location:org.jetbrains.skiko//toSkikoDragEvent/#org.w3c.dom.events.MouseEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-drag-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoEvent/#[Error type: Unresolved type for NSEvent]#[Error type: Unresolved type for SkikoKeyboardEventKind]/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoEvent/#[Error type: Unresolved type for NSEvent]#[Error type: Unresolved type for SkikoMouseButtons]#[Error type: Unresolved type for SkikoPointerEventKind]#[Error type: Unresolved type for NSView]/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoEvent/#[Error type: Unresolved type for NSEvent]#[Error type: Unresolved type for SkikoPointerEventKind]#[Error type: Unresolved type for NSView]/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoEvent/#[Error type: Unresolved type for NSEvent]/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoEvent/#java.awt.event.KeyEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoEvent/#java.awt.event.MouseEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoEvent/#java.awt.event.MouseWheelEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoEvent/#org.w3c.dom.events.KeyboardEvent#org.jetbrains.skiko.SkikoKeyboardEventKind/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoEvent/#org.w3c.dom.events.MouseEvent#org.jetbrains.skiko.SkikoPointerEventKind/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoGestureDirection/#[Error type: Unresolved type for UISwipeGestureRecognizerDirection]/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-gesture-direction.html
+$dokka.location:org.jetbrains.skiko//toSkikoGestureState/#[Error type: Unresolved type for UIGestureRecognizerState]/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-gesture-state.html
+$dokka.location:org.jetbrains.skiko//toSkikoKeyboardEvent/#[Error type: Unresolved type for UIPress]#[Error type: Unresolved type for SkikoKeyboardEventKind]/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-keyboard-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoKeyboardEvent/#android.view.KeyEvent#kotlin.Int#org.jetbrains.skiko.SkikoKeyboardEventKind/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-keyboard-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoPointerEvent/#android.view.MotionEvent#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-pointer-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoScaleGestureEvent/#android.view.MotionEvent#kotlin.Double#org.jetbrains.skiko.SkikoGestureEventState#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-scale-gesture-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoScrollEvent/#[Error type: Unresolved type for NSEvent]#[Error type: Unresolved type for NSView]/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-scroll-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoScrollEvent/#org.w3c.dom.events.WheelEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-scroll-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoTypeEvent/#android.view.KeyEvent#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-type-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoTypeEvent/#java.awt.event.InputMethodEvent#java.awt.event.KeyEvent?/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-type-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoTypeEvent/#java.awt.event.KeyEvent#java.awt.event.KeyEvent?/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-type-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoTypeEvent/#kotlin.String#[Error type: Unresolved type for NSEvent]?/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-type-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoTypeEvent/#kotlin.String#[Error type: Unresolved type for UIPress]?/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-type-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoTypeEvent/#kotlin.String#org.w3c.dom.events.KeyboardEvent?/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-type-event.html
+$dokka.location:org.jetbrains.skiko//toSkikoTypeface/java.awt.Font#org.jetbrains.skiko.AwtFontManager/PointingToDeclaration/skiko/org.jetbrains.skiko/to-skiko-typeface.html
+$dokka.location:org.jetbrains.skiko/Arch.Arm64///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-arch/-arm64/index.html
+$dokka.location:org.jetbrains.skiko/Arch.JS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-arch/-j-s/index.html
+$dokka.location:org.jetbrains.skiko/Arch.WASM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-arch/-w-a-s-m/index.html
+$dokka.location:org.jetbrains.skiko/Arch.X64///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-arch/-x64/index.html
+$dokka.location:org.jetbrains.skiko/Arch///PointingToDeclaration/skiko/org.jetbrains.skiko/-arch/index.html
+$dokka.location:org.jetbrains.skiko/Arch/id/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-arch/id.html
+$dokka.location:org.jetbrains.skiko/Arch/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-arch/value-of.html
+$dokka.location:org.jetbrains.skiko/Arch/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-arch/values.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager.Companion///PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/-companion/index.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager.Companion/DEFAULT/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/-companion/-d-e-f-a-u-l-t.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager///PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/index.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager/AwtFontManager/#kotlin.Array[kotlin.String]/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/-awt-font-manager.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager/addCustomPath/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/add-custom-path.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager/addResourceFont/#kotlin.String#java.lang.ClassLoader/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/add-resource-font.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager/allFontsCached/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/all-fonts-cached.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager/findAvailableFontFile/#java.awt.Font/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/find-available-font-file.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager/findFontFamilyFile/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/find-font-family-file.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager/findFontFile/#java.awt.Font/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/find-font-file.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager/invalidate/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/invalidate.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager/listAvailableFontFiles/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/list-available-font-files.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager/listFontFiles/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/list-font-files.html
+$dokka.location:org.jetbrains.skiko/AwtFontManager/whenAllFontsCachedBlocking/#kotlin.Function0[kotlin.Unit]/PointingToDeclaration/skiko/org.jetbrains.skiko/-awt-font-manager/when-all-fonts-cached-blocking.html
+$dokka.location:org.jetbrains.skiko/CanvasRenderer///PointingToDeclaration/skiko/org.jetbrains.skiko/-canvas-renderer/index.html
+$dokka.location:org.jetbrains.skiko/CanvasRenderer/CanvasRenderer/#org.w3c.dom.HTMLCanvasElement/PointingToDeclaration/skiko/org.jetbrains.skiko/-canvas-renderer/-canvas-renderer.html
+$dokka.location:org.jetbrains.skiko/CanvasRenderer/drawFrame/#kotlin.Double/PointingToDeclaration/skiko/org.jetbrains.skiko/-canvas-renderer/draw-frame.html
+$dokka.location:org.jetbrains.skiko/CanvasRenderer/height/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-canvas-renderer/height.html
+$dokka.location:org.jetbrains.skiko/CanvasRenderer/htmlCanvas/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-canvas-renderer/html-canvas.html
+$dokka.location:org.jetbrains.skiko/CanvasRenderer/initCanvas/#kotlin.Int#kotlin.Int#kotlin.Float#org.jetbrains.skia.PixelGeometry/PointingToDeclaration/skiko/org.jetbrains.skiko/-canvas-renderer/init-canvas.html
+$dokka.location:org.jetbrains.skiko/CanvasRenderer/needRedraw/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-canvas-renderer/need-redraw.html
+$dokka.location:org.jetbrains.skiko/CanvasRenderer/width/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-canvas-renderer/width.html
+$dokka.location:org.jetbrains.skiko/ClipComponent///PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-component/index.html
+$dokka.location:org.jetbrains.skiko/ClipComponent/ClipComponent/#java.awt.Component/PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-component/-clip-component.html
+$dokka.location:org.jetbrains.skiko/ClipComponent/component/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-component/component.html
+$dokka.location:org.jetbrains.skiko/ClipComponent/height/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-component/height.html
+$dokka.location:org.jetbrains.skiko/ClipComponent/width/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-component/width.html
+$dokka.location:org.jetbrains.skiko/ClipComponent/x/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-component/x.html
+$dokka.location:org.jetbrains.skiko/ClipComponent/y/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-component/y.html
+$dokka.location:org.jetbrains.skiko/ClipRectangle///PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-rectangle/index.html
+$dokka.location:org.jetbrains.skiko/ClipRectangle/height/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-rectangle/height.html
+$dokka.location:org.jetbrains.skiko/ClipRectangle/width/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-rectangle/width.html
+$dokka.location:org.jetbrains.skiko/ClipRectangle/x/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-rectangle/x.html
+$dokka.location:org.jetbrains.skiko/ClipRectangle/y/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clip-rectangle/y.html
+$dokka.location:org.jetbrains.skiko/ClipboardManager///PointingToDeclaration/skiko/org.jetbrains.skiko/-clipboard-manager/index.html
+$dokka.location:org.jetbrains.skiko/ClipboardManager/ClipboardManager/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clipboard-manager/-clipboard-manager.html
+$dokka.location:org.jetbrains.skiko/ClipboardManager/getText/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clipboard-manager/get-text.html
+$dokka.location:org.jetbrains.skiko/ClipboardManager/hasText/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-clipboard-manager/has-text.html
+$dokka.location:org.jetbrains.skiko/ClipboardManager/setText/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-clipboard-manager/set-text.html
+$dokka.location:org.jetbrains.skiko/Cursor///PointingToDeclaration/skiko/org.jetbrains.skiko/-cursor/index.html
+$dokka.location:org.jetbrains.skiko/CursorManager///PointingToDeclaration/skiko/org.jetbrains.skiko/-cursor-manager/index.html
+$dokka.location:org.jetbrains.skiko/CursorManager/CursorManager/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-cursor-manager/-cursor-manager.html
+$dokka.location:org.jetbrains.skiko/CursorManager/getCursor/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skiko/-cursor-manager/get-cursor.html
+$dokka.location:org.jetbrains.skiko/CursorManager/setCursor/#kotlin.Any?#org.jetbrains.skiko.Cursor/PointingToDeclaration/skiko/org.jetbrains.skiko/-cursor-manager/set-cursor.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger.Companion///PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/-companion/index.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger.Companion/fromLevel/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/-companion/from-level.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger///PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/index.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/DefaultConsoleLogger/#kotlin.Boolean#kotlin.Boolean#kotlin.Boolean#kotlin.Boolean#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/-default-console-logger.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/debug/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/debug.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/debug/#kotlin.Throwable#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/debug.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/error/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/error.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/error/#kotlin.Throwable#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/error.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/info/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/info.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/info/#kotlin.Throwable#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/info.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/isDebugEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/is-debug-enabled.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/isErrorEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/is-error-enabled.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/isInfoEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/is-info-enabled.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/isTraceEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/is-trace-enabled.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/isWarnEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/is-warn-enabled.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/trace/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/trace.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/trace/#kotlin.Throwable#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/trace.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/warn/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/warn.html
+$dokka.location:org.jetbrains.skiko/DefaultConsoleLogger/warn/#kotlin.Throwable#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-default-console-logger/warn.html
+$dokka.location:org.jetbrains.skiko/DelicateSkikoApi///PointingToDeclaration/skiko/org.jetbrains.skiko/-delicate-skiko-api/index.html
+$dokka.location:org.jetbrains.skiko/ExperimentalSkikoApi///PointingToDeclaration/skiko/org.jetbrains.skiko/-experimental-skiko-api/index.html
+$dokka.location:org.jetbrains.skiko/FPSCounter///PointingToDeclaration/skiko/org.jetbrains.skiko/-f-p-s-counter/index.html
+$dokka.location:org.jetbrains.skiko/FPSCounter/FPSCounter/#kotlin.Double#kotlin.Boolean#kotlin.Function0[kotlin.Double]#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skiko/-f-p-s-counter/-f-p-s-counter.html
+$dokka.location:org.jetbrains.skiko/FPSCounter/average/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-f-p-s-counter/average.html
+$dokka.location:org.jetbrains.skiko/FPSCounter/max/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-f-p-s-counter/max.html
+$dokka.location:org.jetbrains.skiko/FPSCounter/min/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-f-p-s-counter/min.html
+$dokka.location:org.jetbrains.skiko/FPSCounter/tick/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-f-p-s-counter/tick.html
+$dokka.location:org.jetbrains.skiko/FrameDispatcher///PointingToDeclaration/skiko/org.jetbrains.skiko/-frame-dispatcher/index.html
+$dokka.location:org.jetbrains.skiko/FrameDispatcher/FrameDispatcher/#kotlin.coroutines.CoroutineContext#kotlin.coroutines.SuspendFunction0[kotlin.Unit]/PointingToDeclaration/skiko/org.jetbrains.skiko/-frame-dispatcher/-frame-dispatcher.html
+$dokka.location:org.jetbrains.skiko/FrameDispatcher/FrameDispatcher/#kotlinx.coroutines.CoroutineScope#kotlin.coroutines.SuspendFunction0[kotlin.Unit]/PointingToDeclaration/skiko/org.jetbrains.skiko/-frame-dispatcher/-frame-dispatcher.html
+$dokka.location:org.jetbrains.skiko/FrameDispatcher/cancel/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-frame-dispatcher/cancel.html
+$dokka.location:org.jetbrains.skiko/FrameDispatcher/scheduleFrame/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-frame-dispatcher/schedule-frame.html
+$dokka.location:org.jetbrains.skiko/FrameLimiter///PointingToDeclaration/skiko/org.jetbrains.skiko/-frame-limiter/index.html
+$dokka.location:org.jetbrains.skiko/FrameLimiter/FrameLimiter/#[Error type: Unresolved type for CoroutineScope]#kotlin.Function0[kotlin.Long]#kotlin.Function0[kotlin.Long]/PointingToDeclaration/skiko/org.jetbrains.skiko/-frame-limiter/-frame-limiter.html
+$dokka.location:org.jetbrains.skiko/FrameLimiter/awaitNextFrame/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-frame-limiter/await-next-frame.html
+$dokka.location:org.jetbrains.skiko/GenericSkikoView///PointingToDeclaration/skiko/org.jetbrains.skiko/-generic-skiko-view/index.html
+$dokka.location:org.jetbrains.skiko/GenericSkikoView/GenericSkikoView/#org.jetbrains.skiko.SkiaLayer#org.jetbrains.skiko.SkikoView/PointingToDeclaration/skiko/org.jetbrains.skiko/-generic-skiko-view/-generic-skiko-view.html
+$dokka.location:org.jetbrains.skiko/GenericSkikoView/app/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-generic-skiko-view/app.html
+$dokka.location:org.jetbrains.skiko/GenericSkikoView/input/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-generic-skiko-view/input.html
+$dokka.location:org.jetbrains.skiko/GenericSkikoView/layer/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-generic-skiko-view/layer.html
+$dokka.location:org.jetbrains.skiko/GenericSkikoView/onGestureEvent/#org.jetbrains.skiko.SkikoGestureEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-generic-skiko-view/on-gesture-event.html
+$dokka.location:org.jetbrains.skiko/GenericSkikoView/onInputEvent/#org.jetbrains.skiko.SkikoInputEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-generic-skiko-view/on-input-event.html
+$dokka.location:org.jetbrains.skiko/GenericSkikoView/onKeyboardEvent/#org.jetbrains.skiko.SkikoKeyboardEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-generic-skiko-view/on-keyboard-event.html
+$dokka.location:org.jetbrains.skiko/GenericSkikoView/onPointerEvent/#org.jetbrains.skiko.SkikoPointerEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-generic-skiko-view/on-pointer-event.html
+$dokka.location:org.jetbrains.skiko/GenericSkikoView/onRender/#org.jetbrains.skia.Canvas#kotlin.Int#kotlin.Int#kotlin.Long/PointingToDeclaration/skiko/org.jetbrains.skiko/-generic-skiko-view/on-render.html
+$dokka.location:org.jetbrains.skiko/GpuPriority.Auto///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-gpu-priority/-auto/index.html
+$dokka.location:org.jetbrains.skiko/GpuPriority.Companion///PointingToDeclaration/skiko/org.jetbrains.skiko/-gpu-priority/-companion/index.html
+$dokka.location:org.jetbrains.skiko/GpuPriority.Companion/parseOrNull/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-gpu-priority/-companion/parse-or-null.html
+$dokka.location:org.jetbrains.skiko/GpuPriority.Discrete///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-gpu-priority/-discrete/index.html
+$dokka.location:org.jetbrains.skiko/GpuPriority.Integrated///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-gpu-priority/-integrated/index.html
+$dokka.location:org.jetbrains.skiko/GpuPriority///PointingToDeclaration/skiko/org.jetbrains.skiko/-gpu-priority/index.html
+$dokka.location:org.jetbrains.skiko/GpuPriority/value/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-gpu-priority/value.html
+$dokka.location:org.jetbrains.skiko/GpuPriority/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-gpu-priority/value-of.html
+$dokka.location:org.jetbrains.skiko/GpuPriority/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-gpu-priority/values.html
+$dokka.location:org.jetbrains.skiko/GraphicsApi.DIRECT3D///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-graphics-api/-d-i-r-e-c-t3-d/index.html
+$dokka.location:org.jetbrains.skiko/GraphicsApi.METAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-graphics-api/-m-e-t-a-l/index.html
+$dokka.location:org.jetbrains.skiko/GraphicsApi.OPENGL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-graphics-api/-o-p-e-n-g-l/index.html
+$dokka.location:org.jetbrains.skiko/GraphicsApi.SOFTWARE_COMPAT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-graphics-api/-s-o-f-t-w-a-r-e_-c-o-m-p-a-t/index.html
+$dokka.location:org.jetbrains.skiko/GraphicsApi.SOFTWARE_FAST///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-graphics-api/-s-o-f-t-w-a-r-e_-f-a-s-t/index.html
+$dokka.location:org.jetbrains.skiko/GraphicsApi.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-graphics-api/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/GraphicsApi.VULKAN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-graphics-api/-v-u-l-k-a-n/index.html
+$dokka.location:org.jetbrains.skiko/GraphicsApi.WEBGL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-graphics-api/-w-e-b-g-l/index.html
+$dokka.location:org.jetbrains.skiko/GraphicsApi///PointingToDeclaration/skiko/org.jetbrains.skiko/-graphics-api/index.html
+$dokka.location:org.jetbrains.skiko/GraphicsApi/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-graphics-api/value-of.html
+$dokka.location:org.jetbrains.skiko/GraphicsApi/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-graphics-api/values.html
+$dokka.location:org.jetbrains.skiko/KotlinBackend.JS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-kotlin-backend/-j-s/index.html
+$dokka.location:org.jetbrains.skiko/KotlinBackend.JVM///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-kotlin-backend/-j-v-m/index.html
+$dokka.location:org.jetbrains.skiko/KotlinBackend.Native///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-kotlin-backend/-native/index.html
+$dokka.location:org.jetbrains.skiko/KotlinBackend///PointingToDeclaration/skiko/org.jetbrains.skiko/-kotlin-backend/index.html
+$dokka.location:org.jetbrains.skiko/KotlinBackend/id/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-kotlin-backend/id.html
+$dokka.location:org.jetbrains.skiko/KotlinBackend/isNotJs/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-kotlin-backend/is-not-js.html
+$dokka.location:org.jetbrains.skiko/KotlinBackend/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-kotlin-backend/value-of.html
+$dokka.location:org.jetbrains.skiko/KotlinBackend/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-kotlin-backend/values.html
+$dokka.location:org.jetbrains.skiko/Library///PointingToDeclaration/skiko/org.jetbrains.skiko/-library/index.html
+$dokka.location:org.jetbrains.skiko/Library/load/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-library/load.html
+$dokka.location:org.jetbrains.skiko/LibraryLoadException///PointingToDeclaration/skiko/org.jetbrains.skiko/-library-load-exception/index.html
+$dokka.location:org.jetbrains.skiko/LibraryLoadException/LibraryLoadException/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-library-load-exception/-library-load-exception.html
+$dokka.location:org.jetbrains.skiko/OS.Android///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-o-s/-android/index.html
+$dokka.location:org.jetbrains.skiko/OS.Ios///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-o-s/-ios/index.html
+$dokka.location:org.jetbrains.skiko/OS.JS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-o-s/-j-s/index.html
+$dokka.location:org.jetbrains.skiko/OS.Linux///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-o-s/-linux/index.html
+$dokka.location:org.jetbrains.skiko/OS.MacOS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-o-s/-mac-o-s/index.html
+$dokka.location:org.jetbrains.skiko/OS.Windows///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-o-s/-windows/index.html
+$dokka.location:org.jetbrains.skiko/OS///PointingToDeclaration/skiko/org.jetbrains.skiko/-o-s/index.html
+$dokka.location:org.jetbrains.skiko/OS/id/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-o-s/id.html
+$dokka.location:org.jetbrains.skiko/OS/isLinux/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-o-s/is-linux.html
+$dokka.location:org.jetbrains.skiko/OS/isMacOS/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-o-s/is-mac-o-s.html
+$dokka.location:org.jetbrains.skiko/OS/isWindows/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-o-s/is-windows.html
+$dokka.location:org.jetbrains.skiko/OS/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-o-s/value-of.html
+$dokka.location:org.jetbrains.skiko/OS/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-o-s/values.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi.Companion///PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/-companion/index.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi.Companion/instance/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/-companion/instance.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi///PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/index.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/GL_COLOR_BUFFER_BIT/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/-g-l_-c-o-l-o-r_-b-u-f-f-e-r_-b-i-t.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/GL_DRAW_FRAMEBUFFER_BINDING/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/-g-l_-d-r-a-w_-f-r-a-m-e-b-u-f-f-e-r_-b-i-n-d-i-n-g.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/GL_RENDERER/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/-g-l_-r-e-n-d-e-r-e-r.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/GL_TEXTURE_2D/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/-g-l_-t-e-x-t-u-r-e_2-d.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/GL_TEXTURE_BINDING_2D/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/-g-l_-t-e-x-t-u-r-e_-b-i-n-d-i-n-g_2-d.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/GL_TOTAL_MEMORY/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/-g-l_-t-o-t-a-l_-m-e-m-o-r-y.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/GL_VENDOR/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/-g-l_-v-e-n-d-o-r.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/glBindTexture/#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/gl-bind-texture.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/glClear/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/gl-clear.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/glClearColor/#kotlin.Float#kotlin.Float#kotlin.Float#kotlin.Float/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/gl-clear-color.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/glEnable/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/gl-enable.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/glFinish/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/gl-finish.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/glGetIntegerv/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/gl-get-integerv.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/glGetString/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/gl-get-string.html
+$dokka.location:org.jetbrains.skiko/OpenGLApi/glViewport/#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skiko/-open-g-l-api/gl-viewport.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursors///PointingToDeclaration/skiko/org.jetbrains.skiko/-predefined-cursors/index.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursors/CROSSHAIR/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-predefined-cursors/-c-r-o-s-s-h-a-i-r.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursors/DEFAULT/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-predefined-cursors/-d-e-f-a-u-l-t.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursors/HAND/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-predefined-cursors/-h-a-n-d.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursors/TEXT/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-predefined-cursors/-t-e-x-t.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursorsId.CROSSHAIR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-predefined-cursors-id/-c-r-o-s-s-h-a-i-r/index.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursorsId.DEFAULT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-predefined-cursors-id/-d-e-f-a-u-l-t/index.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursorsId.HAND///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-predefined-cursors-id/-h-a-n-d/index.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursorsId.TEXT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-predefined-cursors-id/-t-e-x-t/index.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursorsId///PointingToDeclaration/skiko/org.jetbrains.skiko/-predefined-cursors-id/index.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursorsId/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-predefined-cursors-id/value-of.html
+$dokka.location:org.jetbrains.skiko/PredefinedCursorsId/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-predefined-cursors-id/values.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer///PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/index.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/SkiaLayer/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/-skia-layer.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/attachTo/#[Error type: Unresolved type for NSWindow]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/attach-to.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/attachTo/#[Error type: Unresolved type for UIView]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/attach-to.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/attachTo/#kotlin.Any/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/attach-to.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/attachTo/#org.w3c.dom.HTMLCanvasElement#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/attach-to.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/component/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/component.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/contentScale/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/content-scale.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/detach/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/detach.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/fullscreen/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/fullscreen.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/gesturesToListen/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/gestures-to-listen.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/height/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/height.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/hideScreenKeyboard/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/hide-screen-keyboard.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/isScreenKeyboardOpen/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/is-screen-keyboard-open.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/isShowing/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/[macos]is-showing.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/needRedraw/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/need-redraw.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/nsView/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/ns-view.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/pixelGeometry/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/pixel-geometry.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/renderApi/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/render-api.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/showScreenKeyboard/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/show-screen-keyboard.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/skikoView/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/skiko-view.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/transparency/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/transparency.html
+$dokka.location:org.jetbrains.skiko/SkiaLayer/width/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer/width.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.Companion///PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-companion/index.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.Companion/Empty/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-companion/-empty.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.DeviceAnalytics.Companion///PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-device-analytics/-companion/index.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.DeviceAnalytics.Companion/Empty/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-device-analytics/-companion/-empty.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.DeviceAnalytics///PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-device-analytics/index.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.DeviceAnalytics/afterFirstFrameRender/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-device-analytics/after-first-frame-render.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.DeviceAnalytics/beforeFirstFrameRender/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-device-analytics/before-first-frame-render.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.DeviceAnalytics/contextInit/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-device-analytics/context-init.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.DeviceAnalytics/init/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-device-analytics/init.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.RendererAnalytics.Companion///PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-renderer-analytics/-companion/index.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.RendererAnalytics.Companion/Empty/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-renderer-analytics/-companion/-empty.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.RendererAnalytics///PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-renderer-analytics/index.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.RendererAnalytics/deviceChosen/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-renderer-analytics/device-chosen.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics.RendererAnalytics/init/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/-renderer-analytics/init.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics///PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/index.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics/device/#kotlin.String#org.jetbrains.skiko.OS#org.jetbrains.skiko.GraphicsApi#kotlin.String?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/device.html
+$dokka.location:org.jetbrains.skiko/SkiaLayerAnalytics/renderer/#kotlin.String#org.jetbrains.skiko.OS#org.jetbrains.skiko.GraphicsApi/PointingToDeclaration/skiko/org.jetbrains.skiko/-skia-layer-analytics/renderer.html
+$dokka.location:org.jetbrains.skiko/SkikoDispatchers///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-dispatchers/index.html
+$dokka.location:org.jetbrains.skiko/SkikoDispatchers/IO/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-dispatchers/-i-o.html
+$dokka.location:org.jetbrains.skiko/SkikoDispatchers/Main/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-dispatchers/-main.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEvent///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEvent/SkikoGestureEvent/#kotlin.Double#kotlin.Double#kotlin.Double#org.jetbrains.skiko.SkikoGestureEventDirection#kotlin.Double#kotlin.Double#org.jetbrains.skiko.SkikoGestureEventKind#org.jetbrains.skiko.SkikoGestureEventState#org.jetbrains.skiko.SkikoGesturePlatformEvent?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event/-skiko-gesture-event.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEvent/direction/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event/direction.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEvent/kind/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event/kind.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEvent/platform/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event/platform.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEvent/rotation/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event/rotation.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEvent/scale/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event/scale.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEvent/state/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event/state.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEvent/velocity/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event/velocity.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEvent/x/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event/x.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEvent/y/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event/y.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventDirection.DOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-direction/-d-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventDirection.LEFT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-direction/-l-e-f-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventDirection.RIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-direction/-r-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventDirection.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-direction/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventDirection.UP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-direction/-u-p/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventDirection///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event-direction/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventDirection/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event-direction/value-of.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventDirection/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event-direction/values.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventKind.DOUBLETAP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-kind/-d-o-u-b-l-e-t-a-p/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventKind.LONGPRESS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-kind/-l-o-n-g-p-r-e-s-s/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventKind.PAN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-kind/-p-a-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventKind.PINCH///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-kind/-p-i-n-c-h/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventKind.ROTATION///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-kind/-r-o-t-a-t-i-o-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventKind.SWIPE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-kind/-s-w-i-p-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventKind.TAP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-kind/-t-a-p/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventKind.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-kind/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventKind///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event-kind/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventKind/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event-kind/value-of.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventKind/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event-kind/values.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventState.CHANGED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-state/-c-h-a-n-g-e-d/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventState.ENDED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-state/-e-n-d-e-d/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventState.PRESSED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-state/-p-r-e-s-s-e-d/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventState.STARTED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-state/-s-t-a-r-t-e-d/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventState.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-gesture-event-state/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventState///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event-state/index.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventState/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event-state/value-of.html
+$dokka.location:org.jetbrains.skiko/SkikoGestureEventState/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-event-state/values.html
+$dokka.location:org.jetbrains.skiko/SkikoGesturePlatformEvent///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-gesture-platform-event/index.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/index.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/deleteBackward/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/delete-backward.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/endOfDocument/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/end-of-document.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/getSelectedTextRange/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/get-selected-text-range.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/hasText/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/has-text.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/insertText/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/insert-text.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/markedTextRange/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/marked-text-range.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/onInputEvent/#org.jetbrains.skiko.SkikoInputEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/on-input-event.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/replaceRange/#kotlin.ranges.IntRange#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/replace-range.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/selectAll/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/select-all.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/setMarkedText/#kotlin.String?#kotlin.ranges.IntRange/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/set-marked-text.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/setSelectedTextRange/#kotlin.ranges.IntRange?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/set-selected-text-range.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/textInRange/#kotlin.ranges.IntRange/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/text-in-range.html
+$dokka.location:org.jetbrains.skiko/SkikoInput.Empty/unmarkText/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/-empty/unmark-text.html
+$dokka.location:org.jetbrains.skiko/SkikoInput///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/index.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/deleteBackward/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/delete-backward.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/endOfDocument/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/end-of-document.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/getSelectedTextRange/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/get-selected-text-range.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/hasText/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/has-text.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/insertText/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/insert-text.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/markedTextRange/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/marked-text-range.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/onInputEvent/#org.jetbrains.skiko.SkikoInputEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/on-input-event.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/replaceRange/#kotlin.ranges.IntRange#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/replace-range.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/selectAll/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/select-all.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/setMarkedText/#kotlin.String?#kotlin.ranges.IntRange/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/set-marked-text.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/setSelectedTextRange/#kotlin.ranges.IntRange?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/set-selected-text-range.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/textInRange/#kotlin.ranges.IntRange/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/text-in-range.html
+$dokka.location:org.jetbrains.skiko/SkikoInput/unmarkText/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input/unmark-text.html
+$dokka.location:org.jetbrains.skiko/SkikoInputEvent///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-event/index.html
+$dokka.location:org.jetbrains.skiko/SkikoInputEvent/SkikoInputEvent/#kotlin.String#org.jetbrains.skiko.SkikoKey#org.jetbrains.skiko.SkikoInputModifiers#org.jetbrains.skiko.SkikoKeyboardEventKind#org.jetbrains.skiko.SkikoPlatformInputEvent?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-event/-skiko-input-event.html
+$dokka.location:org.jetbrains.skiko/SkikoInputEvent/input/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-event/input.html
+$dokka.location:org.jetbrains.skiko/SkikoInputEvent/key/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-event/key.html
+$dokka.location:org.jetbrains.skiko/SkikoInputEvent/kind/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-event/kind.html
+$dokka.location:org.jetbrains.skiko/SkikoInputEvent/modifiers/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-event/modifiers.html
+$dokka.location:org.jetbrains.skiko/SkikoInputEvent/platform/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-event/platform.html
+$dokka.location:org.jetbrains.skiko/SkikoInputModifiers.Companion///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-modifiers/-companion/index.html
+$dokka.location:org.jetbrains.skiko/SkikoInputModifiers.Companion/ALT/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-modifiers/-companion/-a-l-t.html
+$dokka.location:org.jetbrains.skiko/SkikoInputModifiers.Companion/CONTROL/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-modifiers/-companion/-c-o-n-t-r-o-l.html
+$dokka.location:org.jetbrains.skiko/SkikoInputModifiers.Companion/EMPTY/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-modifiers/-companion/-e-m-p-t-y.html
+$dokka.location:org.jetbrains.skiko/SkikoInputModifiers.Companion/META/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-modifiers/-companion/-m-e-t-a.html
+$dokka.location:org.jetbrains.skiko/SkikoInputModifiers.Companion/SHIFT/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-modifiers/-companion/-s-h-i-f-t.html
+$dokka.location:org.jetbrains.skiko/SkikoInputModifiers///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-modifiers/index.html
+$dokka.location:org.jetbrains.skiko/SkikoInputModifiers/SkikoInputModifiers/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-modifiers/-skiko-input-modifiers.html
+$dokka.location:org.jetbrains.skiko/SkikoInputModifiers/has/#org.jetbrains.skiko.SkikoInputModifiers/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-modifiers/has.html
+$dokka.location:org.jetbrains.skiko/SkikoInputModifiers/toString/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-modifiers/to-string.html
+$dokka.location:org.jetbrains.skiko/SkikoInputModifiers/value/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-input-modifiers/value.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.Companion///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-key/[macos]-companion/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.Companion/valueOf/#[Error type: Unresolved type for UIKeyboardHIDUsage]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-key/[ios]-companion/value-of.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.Companion/valueOf/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-key/[macos]-companion/value-of.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_0///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_0/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_1///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_1/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_2///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_2/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_3///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_3/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_4///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_4/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_5///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_5/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_6///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_6/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_7///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_7/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_8///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_8/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_9///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_9/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_A///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-a/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_B///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-b/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_BACKSLASH///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-b-a-c-k-s-l-a-s-h/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_BACKSPACE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-b-a-c-k-s-p-a-c-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_BACK_QUOTE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-b-a-c-k_-q-u-o-t-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_C///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-c/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_CAPSLOCK///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-c-a-p-s-l-o-c-k/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_CLOSE_BRACKET///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-c-l-o-s-e_-b-r-a-c-k-e-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_COMMA///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-c-o-m-m-a/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_D///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-d/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_DELETE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-d-e-l-e-t-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_DOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-d-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_E///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_END///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-e-n-d/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_ENTER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-e-n-t-e-r/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_EQUALS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-e-q-u-a-l-s/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_ESCAPE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-e-s-c-a-p-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F1///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f1/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F10///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f10/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F11///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f11/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F12///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f12/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F2///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f2/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F3///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f3/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F4///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f4/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F5///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f5/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F6///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f6/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F7///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f7/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F8///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f8/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_F9///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-f9/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_G///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-g/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_H///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-h/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_HOME///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-h-o-m-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_I///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-i/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_INSERT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-i-n-s-e-r-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_J///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-j/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_K///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-k/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_L///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-l/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_LEFT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-l-e-f-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_LEFT_ALT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-l-e-f-t_-a-l-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_LEFT_CONTROL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-l-e-f-t_-c-o-n-t-r-o-l/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_LEFT_META///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-l-e-f-t_-m-e-t-a/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_LEFT_SHIFT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-l-e-f-t_-s-h-i-f-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_M///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-m/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_MENU///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-m-e-n-u/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_MINUS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-m-i-n-u-s/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_N///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_0///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_0/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_1///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_1/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_2///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_2/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_3///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_3/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_4///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_4/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_5///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_5/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_6///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_6/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_7///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_7/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_8///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_8/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_9///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_9/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_ADD///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_-a-d-d/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_DECIMAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_-d-e-c-i-m-a-l/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_DIVIDE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_-d-i-v-i-d-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_ENTER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_-e-n-t-e-r/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_MULTIPLY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_-m-u-l-t-i-p-l-y/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUMPAD_SUBTRACT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m-p-a-d_-s-u-b-t-r-a-c-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_NUM_LOCK///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-n-u-m_-l-o-c-k/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_O///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-o/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_OPEN_BRACKET///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-o-p-e-n_-b-r-a-c-k-e-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_P///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-p/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_PAUSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-p-a-u-s-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_PERIOD///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-p-e-r-i-o-d/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_PGDOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-p-g-d-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_PGUP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-p-g-u-p/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_PRINTSCEEN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-p-r-i-n-t-s-c-e-e-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_Q///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-q/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_QUOTE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-q-u-o-t-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_R///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-r/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_RIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-r-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_RIGHT_ALT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-r-i-g-h-t_-a-l-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_RIGHT_CONTROL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-r-i-g-h-t_-c-o-n-t-r-o-l/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_RIGHT_META///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-r-i-g-h-t_-m-e-t-a/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_RIGHT_SHIFT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-r-i-g-h-t_-s-h-i-f-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_S///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-s/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_SCROLL_LOCK///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-s-c-r-o-l-l_-l-o-c-k/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_SEMICOLON///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-s-e-m-i-c-o-l-o-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_SLASH///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-s-l-a-s-h/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_SPACE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-s-p-a-c-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_T///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_TAB///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-t-a-b/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_U///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-u/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_UP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-u-p/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_V///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-v/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_W///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-w/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_X///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-x/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_Y///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-y/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey.KEY_Z///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-key/-k-e-y_-z/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-key/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKey/platformKeyCode/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-key/platform-key-code.html
+$dokka.location:org.jetbrains.skiko/SkikoKey/value/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-key/value.html
+$dokka.location:org.jetbrains.skiko/SkikoKey/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-key/[macos]value-of.html
+$dokka.location:org.jetbrains.skiko/SkikoKey/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-key/[macos]values.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEvent///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-keyboard-event/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEvent/SkikoKeyboardEvent/#org.jetbrains.skiko.SkikoKey#org.jetbrains.skiko.SkikoInputModifiers#org.jetbrains.skiko.SkikoKeyboardEventKind#kotlin.Long#org.jetbrains.skiko.SkikoPlatformKeyboardEvent?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-keyboard-event/-skiko-keyboard-event.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEvent/key/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-keyboard-event/key.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEvent/kind/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-keyboard-event/kind.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEvent/modifiers/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-keyboard-event/modifiers.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEvent/platform/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-keyboard-event/platform.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEvent/timestamp/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-keyboard-event/timestamp.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEventKind.DOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-keyboard-event-kind/-d-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEventKind.TYPE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-keyboard-event-kind/-t-y-p-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEventKind.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-keyboard-event-kind/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEventKind.UP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-keyboard-event-kind/-u-p/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEventKind///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-keyboard-event-kind/index.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEventKind/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-keyboard-event-kind/value-of.html
+$dokka.location:org.jetbrains.skiko/SkikoKeyboardEventKind/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-keyboard-event-kind/values.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/index.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/debug/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/debug.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/debug/#kotlin.Throwable#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/debug.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/error/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/error.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/error/#kotlin.Throwable#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/error.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/info/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/info.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/info/#kotlin.Throwable#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/info.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/isDebugEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/is-debug-enabled.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/isErrorEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/is-error-enabled.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/isInfoEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/is-info-enabled.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/isTraceEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/is-trace-enabled.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/isWarnEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/is-warn-enabled.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/trace/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/trace.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/trace/#kotlin.Throwable#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/trace.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/warn/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/warn.html
+$dokka.location:org.jetbrains.skiko/SkikoLoggerInterface/warn/#kotlin.Throwable#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-logger-interface/warn.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/index.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/BUTTON_1/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-b-u-t-t-o-n_1.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/BUTTON_2/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-b-u-t-t-o-n_2.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/BUTTON_3/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-b-u-t-t-o-n_3.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/BUTTON_4/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-b-u-t-t-o-n_4.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/BUTTON_5/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-b-u-t-t-o-n_5.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/BUTTON_6/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-b-u-t-t-o-n_6.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/BUTTON_7/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-b-u-t-t-o-n_7.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/BUTTON_8/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-b-u-t-t-o-n_8.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/LEFT/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-l-e-f-t.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/MIDDLE/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-m-i-d-d-l-e.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/NONE/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-n-o-n-e.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons.Companion/RIGHT/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-companion/-r-i-g-h-t.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/index.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons/SkikoMouseButtons/#kotlin.Int/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/-skiko-mouse-buttons.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons/has/#org.jetbrains.skiko.SkikoMouseButtons/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/has.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons/toString/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/to-string.html
+$dokka.location:org.jetbrains.skiko/SkikoMouseButtons/value/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-mouse-buttons/value.html
+$dokka.location:org.jetbrains.skiko/SkikoPlatformInputEvent///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-platform-input-event/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPlatformKeyboardEvent///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-platform-keyboard-event/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPlatformPointerEvent///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-platform-pointer-event/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointer///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointer/SkikoPointer/#kotlin.Long#kotlin.Double#kotlin.Double#kotlin.Boolean#org.jetbrains.skiko.SkikoPointerDevice#kotlin.Double/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer/-skiko-pointer.html
+$dokka.location:org.jetbrains.skiko/SkikoPointer/device/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer/device.html
+$dokka.location:org.jetbrains.skiko/SkikoPointer/id/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer/id.html
+$dokka.location:org.jetbrains.skiko/SkikoPointer/pressed/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer/pressed.html
+$dokka.location:org.jetbrains.skiko/SkikoPointer/pressure/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer/pressure.html
+$dokka.location:org.jetbrains.skiko/SkikoPointer/x/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer/x.html
+$dokka.location:org.jetbrains.skiko/SkikoPointer/y/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer/y.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerDevice.MOUSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-pointer-device/-m-o-u-s-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerDevice.TOUCH///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-pointer-device/-t-o-u-c-h/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerDevice.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-pointer-device/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerDevice///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-device/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerDevice/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-device/value-of.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerDevice/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-device/values.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/SkikoPointerEvent/#kotlin.Double#kotlin.Double#org.jetbrains.skiko.SkikoPointerEventKind#kotlin.Double#kotlin.Double#org.jetbrains.skiko.SkikoMouseButtons#org.jetbrains.skiko.SkikoMouseButtons#org.jetbrains.skiko.SkikoInputModifiers#kotlin.Long#kotlin.collections.List[org.jetbrains.skiko.SkikoPointer]#org.jetbrains.skiko.SkikoPlatformPointerEvent?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/-skiko-pointer-event.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/button/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/button.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/deltaX/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/delta-x.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/deltaY/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/delta-y.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/kind/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/kind.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/modifiers/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/modifiers.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/platform/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/platform.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/pointers/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/pointers.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/pressedButtons/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/pressed-buttons.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/timestamp/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/timestamp.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/x/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/x.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEvent/y/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event/y.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEventKind.DOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-pointer-event-kind/-d-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEventKind.DRAG///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-pointer-event-kind/-d-r-a-g/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEventKind.ENTER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-pointer-event-kind/-e-n-t-e-r/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEventKind.EXIT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-pointer-event-kind/-e-x-i-t/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEventKind.MOVE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-pointer-event-kind/-m-o-v-e/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEventKind.SCROLL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-pointer-event-kind/-s-c-r-o-l-l/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEventKind.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-pointer-event-kind/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEventKind.UP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-skiko-pointer-event-kind/-u-p/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEventKind///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event-kind/index.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEventKind/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event-kind/value-of.html
+$dokka.location:org.jetbrains.skiko/SkikoPointerEventKind/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-pointer-event-kind/values.html
+$dokka.location:org.jetbrains.skiko/SkikoProperties///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-properties/index.html
+$dokka.location:org.jetbrains.skiko/SkikoProperties/fpsEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-properties/fps-enabled.html
+$dokka.location:org.jetbrains.skiko/SkikoProperties/fpsLongFramesMillis/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-properties/fps-long-frames-millis.html
+$dokka.location:org.jetbrains.skiko/SkikoProperties/fpsLongFramesShow/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-properties/fps-long-frames-show.html
+$dokka.location:org.jetbrains.skiko/SkikoProperties/fpsPeriodSeconds/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-properties/fps-period-seconds.html
+$dokka.location:org.jetbrains.skiko/SkikoProperties/gpuPriority/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-properties/gpu-priority.html
+$dokka.location:org.jetbrains.skiko/SkikoProperties/renderApi/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-properties/render-api.html
+$dokka.location:org.jetbrains.skiko/SkikoProperties/vsyncEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-properties/vsync-enabled.html
+$dokka.location:org.jetbrains.skiko/SkikoProperties/vsyncFramelimitFallbackEnabled/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-properties/vsync-framelimit-fallback-enabled.html
+$dokka.location:org.jetbrains.skiko/SkikoSurfaceView///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-surface-view/index.html
+$dokka.location:org.jetbrains.skiko/SkikoSurfaceView/SkikoSurfaceView/#android.content.Context#org.jetbrains.skiko.SkiaLayer/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-surface-view/-skiko-surface-view.html
+$dokka.location:org.jetbrains.skiko/SkikoSurfaceView/layer/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-surface-view/layer.html
+$dokka.location:org.jetbrains.skiko/SkikoSurfaceView/onFrameCompleted/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-surface-view/on-frame-completed.html
+$dokka.location:org.jetbrains.skiko/SkikoSurfaceView/onKeyDown/#kotlin.Int#android.view.KeyEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-surface-view/on-key-down.html
+$dokka.location:org.jetbrains.skiko/SkikoSurfaceView/onKeyUp/#kotlin.Int#android.view.KeyEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-surface-view/on-key-up.html
+$dokka.location:org.jetbrains.skiko/SkikoSurfaceView/onTouchEvent/#android.view.MotionEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-surface-view/on-touch-event.html
+$dokka.location:org.jetbrains.skiko/SkikoSurfaceView/scheduleFrame/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-surface-view/schedule-frame.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/index.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/SkikoUIView/#[Error type: Unresolved type for NSCoder]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/-skiko-u-i-view.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/SkikoUIView/#kotlinx.cinterop.CValue[[Error type: Unresolved type for CGRect]]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/-skiko-u-i-view.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/SkikoUIView/#org.jetbrains.skiko.SkiaLayer#kotlinx.cinterop.CValue[[Error type: Unresolved type for CGRect]]#kotlin.Function2[[Error type: Unresolved type for Point],[Error type: Unresolved type for UIEvent]?,kotlin.Boolean]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/-skiko-u-i-view.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/autocapitalizationType/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/autocapitalization-type.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/autocorrectionType/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/autocorrection-type.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/baseWritingDirectionForPosition/#[Error type: Unresolved type for UITextPosition]#[Error type: Unresolved type for UITextStorageDirection]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/base-writing-direction-for-position.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/beginningOfDocument/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/beginning-of-document.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/canBecomeFirstResponder/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/can-become-first-responder.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/canPerformAction/#kotlinx.cinterop.CPointer[kotlinx.cinterop.CPointed]?#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/can-perform-action.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/caretRectForPosition/#[Error type: Unresolved type for UITextPosition]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/caret-rect-for-position.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/characterOffsetOfPosition/#[Error type: Unresolved type for UITextPosition]#[Error type: Unresolved type for UITextRange]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/character-offset-of-position.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/characterRangeAtPoint/#kotlinx.cinterop.CValue[[Error type: Unresolved type for CGPoint]]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/character-range-at-point.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/characterRangeByExtendingPosition/#[Error type: Unresolved type for UITextPosition]#[Error type: Unresolved type for UITextLayoutDirection]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/character-range-by-extending-position.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/closestPositionToPoint/#kotlinx.cinterop.CValue[[Error type: Unresolved type for CGPoint]]#[Error type: Unresolved type for UITextRange]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/closest-position-to-point.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/closestPositionToPoint/#kotlinx.cinterop.CValue[[Error type: Unresolved type for CGPoint]]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/closest-position-to-point.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/comparePosition/#[Error type: Unresolved type for UITextPosition]#[Error type: Unresolved type for UITextPosition]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/compare-position.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/copy/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/copy.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/currentAutocapitalizationType/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/current-autocapitalization-type.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/currentAutocorrectionType/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/current-autocorrection-type.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/currentEnablesReturnKeyAutomatically/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/current-enables-return-key-automatically.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/currentIsSecureTextEntry/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/current-is-secure-text-entry.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/currentKeyboardAppearance/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/current-keyboard-appearance.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/currentKeyboardType/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/current-keyboard-type.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/currentReturnKeyType/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/current-return-key-type.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/currentTextContentType/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/current-text-content-type.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/cut/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/cut.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/deleteBackward/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/delete-backward.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/detach/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/detach.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/dictationRecognitionFailed/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/dictation-recognition-failed.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/dictationRecordingDidEnd/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/dictation-recording-did-end.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/enablesReturnKeyAutomatically/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/enables-return-key-automatically.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/endOfDocument/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/end-of-document.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/firstRectForRange/#[Error type: Unresolved type for UITextRange]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/first-rect-for-range.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/hasText/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/has-text.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/hideScreenKeyboard/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/hide-screen-keyboard.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/hideTextMenu/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/hide-text-menu.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/inputDelegate/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/input-delegate.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/insertText/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/insert-text.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/isScreenKeyboardOpen/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/is-screen-keyboard-open.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/isSecureTextEntry/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/is-secure-text-entry.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/isTextMenuShown/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/is-text-menu-shown.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/keyboardAppearance/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/keyboard-appearance.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/keyboardType/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/keyboard-type.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/load/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/load.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/markedTextRange/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/marked-text-range.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/markedTextStyle/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/marked-text-style.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/offsetFromPosition/#[Error type: Unresolved type for UITextPosition]#[Error type: Unresolved type for UITextPosition]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/offset-from-position.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/paste/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/paste.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/pointInside/#kotlinx.cinterop.CValue[[Error type: Unresolved type for CGPoint]]#[Error type: Unresolved type for UIEvent]?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/point-inside.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/positionFromPosition/#[Error type: Unresolved type for UITextPosition]#[Error type: Unresolved type for NSInteger]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/position-from-position.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/positionFromPosition/#[Error type: Unresolved type for UITextPosition]#[Error type: Unresolved type for UITextLayoutDirection]#[Error type: Unresolved type for NSInteger]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/position-from-position.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/positionWithinRange/#[Error type: Unresolved type for UITextRange]#[Error type: Unresolved type for NSInteger]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/position-within-range.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/positionWithinRange/#[Error type: Unresolved type for UITextRange]#[Error type: Unresolved type for UITextLayoutDirection]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/position-within-range.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/pressesBegan/#kotlin.collections.Set[*]#[Error type: Unresolved type for UIPressesEvent]?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/presses-began.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/pressesEnded/#kotlin.collections.Set[*]#[Error type: Unresolved type for UIPressesEvent]?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/presses-ended.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/replaceRange/#[Error type: Unresolved type for UITextRange]#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/replace-range.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/returnKeyType/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/return-key-type.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/selectAll/#kotlin.Any?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/select-all.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/selectedTextRange/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/selected-text-range.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/selectionDidChange/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/selection-did-change.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/selectionRectsForRange/#[Error type: Unresolved type for UITextRange]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/selection-rects-for-range.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/selectionWillChange/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/selection-will-change.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/setBaseWritingDirection/#[Error type: Unresolved type for NSWritingDirection]#[Error type: Unresolved type for UITextRange]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/set-base-writing-direction.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/setInputDelegate/#[Error type: Unresolved type for UITextInputDelegateProtocol]?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/set-input-delegate.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/setMarkedText/#kotlin.String?#kotlinx.cinterop.CValue[[Error type: Unresolved type for NSRange]]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/set-marked-text.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/setMarkedTextStyle/#kotlin.collections.Map[kotlin.Any?,*]?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/set-marked-text-style.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/setSelectedTextRange/#[Error type: Unresolved type for UITextRange]?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/set-selected-text-range.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/shouldChangeTextInRange/#[Error type: Unresolved type for UITextRange]#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/should-change-text-in-range.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/showScreenKeyboard/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/show-screen-keyboard.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/showTextMenu/#[Error type: Unresolved type for Rect]#org.jetbrains.skiko.TextActions/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/show-text-menu.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/textContentType/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/text-content-type.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/textDidChange/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/text-did-change.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/textInRange/#[Error type: Unresolved type for UITextRange]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/text-in-range.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/textInputView/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/text-input-view.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/textRangeFromPosition/#[Error type: Unresolved type for UITextPosition]#[Error type: Unresolved type for UITextPosition]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/text-range-from-position.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/textStylingAtPosition/#[Error type: Unresolved type for UITextPosition]#[Error type: Unresolved type for UITextStorageDirection]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/text-styling-at-position.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/textWillChange/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/text-will-change.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/tokenizer/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/tokenizer.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/touchesBegan/#kotlin.collections.Set[*]#[Error type: Unresolved type for UIEvent]?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/touches-began.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/touchesCancelled/#kotlin.collections.Set[*]#[Error type: Unresolved type for UIEvent]?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/touches-cancelled.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/touchesEnded/#kotlin.collections.Set[*]#[Error type: Unresolved type for UIEvent]?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/touches-ended.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/touchesMoved/#kotlin.collections.Set[*]#[Error type: Unresolved type for UIEvent]?/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/touches-moved.html
+$dokka.location:org.jetbrains.skiko/SkikoUIView/unmarkText/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-u-i-view/unmark-text.html
+$dokka.location:org.jetbrains.skiko/SkikoView///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view/index.html
+$dokka.location:org.jetbrains.skiko/SkikoView/input/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view/input.html
+$dokka.location:org.jetbrains.skiko/SkikoView/onGestureEvent/#org.jetbrains.skiko.SkikoGestureEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view/on-gesture-event.html
+$dokka.location:org.jetbrains.skiko/SkikoView/onInputEvent/#org.jetbrains.skiko.SkikoInputEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view/on-input-event.html
+$dokka.location:org.jetbrains.skiko/SkikoView/onKeyboardEvent/#org.jetbrains.skiko.SkikoKeyboardEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view/on-keyboard-event.html
+$dokka.location:org.jetbrains.skiko/SkikoView/onPointerEvent/#org.jetbrains.skiko.SkikoPointerEvent/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view/on-pointer-event.html
+$dokka.location:org.jetbrains.skiko/SkikoView/onRender/#org.jetbrains.skia.Canvas#kotlin.Int#kotlin.Int#kotlin.Long/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view/on-render.html
+$dokka.location:org.jetbrains.skiko/SkikoViewController///PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view-controller/index.html
+$dokka.location:org.jetbrains.skiko/SkikoViewController/SkikoViewController/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view-controller/-skiko-view-controller.html
+$dokka.location:org.jetbrains.skiko/SkikoViewController/SkikoViewController/#[Error type: Unresolved type for NSCoder]/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view-controller/-skiko-view-controller.html
+$dokka.location:org.jetbrains.skiko/SkikoViewController/SkikoViewController/#org.jetbrains.skiko.SkikoUIView/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view-controller/-skiko-view-controller.html
+$dokka.location:org.jetbrains.skiko/SkikoViewController/loadView/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view-controller/load-view.html
+$dokka.location:org.jetbrains.skiko/SkikoViewController/viewDidDisappear/#kotlin.Boolean/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view-controller/view-did-disappear.html
+$dokka.location:org.jetbrains.skiko/SkikoViewController/viewDidLoad/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-skiko-view-controller/view-did-load.html
+$dokka.location:org.jetbrains.skiko/SystemTheme.DARK///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-system-theme/-d-a-r-k/index.html
+$dokka.location:org.jetbrains.skiko/SystemTheme.LIGHT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-system-theme/-l-i-g-h-t/index.html
+$dokka.location:org.jetbrains.skiko/SystemTheme.UNKNOWN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}skiko/org.jetbrains.skiko/-system-theme/-u-n-k-n-o-w-n/index.html
+$dokka.location:org.jetbrains.skiko/SystemTheme///PointingToDeclaration/skiko/org.jetbrains.skiko/-system-theme/index.html
+$dokka.location:org.jetbrains.skiko/SystemTheme/valueOf/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-system-theme/value-of.html
+$dokka.location:org.jetbrains.skiko/SystemTheme/values/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-system-theme/values.html
+$dokka.location:org.jetbrains.skiko/TextActions///PointingToDeclaration/skiko/org.jetbrains.skiko/-text-actions/index.html
+$dokka.location:org.jetbrains.skiko/TextActions/copy/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-text-actions/copy.html
+$dokka.location:org.jetbrains.skiko/TextActions/cut/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-text-actions/cut.html
+$dokka.location:org.jetbrains.skiko/TextActions/paste/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-text-actions/paste.html
+$dokka.location:org.jetbrains.skiko/TextActions/selectAll/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-text-actions/select-all.html
+$dokka.location:org.jetbrains.skiko/URIManager///PointingToDeclaration/skiko/org.jetbrains.skiko/-u-r-i-manager/index.html
+$dokka.location:org.jetbrains.skiko/URIManager/URIManager/#/PointingToDeclaration/skiko/org.jetbrains.skiko/-u-r-i-manager/-u-r-i-manager.html
+$dokka.location:org.jetbrains.skiko/URIManager/openUri/#kotlin.String/PointingToDeclaration/skiko/org.jetbrains.skiko/-u-r-i-manager/open-uri.html
+org.jetbrains.skia
+org.jetbrains.skia.icu
+org.jetbrains.skia.impl
+org.jetbrains.skia.paragraph
+org.jetbrains.skia.shaper
+org.jetbrains.skia.skottie
+org.jetbrains.skia.sksg
+org.jetbrains.skia.svg
+org.jetbrains.skiko
+org.jetbrains.skiko.wasm
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index e62e0d7..3e1f91d 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -28,6 +28,8 @@
docs(project(":appcompat:appcompat"))
docs(project(":appcompat:appcompat-resources"))
docs(project(":appsearch:appsearch"))
+ docs(project(":appsearch:appsearch-builtin-types"))
+ docs(project(":appsearch:appsearch-platform-storage"))
docs(project(":appsearch:appsearch-local-storage"))
docs(project(":arch:core:core-common"))
docs(project(":arch:core:core-runtime"))
@@ -134,6 +136,8 @@
docs(project(":core:core-splashscreen"))
docs(project(":core:core-role"))
docs(project(":core:core-testing"))
+ docs(project(":core:haptics:haptics"))
+ samples(project(":core:haptics:haptics-samples"))
docs(project(":core:uwb:uwb"))
docs(project(":core:uwb:uwb-rxjava3"))
docs(project(":credentials:credentials"))
@@ -327,7 +331,6 @@
docs(project(":wear:protolayout:protolayout-expression"))
docs(project(":wear:protolayout:protolayout-expression-pipeline"))
docs(project(":wear:protolayout:protolayout-material"))
- docs(project(":wear:protolayout:protolayout-proto"))
docs(project(":wear:protolayout:protolayout-renderer"))
docs(project(":wear:wear"))
stubs(fileTree(dir: "../wear/wear_stubs/", include: ["com.google.android.wearable-stubs.jar"]))
diff --git a/docs/api_guidelines/misc.md b/docs/api_guidelines/misc.md
index 2fa9b8f..a2930e6 100644
--- a/docs/api_guidelines/misc.md
+++ b/docs/api_guidelines/misc.md
@@ -114,11 +114,9 @@
### `@RestrictTo` APIs {#restricted-api}
-Jetpack's library tooling supports hiding Java-visible (ex. `public` and
+Jetpack's library tooling supports hiding JVM-visible (ex. `public` and
`protected`) APIs from developers using a combination of the `@RestrictTo`
-source annotation, and the `@hide` docs annotation (`@suppress` in Kotlin).
-These annotations **must** be paired together when used, and are validated as
-part of presubmit checks for Java code.
+source annotation.
> `@RestrictTo` at-a-glance:
>
@@ -135,24 +133,20 @@
* Android Studio will not warn if hidden APIs are called using reflection
* Hidden APIs will still show in Android Studio's auto-complete
-#### When to use `@hide` {#restricted-api-usage}
+These annotations indicate that developers should not call an API that is
+*technically* public from a JVM visibility perspective. Hiding APIs is often a
+sign of a poorly-abstracted API surface, and priority should be given to
+creating public, maintainable APIs and using Java visibility modifiers.
-In other cases, avoid using `@hide` / `@suppress`. These annotations indicates
-that developers should not call an API that is *technically* public from a Java
-visibility perspective. Hiding APIs is often a sign of a poorly-abstracted API
-surface, and priority should be given to creating public, maintainable APIs and
-using Java visibility modifiers.
+*Do not* use `@RestrictTo` to bypass API tracking and review for production
+APIs; instead, rely on API+1 and API Council review to ensure APIs are reviewed
+on a timely basis.
-*Do not* use `@hide`/`@suppress` to bypass API tracking and review for
-production APIs; instead, rely on API+1 and API Council review to ensure APIs
-are reviewed on a timely basis.
+*Do not* use `@RestrictTo` for implementation detail APIs that are used between
+libraries and could reasonably be made public.
-*Do not* use `@hide`/`@suppress` for implementation detail APIs that are used
-between libraries and could reasonably be made public.
-
-*Do* use `@hide`/`@suppress` paired with `@RestrictTo(LIBRARY)` for
-implementation detail APIs used within a single library (but prefer Java
-language `private` or `default` visibility).
+*Do* use `@RestrictTo(LIBRARY)` for implementation detail APIs used within a
+single library (but prefer Java language `private` or `default` visibility).
#### `RestrictTo.Scope` and inter- versus intra-library API surfaces {#private-api-types}
@@ -160,13 +154,13 @@
restricted API surfaces that are used between libraries within Jetpack
(inter-library APIs) must follow the same Semantic Versioning rules as public
APIs. Inter-library APIs should be annotated with the
-`@RestrictTo(LIBRARY_GROUP)` source annotation and `@hide` docs annotation.
+`@RestrictTo(LIBRARY_GROUP)` source annotation.
Restricted API surfaces used within a single library (intra-library APIs), on
the other hand, may be added or removed without any compatibility
considerations. It is safe to assume that developers *never* call these APIs,
even though it is technically feasible. Intra-library APIs should be annotated
-with the `@RestrictTo(LIBRARY)` source annotation and `@hide` docs annotation.
+with the `@RestrictTo(LIBRARY)` source annotation.
In all cases, correctness and compatibility tracking are handled by AndroidX's
build system and lint checks.
@@ -216,12 +210,10 @@
and packaged separately to be read by Android Studio and lint which enforces the
types in application code.
-* Libraries *must* `@hide` all `@IntDef`, `@StringDef`, and `@LongDef`
- declarations.
+* Libraries *must* `@RestrictTo` all `@IntDef`, `@StringDef`, and `@LongDef`
+ declarations to create a warning when the type is used incorrectly.
* Libraries *must* expose constants used to define the `@IntDef` etc at the
same Java visibility as the hidden `@IntDef`
-* Libraries *must* use `@RestrictTo` to create a warning when the type is used
- incorrectly.
Here is a complete example of an `@IntDef`
@@ -231,7 +223,6 @@
public static final int STREAM_TYPE_FULL_IMAGE_DATA = 1;
public static final int STREAM_TYPE_EXIF_DATA_ONLY = 2;
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY) // Don't export ExifStreamType outside module
@Retention(RetentionPolicy.SOURCE)
@IntDef({
diff --git a/emoji2/CHANGELOG.md b/emoji2/CHANGELOG.md
new file mode 100644
index 0000000..65fe7cf7
--- /dev/null
+++ b/emoji2/CHANGELOG.md
@@ -0,0 +1,26 @@
+# Log for changes in the emoji2 library
+#
+# `Added`: for new features
+# `Changed`: for changes in existing functionality
+# `Deprecated`: for soon to be removed functionality
+# `Removed`: for now removed feature
+# `Fixed`: for any bug fixes
+# `Security`: in case of vulnerabilities
+#
+# Possible headings:
+# API Changes
+# Bug Fixes
+# Dependency Updates
+# Behavior Change
+# External Contributions
+
+## Unreleased
+
+### New Features
+
+### Bug Fixes
+
+- Fixed a bug introduced in 1.3 that would cause MetricsAffectingSpans such as RelativeSizeSpan to
+ apply twice. Once during text layout, and again inside of EmojiSpan.draw. The result was
+ incorrectly sized draw, visible if any of the text size parameters were changed by the
+ span. (b/283208650)
\ No newline at end of file
diff --git a/emoji2/emoji2-bundled/api/1.4.0-beta05.txt b/emoji2/emoji2-bundled/api/1.4.0-beta05.txt
new file mode 100644
index 0000000..8749c28
--- /dev/null
+++ b/emoji2/emoji2-bundled/api/1.4.0-beta05.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.emoji2.bundled {
+
+ public class BundledEmojiCompatConfig extends androidx.emoji2.text.EmojiCompat.Config {
+ ctor public BundledEmojiCompatConfig(android.content.Context);
+ }
+
+}
+
diff --git a/emoji2/emoji2-bundled/api/res-1.4.0-beta05.txt b/emoji2/emoji2-bundled/api/res-1.4.0-beta05.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/emoji2/emoji2-bundled/api/res-1.4.0-beta05.txt
diff --git a/emoji2/emoji2-bundled/api/restricted_1.4.0-beta05.txt b/emoji2/emoji2-bundled/api/restricted_1.4.0-beta05.txt
new file mode 100644
index 0000000..8749c28
--- /dev/null
+++ b/emoji2/emoji2-bundled/api/restricted_1.4.0-beta05.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.emoji2.bundled {
+
+ public class BundledEmojiCompatConfig extends androidx.emoji2.text.EmojiCompat.Config {
+ ctor public BundledEmojiCompatConfig(android.content.Context);
+ }
+
+}
+
diff --git a/emoji2/emoji2-emojipicker/api/1.4.0-beta05.txt b/emoji2/emoji2-emojipicker/api/1.4.0-beta05.txt
new file mode 100644
index 0000000..65d3ad7
--- /dev/null
+++ b/emoji2/emoji2-emojipicker/api/1.4.0-beta05.txt
@@ -0,0 +1,43 @@
+// Signature format: 4.0
+package androidx.emoji2.emojipicker {
+
+ public final class EmojiPickerView extends android.widget.FrameLayout {
+ ctor public EmojiPickerView(android.content.Context context);
+ ctor public EmojiPickerView(android.content.Context context, optional android.util.AttributeSet? attrs);
+ ctor public EmojiPickerView(android.content.Context context, optional android.util.AttributeSet? attrs, optional int defStyleAttr);
+ method public int getEmojiGridColumns();
+ method public float getEmojiGridRows();
+ method public void setEmojiGridColumns(int);
+ method public void setEmojiGridRows(float);
+ method public void setOnEmojiPickedListener(androidx.core.util.Consumer<androidx.emoji2.emojipicker.EmojiViewItem>? onEmojiPickedListener);
+ method public void setRecentEmojiProvider(androidx.emoji2.emojipicker.RecentEmojiProvider recentEmojiProvider);
+ property public final int emojiGridColumns;
+ property public final float emojiGridRows;
+ }
+
+ public final class EmojiViewItem {
+ ctor public EmojiViewItem(String emoji, java.util.List<java.lang.String> variants);
+ method public String getEmoji();
+ method public java.util.List<java.lang.String> getVariants();
+ property public final String emoji;
+ property public final java.util.List<java.lang.String> variants;
+ }
+
+ public interface RecentEmojiAsyncProvider {
+ method public com.google.common.util.concurrent.ListenableFuture<java.util.List<java.lang.String>> getRecentEmojiListAsync();
+ method public void recordSelection(String emoji);
+ }
+
+ public interface RecentEmojiProvider {
+ method public suspend Object? getRecentEmojiList(kotlin.coroutines.Continuation<? super java.util.List<? extends java.lang.String>>);
+ method public void recordSelection(String emoji);
+ }
+
+ public final class RecentEmojiProviderAdapter implements androidx.emoji2.emojipicker.RecentEmojiProvider {
+ ctor public RecentEmojiProviderAdapter(androidx.emoji2.emojipicker.RecentEmojiAsyncProvider recentEmojiAsyncProvider);
+ method public suspend Object? getRecentEmojiList(kotlin.coroutines.Continuation<? super java.util.List<? extends java.lang.String>>);
+ method public void recordSelection(String emoji);
+ }
+
+}
+
diff --git a/emoji2/emoji2-emojipicker/api/res-1.4.0-beta05.txt b/emoji2/emoji2-emojipicker/api/res-1.4.0-beta05.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/emoji2/emoji2-emojipicker/api/res-1.4.0-beta05.txt
diff --git a/emoji2/emoji2-emojipicker/api/restricted_1.4.0-beta05.txt b/emoji2/emoji2-emojipicker/api/restricted_1.4.0-beta05.txt
new file mode 100644
index 0000000..65d3ad7
--- /dev/null
+++ b/emoji2/emoji2-emojipicker/api/restricted_1.4.0-beta05.txt
@@ -0,0 +1,43 @@
+// Signature format: 4.0
+package androidx.emoji2.emojipicker {
+
+ public final class EmojiPickerView extends android.widget.FrameLayout {
+ ctor public EmojiPickerView(android.content.Context context);
+ ctor public EmojiPickerView(android.content.Context context, optional android.util.AttributeSet? attrs);
+ ctor public EmojiPickerView(android.content.Context context, optional android.util.AttributeSet? attrs, optional int defStyleAttr);
+ method public int getEmojiGridColumns();
+ method public float getEmojiGridRows();
+ method public void setEmojiGridColumns(int);
+ method public void setEmojiGridRows(float);
+ method public void setOnEmojiPickedListener(androidx.core.util.Consumer<androidx.emoji2.emojipicker.EmojiViewItem>? onEmojiPickedListener);
+ method public void setRecentEmojiProvider(androidx.emoji2.emojipicker.RecentEmojiProvider recentEmojiProvider);
+ property public final int emojiGridColumns;
+ property public final float emojiGridRows;
+ }
+
+ public final class EmojiViewItem {
+ ctor public EmojiViewItem(String emoji, java.util.List<java.lang.String> variants);
+ method public String getEmoji();
+ method public java.util.List<java.lang.String> getVariants();
+ property public final String emoji;
+ property public final java.util.List<java.lang.String> variants;
+ }
+
+ public interface RecentEmojiAsyncProvider {
+ method public com.google.common.util.concurrent.ListenableFuture<java.util.List<java.lang.String>> getRecentEmojiListAsync();
+ method public void recordSelection(String emoji);
+ }
+
+ public interface RecentEmojiProvider {
+ method public suspend Object? getRecentEmojiList(kotlin.coroutines.Continuation<? super java.util.List<? extends java.lang.String>>);
+ method public void recordSelection(String emoji);
+ }
+
+ public final class RecentEmojiProviderAdapter implements androidx.emoji2.emojipicker.RecentEmojiProvider {
+ ctor public RecentEmojiProviderAdapter(androidx.emoji2.emojipicker.RecentEmojiAsyncProvider recentEmojiAsyncProvider);
+ method public suspend Object? getRecentEmojiList(kotlin.coroutines.Continuation<? super java.util.List<? extends java.lang.String>>);
+ method public void recordSelection(String emoji);
+ }
+
+}
+
diff --git a/emoji2/emoji2-views-helper/api/1.4.0-beta05.txt b/emoji2/emoji2-views-helper/api/1.4.0-beta05.txt
new file mode 100644
index 0000000..30a6feb
--- /dev/null
+++ b/emoji2/emoji2-views-helper/api/1.4.0-beta05.txt
@@ -0,0 +1,27 @@
+// Signature format: 4.0
+package androidx.emoji2.viewsintegration {
+
+ public final class EmojiEditTextHelper {
+ ctor public EmojiEditTextHelper(android.widget.EditText);
+ ctor public EmojiEditTextHelper(android.widget.EditText, boolean);
+ method public android.text.method.KeyListener? getKeyListener(android.text.method.KeyListener?);
+ method public int getMaxEmojiCount();
+ method public boolean isEnabled();
+ method public android.view.inputmethod.InputConnection? onCreateInputConnection(android.view.inputmethod.InputConnection?, android.view.inputmethod.EditorInfo);
+ method public void setEnabled(boolean);
+ method public void setMaxEmojiCount(@IntRange(from=0) int);
+ }
+
+ public final class EmojiTextViewHelper {
+ ctor public EmojiTextViewHelper(android.widget.TextView);
+ ctor public EmojiTextViewHelper(android.widget.TextView, boolean);
+ method public android.text.InputFilter![] getFilters(android.text.InputFilter![]);
+ method public boolean isEnabled();
+ method public void setAllCaps(boolean);
+ method public void setEnabled(boolean);
+ method public void updateTransformationMethod();
+ method public android.text.method.TransformationMethod? wrapTransformationMethod(android.text.method.TransformationMethod?);
+ }
+
+}
+
diff --git a/emoji2/emoji2-views-helper/api/res-1.4.0-beta05.txt b/emoji2/emoji2-views-helper/api/res-1.4.0-beta05.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/emoji2/emoji2-views-helper/api/res-1.4.0-beta05.txt
diff --git a/emoji2/emoji2-views-helper/api/restricted_1.4.0-beta05.txt b/emoji2/emoji2-views-helper/api/restricted_1.4.0-beta05.txt
new file mode 100644
index 0000000..30a6feb
--- /dev/null
+++ b/emoji2/emoji2-views-helper/api/restricted_1.4.0-beta05.txt
@@ -0,0 +1,27 @@
+// Signature format: 4.0
+package androidx.emoji2.viewsintegration {
+
+ public final class EmojiEditTextHelper {
+ ctor public EmojiEditTextHelper(android.widget.EditText);
+ ctor public EmojiEditTextHelper(android.widget.EditText, boolean);
+ method public android.text.method.KeyListener? getKeyListener(android.text.method.KeyListener?);
+ method public int getMaxEmojiCount();
+ method public boolean isEnabled();
+ method public android.view.inputmethod.InputConnection? onCreateInputConnection(android.view.inputmethod.InputConnection?, android.view.inputmethod.EditorInfo);
+ method public void setEnabled(boolean);
+ method public void setMaxEmojiCount(@IntRange(from=0) int);
+ }
+
+ public final class EmojiTextViewHelper {
+ ctor public EmojiTextViewHelper(android.widget.TextView);
+ ctor public EmojiTextViewHelper(android.widget.TextView, boolean);
+ method public android.text.InputFilter![] getFilters(android.text.InputFilter![]);
+ method public boolean isEnabled();
+ method public void setAllCaps(boolean);
+ method public void setEnabled(boolean);
+ method public void updateTransformationMethod();
+ method public android.text.method.TransformationMethod? wrapTransformationMethod(android.text.method.TransformationMethod?);
+ }
+
+}
+
diff --git a/emoji2/emoji2-views/api/1.4.0-beta05.txt b/emoji2/emoji2-views/api/1.4.0-beta05.txt
new file mode 100644
index 0000000..879b30e
--- /dev/null
+++ b/emoji2/emoji2-views/api/1.4.0-beta05.txt
@@ -0,0 +1,34 @@
+// Signature format: 4.0
+package androidx.emoji2.widget {
+
+ public class EmojiButton extends android.widget.Button {
+ ctor public EmojiButton(android.content.Context);
+ ctor public EmojiButton(android.content.Context, android.util.AttributeSet?);
+ ctor public EmojiButton(android.content.Context, android.util.AttributeSet?, int);
+ }
+
+ public class EmojiEditText extends android.widget.EditText {
+ ctor public EmojiEditText(android.content.Context);
+ ctor public EmojiEditText(android.content.Context, android.util.AttributeSet?);
+ ctor public EmojiEditText(android.content.Context, android.util.AttributeSet?, int);
+ method public int getMaxEmojiCount();
+ method public void setMaxEmojiCount(@IntRange(from=0) int);
+ }
+
+ public class EmojiExtractTextLayout extends android.widget.LinearLayout {
+ ctor public EmojiExtractTextLayout(android.content.Context);
+ ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet?, int);
+ method public int getEmojiReplaceStrategy();
+ method public void onUpdateExtractingViews(android.inputmethodservice.InputMethodService, android.view.inputmethod.EditorInfo);
+ method public void setEmojiReplaceStrategy(int);
+ }
+
+ public class EmojiTextView extends android.widget.TextView {
+ ctor public EmojiTextView(android.content.Context);
+ ctor public EmojiTextView(android.content.Context, android.util.AttributeSet?);
+ ctor public EmojiTextView(android.content.Context, android.util.AttributeSet?, int);
+ }
+
+}
+
diff --git a/emoji2/emoji2-views/api/res-1.4.0-beta05.txt b/emoji2/emoji2-views/api/res-1.4.0-beta05.txt
new file mode 100644
index 0000000..8bc8423
--- /dev/null
+++ b/emoji2/emoji2-views/api/res-1.4.0-beta05.txt
@@ -0,0 +1,2 @@
+attr emojiReplaceStrategy
+attr maxEmojiCount
diff --git a/emoji2/emoji2-views/api/restricted_1.4.0-beta05.txt b/emoji2/emoji2-views/api/restricted_1.4.0-beta05.txt
new file mode 100644
index 0000000..879b30e
--- /dev/null
+++ b/emoji2/emoji2-views/api/restricted_1.4.0-beta05.txt
@@ -0,0 +1,34 @@
+// Signature format: 4.0
+package androidx.emoji2.widget {
+
+ public class EmojiButton extends android.widget.Button {
+ ctor public EmojiButton(android.content.Context);
+ ctor public EmojiButton(android.content.Context, android.util.AttributeSet?);
+ ctor public EmojiButton(android.content.Context, android.util.AttributeSet?, int);
+ }
+
+ public class EmojiEditText extends android.widget.EditText {
+ ctor public EmojiEditText(android.content.Context);
+ ctor public EmojiEditText(android.content.Context, android.util.AttributeSet?);
+ ctor public EmojiEditText(android.content.Context, android.util.AttributeSet?, int);
+ method public int getMaxEmojiCount();
+ method public void setMaxEmojiCount(@IntRange(from=0) int);
+ }
+
+ public class EmojiExtractTextLayout extends android.widget.LinearLayout {
+ ctor public EmojiExtractTextLayout(android.content.Context);
+ ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet?, int);
+ method public int getEmojiReplaceStrategy();
+ method public void onUpdateExtractingViews(android.inputmethodservice.InputMethodService, android.view.inputmethod.EditorInfo);
+ method public void setEmojiReplaceStrategy(int);
+ }
+
+ public class EmojiTextView extends android.widget.TextView {
+ ctor public EmojiTextView(android.content.Context);
+ ctor public EmojiTextView(android.content.Context, android.util.AttributeSet?);
+ ctor public EmojiTextView(android.content.Context, android.util.AttributeSet?, int);
+ }
+
+}
+
diff --git a/emoji2/emoji2/api/1.4.0-beta05.txt b/emoji2/emoji2/api/1.4.0-beta05.txt
new file mode 100644
index 0000000..42809f9
--- /dev/null
+++ b/emoji2/emoji2/api/1.4.0-beta05.txt
@@ -0,0 +1,131 @@
+// Signature format: 4.0
+package androidx.emoji2.text {
+
+ public final class DefaultEmojiCompatConfig {
+ method public static androidx.emoji2.text.FontRequestEmojiCompatConfig? create(android.content.Context);
+ }
+
+ @AnyThread public class EmojiCompat {
+ method public static androidx.emoji2.text.EmojiCompat get();
+ method public String getAssetSignature();
+ method public int getEmojiEnd(CharSequence, @IntRange(from=0) int);
+ method public int getEmojiMatch(CharSequence, @IntRange(from=0) int);
+ method public int getEmojiStart(CharSequence, @IntRange(from=0) int);
+ method public int getLoadState();
+ method public static boolean handleDeleteSurroundingText(android.view.inputmethod.InputConnection, android.text.Editable, @IntRange(from=0) int, @IntRange(from=0) int, boolean);
+ method public static boolean handleOnKeyDown(android.text.Editable, int, android.view.KeyEvent);
+ method @Deprecated public boolean hasEmojiGlyph(CharSequence);
+ method @Deprecated public boolean hasEmojiGlyph(CharSequence, @IntRange(from=0) int);
+ method public static androidx.emoji2.text.EmojiCompat? init(android.content.Context);
+ method public static androidx.emoji2.text.EmojiCompat init(androidx.emoji2.text.EmojiCompat.Config);
+ method public static boolean isConfigured();
+ method public void load();
+ method @CheckResult public CharSequence? process(CharSequence?);
+ method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int);
+ method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+ method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, int);
+ method public void registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+ method public void unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+ method public void updateEditorInfo(android.view.inputmethod.EditorInfo);
+ field public static final String EDITOR_INFO_METAVERSION_KEY = "android.support.text.emoji.emojiCompat_metadataVersion";
+ field public static final String EDITOR_INFO_REPLACE_ALL_KEY = "android.support.text.emoji.emojiCompat_replaceAll";
+ field public static final int EMOJI_FALLBACK = 2; // 0x2
+ field public static final int EMOJI_SUPPORTED = 1; // 0x1
+ field public static final int EMOJI_UNSUPPORTED = 0; // 0x0
+ field public static final int LOAD_STATE_DEFAULT = 3; // 0x3
+ field public static final int LOAD_STATE_FAILED = 2; // 0x2
+ field public static final int LOAD_STATE_LOADING = 0; // 0x0
+ field public static final int LOAD_STATE_SUCCEEDED = 1; // 0x1
+ field public static final int LOAD_STRATEGY_DEFAULT = 0; // 0x0
+ field public static final int LOAD_STRATEGY_MANUAL = 1; // 0x1
+ field public static final int REPLACE_STRATEGY_ALL = 1; // 0x1
+ field public static final int REPLACE_STRATEGY_DEFAULT = 0; // 0x0
+ field public static final int REPLACE_STRATEGY_NON_EXISTENT = 2; // 0x2
+ }
+
+ public abstract static class EmojiCompat.Config {
+ ctor protected EmojiCompat.Config(androidx.emoji2.text.EmojiCompat.MetadataRepoLoader);
+ method protected final androidx.emoji2.text.EmojiCompat.MetadataRepoLoader getMetadataRepoLoader();
+ method public androidx.emoji2.text.EmojiCompat.Config registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+ method public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorColor(@ColorInt int);
+ method public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorEnabled(boolean);
+ method public androidx.emoji2.text.EmojiCompat.Config setGlyphChecker(androidx.emoji2.text.EmojiCompat.GlyphChecker);
+ method public androidx.emoji2.text.EmojiCompat.Config setMetadataLoadStrategy(int);
+ method public androidx.emoji2.text.EmojiCompat.Config setReplaceAll(boolean);
+ method public androidx.emoji2.text.EmojiCompat.Config setSpanFactory(androidx.emoji2.text.EmojiCompat.SpanFactory);
+ method public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean);
+ method public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean, java.util.List<java.lang.Integer!>?);
+ method public androidx.emoji2.text.EmojiCompat.Config unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+ }
+
+ public static interface EmojiCompat.GlyphChecker {
+ method public boolean hasGlyph(CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+ }
+
+ public abstract static class EmojiCompat.InitCallback {
+ ctor public EmojiCompat.InitCallback();
+ method public void onFailed(Throwable?);
+ method public void onInitialized();
+ }
+
+ public static interface EmojiCompat.MetadataRepoLoader {
+ method public void load(androidx.emoji2.text.EmojiCompat.MetadataRepoLoaderCallback);
+ }
+
+ public abstract static class EmojiCompat.MetadataRepoLoaderCallback {
+ ctor public EmojiCompat.MetadataRepoLoaderCallback();
+ method public abstract void onFailed(Throwable?);
+ method public abstract void onLoaded(androidx.emoji2.text.MetadataRepo);
+ }
+
+ public static interface EmojiCompat.SpanFactory {
+ method @RequiresApi(19) public androidx.emoji2.text.EmojiSpan createSpan(androidx.emoji2.text.TypefaceEmojiRasterizer);
+ }
+
+ public class EmojiCompatInitializer implements androidx.startup.Initializer<java.lang.Boolean> {
+ ctor public EmojiCompatInitializer();
+ method public Boolean create(android.content.Context);
+ method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>!> dependencies();
+ }
+
+ @RequiresApi(19) public abstract class EmojiSpan extends android.text.style.ReplacementSpan {
+ method public int getSize(android.graphics.Paint, CharSequence!, int, int, android.graphics.Paint.FontMetricsInt?);
+ method public final androidx.emoji2.text.TypefaceEmojiRasterizer getTypefaceRasterizer();
+ }
+
+ public class FontRequestEmojiCompatConfig extends androidx.emoji2.text.EmojiCompat.Config {
+ ctor public FontRequestEmojiCompatConfig(android.content.Context, androidx.core.provider.FontRequest);
+ method @Deprecated public androidx.emoji2.text.FontRequestEmojiCompatConfig setHandler(android.os.Handler?);
+ method public androidx.emoji2.text.FontRequestEmojiCompatConfig setLoadingExecutor(java.util.concurrent.Executor);
+ method public androidx.emoji2.text.FontRequestEmojiCompatConfig setRetryPolicy(androidx.emoji2.text.FontRequestEmojiCompatConfig.RetryPolicy?);
+ }
+
+ public static class FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy extends androidx.emoji2.text.FontRequestEmojiCompatConfig.RetryPolicy {
+ ctor public FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy(long);
+ method public long getRetryDelay();
+ }
+
+ public abstract static class FontRequestEmojiCompatConfig.RetryPolicy {
+ ctor public FontRequestEmojiCompatConfig.RetryPolicy();
+ method public abstract long getRetryDelay();
+ }
+
+ @AnyThread @RequiresApi(19) public final class MetadataRepo {
+ method public static androidx.emoji2.text.MetadataRepo create(android.content.res.AssetManager, String) throws java.io.IOException;
+ method public static androidx.emoji2.text.MetadataRepo create(android.graphics.Typeface, java.io.InputStream) throws java.io.IOException;
+ method public static androidx.emoji2.text.MetadataRepo create(android.graphics.Typeface, java.nio.ByteBuffer) throws java.io.IOException;
+ }
+
+ @AnyThread @RequiresApi(19) public class TypefaceEmojiRasterizer {
+ method public void draw(android.graphics.Canvas, float, float, android.graphics.Paint);
+ method public int getCodepointAt(int);
+ method public int getCodepointsLength();
+ method public int getHeight();
+ method public android.graphics.Typeface getTypeface();
+ method public int getWidth();
+ method public boolean isDefaultEmoji();
+ method public boolean isPreferredSystemRender();
+ }
+
+}
+
diff --git a/emoji2/emoji2/api/res-1.4.0-beta05.txt b/emoji2/emoji2/api/res-1.4.0-beta05.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/emoji2/emoji2/api/res-1.4.0-beta05.txt
diff --git a/emoji2/emoji2/api/restricted_1.4.0-beta05.txt b/emoji2/emoji2/api/restricted_1.4.0-beta05.txt
new file mode 100644
index 0000000..42809f9
--- /dev/null
+++ b/emoji2/emoji2/api/restricted_1.4.0-beta05.txt
@@ -0,0 +1,131 @@
+// Signature format: 4.0
+package androidx.emoji2.text {
+
+ public final class DefaultEmojiCompatConfig {
+ method public static androidx.emoji2.text.FontRequestEmojiCompatConfig? create(android.content.Context);
+ }
+
+ @AnyThread public class EmojiCompat {
+ method public static androidx.emoji2.text.EmojiCompat get();
+ method public String getAssetSignature();
+ method public int getEmojiEnd(CharSequence, @IntRange(from=0) int);
+ method public int getEmojiMatch(CharSequence, @IntRange(from=0) int);
+ method public int getEmojiStart(CharSequence, @IntRange(from=0) int);
+ method public int getLoadState();
+ method public static boolean handleDeleteSurroundingText(android.view.inputmethod.InputConnection, android.text.Editable, @IntRange(from=0) int, @IntRange(from=0) int, boolean);
+ method public static boolean handleOnKeyDown(android.text.Editable, int, android.view.KeyEvent);
+ method @Deprecated public boolean hasEmojiGlyph(CharSequence);
+ method @Deprecated public boolean hasEmojiGlyph(CharSequence, @IntRange(from=0) int);
+ method public static androidx.emoji2.text.EmojiCompat? init(android.content.Context);
+ method public static androidx.emoji2.text.EmojiCompat init(androidx.emoji2.text.EmojiCompat.Config);
+ method public static boolean isConfigured();
+ method public void load();
+ method @CheckResult public CharSequence? process(CharSequence?);
+ method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int);
+ method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+ method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, int);
+ method public void registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+ method public void unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+ method public void updateEditorInfo(android.view.inputmethod.EditorInfo);
+ field public static final String EDITOR_INFO_METAVERSION_KEY = "android.support.text.emoji.emojiCompat_metadataVersion";
+ field public static final String EDITOR_INFO_REPLACE_ALL_KEY = "android.support.text.emoji.emojiCompat_replaceAll";
+ field public static final int EMOJI_FALLBACK = 2; // 0x2
+ field public static final int EMOJI_SUPPORTED = 1; // 0x1
+ field public static final int EMOJI_UNSUPPORTED = 0; // 0x0
+ field public static final int LOAD_STATE_DEFAULT = 3; // 0x3
+ field public static final int LOAD_STATE_FAILED = 2; // 0x2
+ field public static final int LOAD_STATE_LOADING = 0; // 0x0
+ field public static final int LOAD_STATE_SUCCEEDED = 1; // 0x1
+ field public static final int LOAD_STRATEGY_DEFAULT = 0; // 0x0
+ field public static final int LOAD_STRATEGY_MANUAL = 1; // 0x1
+ field public static final int REPLACE_STRATEGY_ALL = 1; // 0x1
+ field public static final int REPLACE_STRATEGY_DEFAULT = 0; // 0x0
+ field public static final int REPLACE_STRATEGY_NON_EXISTENT = 2; // 0x2
+ }
+
+ public abstract static class EmojiCompat.Config {
+ ctor protected EmojiCompat.Config(androidx.emoji2.text.EmojiCompat.MetadataRepoLoader);
+ method protected final androidx.emoji2.text.EmojiCompat.MetadataRepoLoader getMetadataRepoLoader();
+ method public androidx.emoji2.text.EmojiCompat.Config registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+ method public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorColor(@ColorInt int);
+ method public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorEnabled(boolean);
+ method public androidx.emoji2.text.EmojiCompat.Config setGlyphChecker(androidx.emoji2.text.EmojiCompat.GlyphChecker);
+ method public androidx.emoji2.text.EmojiCompat.Config setMetadataLoadStrategy(int);
+ method public androidx.emoji2.text.EmojiCompat.Config setReplaceAll(boolean);
+ method public androidx.emoji2.text.EmojiCompat.Config setSpanFactory(androidx.emoji2.text.EmojiCompat.SpanFactory);
+ method public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean);
+ method public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean, java.util.List<java.lang.Integer!>?);
+ method public androidx.emoji2.text.EmojiCompat.Config unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+ }
+
+ public static interface EmojiCompat.GlyphChecker {
+ method public boolean hasGlyph(CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+ }
+
+ public abstract static class EmojiCompat.InitCallback {
+ ctor public EmojiCompat.InitCallback();
+ method public void onFailed(Throwable?);
+ method public void onInitialized();
+ }
+
+ public static interface EmojiCompat.MetadataRepoLoader {
+ method public void load(androidx.emoji2.text.EmojiCompat.MetadataRepoLoaderCallback);
+ }
+
+ public abstract static class EmojiCompat.MetadataRepoLoaderCallback {
+ ctor public EmojiCompat.MetadataRepoLoaderCallback();
+ method public abstract void onFailed(Throwable?);
+ method public abstract void onLoaded(androidx.emoji2.text.MetadataRepo);
+ }
+
+ public static interface EmojiCompat.SpanFactory {
+ method @RequiresApi(19) public androidx.emoji2.text.EmojiSpan createSpan(androidx.emoji2.text.TypefaceEmojiRasterizer);
+ }
+
+ public class EmojiCompatInitializer implements androidx.startup.Initializer<java.lang.Boolean> {
+ ctor public EmojiCompatInitializer();
+ method public Boolean create(android.content.Context);
+ method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>!> dependencies();
+ }
+
+ @RequiresApi(19) public abstract class EmojiSpan extends android.text.style.ReplacementSpan {
+ method public int getSize(android.graphics.Paint, CharSequence!, int, int, android.graphics.Paint.FontMetricsInt?);
+ method public final androidx.emoji2.text.TypefaceEmojiRasterizer getTypefaceRasterizer();
+ }
+
+ public class FontRequestEmojiCompatConfig extends androidx.emoji2.text.EmojiCompat.Config {
+ ctor public FontRequestEmojiCompatConfig(android.content.Context, androidx.core.provider.FontRequest);
+ method @Deprecated public androidx.emoji2.text.FontRequestEmojiCompatConfig setHandler(android.os.Handler?);
+ method public androidx.emoji2.text.FontRequestEmojiCompatConfig setLoadingExecutor(java.util.concurrent.Executor);
+ method public androidx.emoji2.text.FontRequestEmojiCompatConfig setRetryPolicy(androidx.emoji2.text.FontRequestEmojiCompatConfig.RetryPolicy?);
+ }
+
+ public static class FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy extends androidx.emoji2.text.FontRequestEmojiCompatConfig.RetryPolicy {
+ ctor public FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy(long);
+ method public long getRetryDelay();
+ }
+
+ public abstract static class FontRequestEmojiCompatConfig.RetryPolicy {
+ ctor public FontRequestEmojiCompatConfig.RetryPolicy();
+ method public abstract long getRetryDelay();
+ }
+
+ @AnyThread @RequiresApi(19) public final class MetadataRepo {
+ method public static androidx.emoji2.text.MetadataRepo create(android.content.res.AssetManager, String) throws java.io.IOException;
+ method public static androidx.emoji2.text.MetadataRepo create(android.graphics.Typeface, java.io.InputStream) throws java.io.IOException;
+ method public static androidx.emoji2.text.MetadataRepo create(android.graphics.Typeface, java.nio.ByteBuffer) throws java.io.IOException;
+ }
+
+ @AnyThread @RequiresApi(19) public class TypefaceEmojiRasterizer {
+ method public void draw(android.graphics.Canvas, float, float, android.graphics.Paint);
+ method public int getCodepointAt(int);
+ method public int getCodepointsLength();
+ method public int getHeight();
+ method public android.graphics.Typeface getTypeface();
+ method public int getWidth();
+ method public boolean isDefaultEmoji();
+ method public boolean isPreferredSystemRender();
+ }
+
+}
+
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/EmojiSpanTest.java b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/EmojiSpanTest.java
index 1d0ca88..23a48cc 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/EmojiSpanTest.java
+++ b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/EmojiSpanTest.java
@@ -16,6 +16,7 @@
package androidx.emoji2.text;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -33,7 +34,9 @@
import android.text.SpannableString;
import android.text.TextPaint;
import android.text.style.BackgroundColorSpan;
+import android.text.style.MetricAffectingSpan;
+import androidx.annotation.NonNull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.filters.SdkSuppress;
@@ -175,4 +178,49 @@
eq((float) bottom), any(Paint.class));
}
+
+ @Test
+ public void testMetrcisSpan_notInvoked_byBackgroundCode() {
+ // control the size of the emoji span
+ final TypefaceEmojiRasterizer metadata = mock(TypefaceEmojiRasterizer.class);
+ when(metadata.getWidth()).thenReturn(10);
+ when(metadata.getHeight()).thenReturn(10);
+
+ final EmojiSpan span = new TypefaceEmojiSpan(metadata);
+ TextPaint textPaint = new TextPaint();
+ final Spannable spannable = new SpannableString("Hello");
+ MyMetricSpan subject = new MyMetricSpan();
+ spannable.setSpan(subject, 0, 1,
+ Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+ // prepare parameters for draw() call
+ final Canvas canvas = mock(Canvas.class);
+ final float x = 10;
+ final int top = 15;
+ final int y = 20;
+ final int bottom = 30;
+
+ // verify the case where background draw happens (position 0)
+ EmojiCompat.reset(NoFontTestEmojiConfig.emptyConfig().setEmojiSpanIndicatorEnabled(false));
+ TextPaint paint = new TextPaint();
+ span.draw(canvas, spannable, 0 /*start*/, 1 /*end*/, x, top, y, bottom, paint);
+
+ assertFalse(subject.mDidUpdateDrawState);
+ assertFalse(subject.mDidUpdateMeasureState);
+ }
+
+ class MyMetricSpan extends MetricAffectingSpan {
+ boolean mDidUpdateMeasureState = false;
+ boolean mDidUpdateDrawState = false;
+
+ @Override
+ public void updateMeasureState(@NonNull TextPaint textPaint) {
+ mDidUpdateMeasureState = true;
+ }
+
+ @Override
+ public void updateDrawState(TextPaint textPaint) {
+ mDidUpdateDrawState = true;
+ }
+ }
+
}
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java
index 1a6e3b5..7595fd5 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java
@@ -21,6 +21,7 @@
import android.text.Spanned;
import android.text.TextPaint;
import android.text.style.CharacterStyle;
+import android.text.style.MetricAffectingSpan;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
@@ -121,7 +122,10 @@
wp.set(paint);
//noinspection ForLoopReplaceableByForEach
for (int pos = 0; pos < spans.length; pos++) {
- spans[pos].updateDrawState(wp);
+ if (!(spans[pos] instanceof MetricAffectingSpan)) {
+ // we're in draw, so at this point we can't do anything to metrics don't try
+ spans[pos].updateDrawState(wp);
+ }
}
return wp;
} else {
diff --git a/fragment/CHANGELOG.md b/fragment/CHANGELOG.md
index 0ea055d..b14a2c3 100644
--- a/fragment/CHANGELOG.md
+++ b/fragment/CHANGELOG.md
@@ -16,7 +16,13 @@
# Unreleased
+### Bug Fixes
+- Fixed an issue where the saved state stored when the activity was stopped but not destroyed
+ would be incorrectly cached even after the fragment instance was moved back to the RESUMED state.
+ This would cause that cached state to be reused if that fragment instance was on the back stack
+ when using the multiple back stacks API to save and restore that fragment.
+
### Dependency Updates
-* Changed dependency of Activity library from version 1.5.1 to version 1.7.1.
+- Changed dependency of Activity library from version 1.5.1 to version 1.7.1.
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt
index d9480fe..88950b5 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt
@@ -22,6 +22,7 @@
import android.animation.ValueAnimator
import android.content.res.Resources
import android.os.Build
+import android.view.Choreographer
import android.view.View
import androidx.annotation.AnimatorRes
import androidx.annotation.LayoutRes
@@ -143,6 +144,7 @@
// Ensure that showing and popping a Fragment uses the enter and popExit animators
// This tests reordered transactions
+ @RequiresApi(16)
@Test
fun showAnimatorsReordered() {
val fm = activityRule.activity.supportFragmentManager
@@ -169,6 +171,16 @@
assertEnterPopExit(fragment)
+ val layoutCountDownLatch = CountDownLatch(1)
+
+ activityRule.runOnUiThread {
+ Choreographer.getInstance().postFrameCallback {
+ layoutCountDownLatch.countDown()
+ }
+ }
+
+ assertThat(layoutCountDownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+
activityRule.runOnUiThread {
assertThat(fragment.requireView().visibility).isEqualTo(View.GONE)
}
@@ -176,6 +188,7 @@
// Ensure that showing and popping a Fragment uses the enter and popExit animators
// This tests ordered transactions
+ @RequiresApi(16)
@Test
fun showAnimatorsOrdered() {
val fm = activityRule.activity.supportFragmentManager
@@ -206,6 +219,15 @@
}
assertEnterPopExit(fragment)
+ val postFrameCountDownLatch = CountDownLatch(1)
+
+ activityRule.runOnUiThread {
+ Choreographer.getInstance().postFrameCallback {
+ postFrameCountDownLatch.countDown()
+ }
+ }
+
+ assertThat(postFrameCountDownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
activityRule.runOnUiThread {
assertThat(fragment.requireView().visibility).isEqualTo(View.GONE)
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt
index 413ec73..5781007 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt
@@ -764,4 +764,55 @@
assertThat(fm.backStackEntryCount).isEqualTo(0)
}
}
+
+ @Test
+ fun resumeClearsFragmentStoreSavedState() {
+ withUse(ActivityScenario.launch(FragmentTestActivity::class.java)) {
+ val fm = withActivity {
+ supportFragmentManager
+ }
+ val fragmentBase = StrictViewFragment()
+ val fragmentReplacement = StateSaveFragment()
+ val fragmentReplacementChild = StateSaveFragment()
+
+ fm.beginTransaction()
+ .add(R.id.content, fragmentBase)
+ .commit()
+ executePendingTransactions()
+
+ fm.beginTransaction()
+ .setReorderingAllowed(true)
+ .replace(R.id.content, fragmentReplacement)
+ .addToBackStack("replacement")
+ .commit()
+ executePendingTransactions()
+
+ fragmentReplacement.childFragmentManager.beginTransaction()
+ .add(fragmentReplacementChild, "replacementChild")
+ .commit()
+ executePendingTransactions(fragmentReplacement.childFragmentManager)
+
+ // stop activity and save fragments
+ moveToState(Lifecycle.State.CREATED)
+ executePendingTransactions()
+
+ // states should be stored in fragmentStore
+ assertThat(fm.fragmentStore.getSavedState(fragmentReplacement.mWho))
+ .isNotNull()
+ assertThat(fragmentReplacement.childFragmentManager.fragmentStore
+ .getSavedState(fragmentReplacementChild.mWho)
+ ).isNotNull()
+
+ // resume activity and restore fragments
+ moveToState(Lifecycle.State.RESUMED)
+ executePendingTransactions()
+
+ // states should be cleared from fragmentStore
+ assertThat(fm.fragmentStore.getSavedState(fragmentReplacement.mWho))
+ .isNull()
+ assertThat(fragmentReplacement.childFragmentManager.fragmentStore
+ .getSavedState(fragmentReplacementChild.mWho)
+ ).isNull()
+ }
+ }
}
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentAnim.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentAnim.java
index 6d79fe1..21f3854 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentAnim.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentAnim.java
@@ -18,6 +18,7 @@
import android.animation.Animator;
import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
@@ -180,7 +181,7 @@
*/
static class AnimationOrAnimator {
public final Animation animation;
- public final Animator animator;
+ public final AnimatorSet animator;
AnimationOrAnimator(Animation animation) {
this.animation = animation;
@@ -192,7 +193,8 @@
AnimationOrAnimator(Animator animator) {
this.animation = null;
- this.animator = animator;
+ this.animator = new AnimatorSet();
+ this.animator.play(animator);
if (animator == null) {
throw new IllegalStateException("Animator cannot be null");
}
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
index e68aac2..68154fb 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
@@ -18,6 +18,7 @@
import android.app.Activity;
import android.content.res.Resources;
+import android.os.BadParcelableException;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
@@ -431,8 +432,14 @@
new Bundle());
}
- mFragment.mSavedViewState = mFragment.mSavedFragmentState.getSparseParcelableArray(
- VIEW_STATE_KEY);
+ try {
+ mFragment.mSavedViewState = mFragment.mSavedFragmentState.getSparseParcelableArray(
+ VIEW_STATE_KEY);
+ } catch (BadParcelableException e) {
+ throw new IllegalStateException(
+ "Failed to restore view hierarchy state for fragment " + getFragment(), e
+ );
+ }
mFragment.mSavedViewRegistryState = mFragment.mSavedFragmentState.getBundle(
VIEW_REGISTRY_STATE_KEY);
@@ -645,6 +652,7 @@
mFragment.setFocusedView(null);
mFragment.performResume();
mDispatcher.dispatchOnFragmentResumed(mFragment, false);
+ mFragmentStore.setSavedState(mFragment.mWho, null);
mFragment.mSavedFragmentState = null;
mFragment.mSavedViewState = null;
mFragment.mSavedViewRegistryState = null;
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.kt b/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.kt
index ec638b2..75b52ea 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.kt
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.kt
@@ -485,6 +485,9 @@
var isComplete = false
private set
+ var isStarted = false
+ private set
+
init {
// Connect the CancellationSignal to our own
cancellationSignal.setOnCancelListener { cancel() }
@@ -499,6 +502,7 @@
}
fun cancel() {
+ isStarted = false
if (isCanceled) {
return
}
@@ -563,7 +567,10 @@
/**
* Callback for when the operation is about to start.
*/
- open fun onStart() {}
+ @CallSuper
+ open fun onStart() {
+ isStarted = true
+ }
/**
* Add new [CancellationSignal] for special effects.
@@ -594,6 +601,7 @@
*/
@CallSuper
open fun complete() {
+ isStarted = false
if (isComplete) {
return
}
@@ -620,6 +628,10 @@
cancellationSignal
) {
override fun onStart() {
+ if (isStarted) {
+ return
+ }
+ super.onStart()
if (lifecycleImpact == LifecycleImpact.ADDING) {
val fragment = fragmentStateManager.fragment
val focusedView = fragment.mView.findFocus()
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_1.jpeg b/fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_1.jpeg
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_1.jpeg
rename to fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_1.jpeg
Binary files differ
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_2.jpeg b/fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_2.jpeg
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_2.jpeg
rename to fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_2.jpeg
Binary files differ
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_3.jpeg b/fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_3.jpeg
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_3.jpeg
rename to fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_3.jpeg
Binary files differ
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_4.jpeg b/fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_4.jpeg
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_4.jpeg
rename to fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_4.jpeg
Binary files differ
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_5.jpeg b/fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_5.jpeg
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_5.jpeg
rename to fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_5.jpeg
Binary files differ
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_6.jpeg b/fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_6.jpeg
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/drawable-hdpi/placekitten_6.jpeg
rename to fragment/integration-tests/testapp/src/main/res/drawable-hdpi/placekitten_6.jpeg
Binary files differ
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/basicAnimators/layout/basic_animator_fragment.xml b/fragment/integration-tests/testapp/src/main/res/layout/basic_animator_fragment.xml
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/basicAnimators/layout/basic_animator_fragment.xml
rename to fragment/integration-tests/testapp/src/main/res/layout/basic_animator_fragment.xml
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/basicAnimators/layout/basic_animators_main.xml b/fragment/integration-tests/testapp/src/main/res/layout/basic_animators_main.xml
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/basicAnimators/layout/basic_animators_main.xml
rename to fragment/integration-tests/testapp/src/main/res/layout/basic_animators_main.xml
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/doubleTransitionBug/layout/double_transition_bug_activity_main.xml b/fragment/integration-tests/testapp/src/main/res/layout/double_transition_bug_activity_main.xml
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/doubleTransitionBug/layout/double_transition_bug_activity_main.xml
rename to fragment/integration-tests/testapp/src/main/res/layout/double_transition_bug_activity_main.xml
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/doubleTransitionBug/layout/double_transition_bug_fragment_first.xml b/fragment/integration-tests/testapp/src/main/res/layout/double_transition_bug_fragment_first.xml
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/doubleTransitionBug/layout/double_transition_bug_fragment_first.xml
rename to fragment/integration-tests/testapp/src/main/res/layout/double_transition_bug_fragment_first.xml
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/doubleTransitionBug/layout/double_transition_bug_fragment_second.xml b/fragment/integration-tests/testapp/src/main/res/layout/double_transition_bug_fragment_second.xml
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/doubleTransitionBug/layout/double_transition_bug_fragment_second.xml
rename to fragment/integration-tests/testapp/src/main/res/layout/double_transition_bug_fragment_second.xml
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/layout/kitten_activity_main.xml b/fragment/integration-tests/testapp/src/main/res/layout/kitten_activity_main.xml
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/layout/kitten_activity_main.xml
rename to fragment/integration-tests/testapp/src/main/res/layout/kitten_activity_main.xml
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/layout/kitten_details_fragment.xml b/fragment/integration-tests/testapp/src/main/res/layout/kitten_details_fragment.xml
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/layout/kitten_details_fragment.xml
rename to fragment/integration-tests/testapp/src/main/res/layout/kitten_details_fragment.xml
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/layout/kitten_fragment_grid.xml b/fragment/integration-tests/testapp/src/main/res/layout/kitten_fragment_grid.xml
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/layout/kitten_fragment_grid.xml
rename to fragment/integration-tests/testapp/src/main/res/layout/kitten_fragment_grid.xml
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/layout/kitten_grid_item.xml b/fragment/integration-tests/testapp/src/main/res/layout/kitten_grid_item.xml
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/layout/kitten_grid_item.xml
rename to fragment/integration-tests/testapp/src/main/res/layout/kitten_grid_item.xml
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/values/donottranslate-strings.xml b/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/values/donottranslate-strings.xml
deleted file mode 100644
index 4c9d564..0000000
--- a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/values/donottranslate-strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<!--
- Copyright 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<resources>
- <string name="details_title_text">Cupcake ipsum dolor</string>
- <string name="details_body_text">Sit amet chocolate cake sweet macaroon chupa chups. Bear claw carrot cake chocolate bar biscuit chocolate cookie. Chocolate sesame snaps candy canes bear claw dragée tootsie roll.</string>
-</resources>
diff --git a/fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/values/dimens.xml b/fragment/integration-tests/testapp/src/main/res/values/dimens.xml
similarity index 100%
rename from fragment/integration-tests/testapp/src/main/res/layouts/kittenFragmentTransitions/values/dimens.xml
rename to fragment/integration-tests/testapp/src/main/res/values/dimens.xml
diff --git a/fragment/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml b/fragment/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
index 36c3cea..305ca04 100644
--- a/fragment/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
+++ b/fragment/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
@@ -16,4 +16,6 @@
-->
<resources>
<string name="app_name">Fragment Effects Tests</string>
+ <string name="details_title_text">Cupcake ipsum dolor</string>
+ <string name="details_body_text">Sit amet chocolate cake sweet macaroon chupa chups. Bear claw carrot cake chocolate bar biscuit chocolate cookie. Chocolate sesame snaps candy canes bear claw dragée tootsie roll.</string>
</resources>
diff --git a/glance/glance-appwidget/api/1.0.0-beta02.txt b/glance/glance-appwidget/api/1.0.0-beta02.txt
index d197a7a..acafa55 100644
--- a/glance/glance-appwidget/api/1.0.0-beta02.txt
+++ b/glance/glance-appwidget/api/1.0.0-beta02.txt
@@ -186,6 +186,7 @@
public final class StartActivityIntentActionKt {
method public static androidx.glance.action.Action actionStartActivity(android.content.Intent intent, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static androidx.glance.action.Action actionStartActivity(android.content.Intent intent, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
}
public final class StartServiceActionKt {
@@ -223,6 +224,7 @@
}
public final class LazyListKt {
+ method @androidx.compose.runtime.Composable @androidx.glance.ExperimentalGlanceApi public static void LazyColumn(android.os.Bundle activityOptions, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyListScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void LazyColumn(optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyListScope,kotlin.Unit> content);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyListScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
@@ -245,6 +247,7 @@
}
public final class LazyVerticalGridKt {
+ method @androidx.compose.runtime.Composable @androidx.glance.ExperimentalGlanceApi public static void LazyVerticalGrid(androidx.glance.appwidget.lazy.GridCells gridCells, android.os.Bundle activityOptions, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyVerticalGridScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void LazyVerticalGrid(androidx.glance.appwidget.lazy.GridCells gridCells, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyVerticalGridScope,kotlin.Unit> content);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyVerticalGridScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyVerticalGridScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
diff --git a/glance/glance-appwidget/api/current.txt b/glance/glance-appwidget/api/current.txt
index d197a7a..acafa55 100644
--- a/glance/glance-appwidget/api/current.txt
+++ b/glance/glance-appwidget/api/current.txt
@@ -186,6 +186,7 @@
public final class StartActivityIntentActionKt {
method public static androidx.glance.action.Action actionStartActivity(android.content.Intent intent, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static androidx.glance.action.Action actionStartActivity(android.content.Intent intent, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
}
public final class StartServiceActionKt {
@@ -223,6 +224,7 @@
}
public final class LazyListKt {
+ method @androidx.compose.runtime.Composable @androidx.glance.ExperimentalGlanceApi public static void LazyColumn(android.os.Bundle activityOptions, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyListScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void LazyColumn(optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyListScope,kotlin.Unit> content);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyListScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
@@ -245,6 +247,7 @@
}
public final class LazyVerticalGridKt {
+ method @androidx.compose.runtime.Composable @androidx.glance.ExperimentalGlanceApi public static void LazyVerticalGrid(androidx.glance.appwidget.lazy.GridCells gridCells, android.os.Bundle activityOptions, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyVerticalGridScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void LazyVerticalGrid(androidx.glance.appwidget.lazy.GridCells gridCells, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyVerticalGridScope,kotlin.Unit> content);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyVerticalGridScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyVerticalGridScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
diff --git a/glance/glance-appwidget/api/restricted_1.0.0-beta02.txt b/glance/glance-appwidget/api/restricted_1.0.0-beta02.txt
index d197a7a..acafa55 100644
--- a/glance/glance-appwidget/api/restricted_1.0.0-beta02.txt
+++ b/glance/glance-appwidget/api/restricted_1.0.0-beta02.txt
@@ -186,6 +186,7 @@
public final class StartActivityIntentActionKt {
method public static androidx.glance.action.Action actionStartActivity(android.content.Intent intent, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static androidx.glance.action.Action actionStartActivity(android.content.Intent intent, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
}
public final class StartServiceActionKt {
@@ -223,6 +224,7 @@
}
public final class LazyListKt {
+ method @androidx.compose.runtime.Composable @androidx.glance.ExperimentalGlanceApi public static void LazyColumn(android.os.Bundle activityOptions, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyListScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void LazyColumn(optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyListScope,kotlin.Unit> content);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyListScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
@@ -245,6 +247,7 @@
}
public final class LazyVerticalGridKt {
+ method @androidx.compose.runtime.Composable @androidx.glance.ExperimentalGlanceApi public static void LazyVerticalGrid(androidx.glance.appwidget.lazy.GridCells gridCells, android.os.Bundle activityOptions, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyVerticalGridScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void LazyVerticalGrid(androidx.glance.appwidget.lazy.GridCells gridCells, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyVerticalGridScope,kotlin.Unit> content);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyVerticalGridScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyVerticalGridScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
diff --git a/glance/glance-appwidget/api/restricted_current.txt b/glance/glance-appwidget/api/restricted_current.txt
index d197a7a..acafa55 100644
--- a/glance/glance-appwidget/api/restricted_current.txt
+++ b/glance/glance-appwidget/api/restricted_current.txt
@@ -186,6 +186,7 @@
public final class StartActivityIntentActionKt {
method public static androidx.glance.action.Action actionStartActivity(android.content.Intent intent, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static androidx.glance.action.Action actionStartActivity(android.content.Intent intent, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
}
public final class StartServiceActionKt {
@@ -223,6 +224,7 @@
}
public final class LazyListKt {
+ method @androidx.compose.runtime.Composable @androidx.glance.ExperimentalGlanceApi public static void LazyColumn(android.os.Bundle activityOptions, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyListScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void LazyColumn(optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyListScope,kotlin.Unit> content);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyListScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
@@ -245,6 +247,7 @@
}
public final class LazyVerticalGridKt {
+ method @androidx.compose.runtime.Composable @androidx.glance.ExperimentalGlanceApi public static void LazyVerticalGrid(androidx.glance.appwidget.lazy.GridCells gridCells, android.os.Bundle activityOptions, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyVerticalGridScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void LazyVerticalGrid(androidx.glance.appwidget.lazy.GridCells gridCells, optional androidx.glance.GlanceModifier modifier, optional int horizontalAlignment, kotlin.jvm.functions.Function1<? super androidx.glance.appwidget.lazy.LazyVerticalGridScope,kotlin.Unit> content);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyVerticalGridScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
method public static inline <T> void items(androidx.glance.appwidget.lazy.LazyVerticalGridScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,java.lang.Long> itemId, kotlin.jvm.functions.Function2<? super androidx.glance.appwidget.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
index 0e11321..9107a59 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
@@ -139,6 +139,19 @@
</receiver>
<receiver
+ android:name="androidx.glance.appwidget.demos.TypographyDemoAppWidgetReceiver"
+ android:label="@string/typography_widget_name"
+ android:enabled="@bool/glance_appwidget_available"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+ <meta-data
+ android:name="android.appwidget.provider"
+ android:resource="@xml/default_app_widget_info" />
+ </receiver>
+
+ <receiver
android:name="androidx.glance.appwidget.demos.ScrollableAppWidgetReceiver"
android:label="@string/scrollable_widget_name"
android:enabled="@bool/glance_appwidget_available"
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ScrollableAppWidget.kt b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ScrollableAppWidget.kt
index dcb80bb..74acc8e 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ScrollableAppWidget.kt
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ScrollableAppWidget.kt
@@ -35,6 +35,8 @@
import androidx.glance.Button
import androidx.glance.GlanceId
import androidx.glance.GlanceModifier
+import androidx.glance.Image
+import androidx.glance.ImageProvider
import androidx.glance.LocalContext
import androidx.glance.LocalSize
import androidx.glance.action.clickable
@@ -51,10 +53,15 @@
import androidx.glance.layout.Alignment
import androidx.glance.layout.Column
import androidx.glance.layout.Row
+import androidx.glance.layout.Spacer
import androidx.glance.layout.fillMaxHeight
import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.padding
+import androidx.glance.layout.size
+import androidx.glance.layout.width
+import androidx.glance.semantics.contentDescription
+import androidx.glance.semantics.semantics
import androidx.glance.text.FontWeight
import androidx.glance.text.Text
import androidx.glance.text.TextAlign
@@ -67,6 +74,8 @@
class ScrollableAppWidget : GlanceAppWidget() {
companion object {
+ private const val TAG = "ScrollableAppWidget"
+
private val singleColumn = DpSize(100.dp, 48.dp)
private val doubleColumn = DpSize(200.dp, 48.dp)
private val tripleColumn = DpSize(300.dp, 48.dp)
@@ -100,119 +109,164 @@
ScrollColumn(modifier)
ScrollColumn(modifier)
}
+
else -> SampleGrid(cells = GridCells.Fixed(3))
}
}
}
-}
-@Composable
-private fun ScrollColumn(modifier: GlanceModifier) {
- val localSize = LocalSize.current
- LazyColumn(modifier) {
- item {
- SectionHeading(
- title = "LocalSize",
- description = "inside lazyColumn"
- )
- }
- item {
- Text(
- text = "${localSize.width}x${localSize.height}",
- modifier = GlanceModifier.padding(10.dp)
- )
- }
- item {
- SectionHeading(
- title = "Activities",
- description = "Click the buttons to open activities"
- )
- }
+ @Composable
+ private fun ScrollColumn(modifier: GlanceModifier) {
+ val localSize = LocalSize.current
+ LazyColumn(modifier) {
+ item {
+ SectionHeading(
+ title = "LocalSize",
+ description = "inside lazyColumn"
+ )
+ }
+ item {
+ Text(
+ text = "${localSize.width}x${localSize.height}",
+ modifier = GlanceModifier.padding(10.dp)
+ )
+ }
+ item {
+ SectionHeading(
+ title = "Activities",
+ description = "Click the buttons to open activities"
+ )
+ }
- itemsIndexed(
- listOf(
- GlanceAppWidgetDemoActivity::class.java,
- ListClickDestinationActivity::class.java
- )
- ) { index, activityClass ->
- Row(
- GlanceModifier.fillMaxWidth(),
- horizontalAlignment = Alignment.Horizontal.CenterHorizontally
- ) {
- Button(
- text = "Activity ${index + 1}",
- onClick = actionStartActivity(
- Intent(
- LocalContext.current,
- activityClass
- ).apply {
- // Move this activity to the top of the stack, so it's obvious in this
- // demo that the button has launched this activity. Otherwise, if
- // another activity was opened on top, the target activity might be
- // buried in the stack.
- flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
- }
+ itemsIndexed(
+ listOf(
+ GlanceAppWidgetDemoActivity::class.java,
+ ListClickDestinationActivity::class.java
+ )
+ ) { index, activityClass ->
+ Row(
+ GlanceModifier.fillMaxWidth(),
+ horizontalAlignment = Alignment.Horizontal.CenterHorizontally
+ ) {
+ Button(
+ text = "Activity ${index + 1}",
+ onClick = actionStartActivity(
+ Intent(
+ LocalContext.current,
+ activityClass
+ ).apply {
+ // Move this activity to the top of the stack, so it's obvious in this
+ // demo that the button has launched this activity. Otherwise, if
+ // another activity was opened on top, the target activity might be
+ // buried in the stack.
+ flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
+ }
+ )
)
+ }
+ }
+
+ item {
+ SectionHeading(
+ title = "Callbacks",
+ description = "Click the list items to invoke a callback"
+ )
+ }
+
+ items(10) { index: Int ->
+ Text(
+ text = "Item $index",
+ modifier = GlanceModifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp, vertical = 8.dp)
+ .clickable {
+ Log.i(TAG, "Click from list item $index")
+ }
+ )
+ }
+ item {
+ // A11y services read out the contents as description of the row and call out
+ // "double tap to activate" as it is clickable.
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = GlanceModifier
+ .padding(horizontal = 16.dp, vertical = 8.dp)
+ .clickable { Log.i(TAG, "Click from an item row") },
+ ) {
+ Image(
+ provider = ImageProvider(R.drawable.compose),
+ contentDescription = "Compose logo",
+ modifier = GlanceModifier.size(20.dp)
+ )
+ Spacer(modifier = GlanceModifier.width(5.dp))
+ Text(
+ text = "Item with click on parent row",
+ modifier = GlanceModifier
+ .fillMaxWidth()
+ )
+ }
+ }
+ item {
+ // A11y services read out the semantics description of the row and call out
+ // "double tap to activate" as it is clickable.
+ Row(modifier = GlanceModifier
+ .padding(horizontal = 16.dp, vertical = 8.dp)
+ .clickable {
+ Log.i(TAG, "Click from an item row with semantics set")
+ }
+ .semantics { contentDescription = "A row with semantics description set" }
+ ) {
+ Image(
+ provider = ImageProvider(R.drawable.compose),
+ contentDescription = "Compose logo",
+ modifier = GlanceModifier.size(20.dp)
+ )
+ Spacer(modifier = GlanceModifier.width(5.dp))
+ Text(
+ text = "Item with click on parent row with contentDescription set",
+ modifier = GlanceModifier
+ .fillMaxWidth()
+ )
+ }
+ }
+ item {
+ SectionHeading(
+ title = "Compound buttons",
+ description = "Check buttons below"
+ )
+ }
+ item {
+ var checked by remember { mutableStateOf(false) }
+ CheckBox(
+ checked = checked,
+ onCheckedChange = { checked = !checked },
+ text = "Checkbox"
)
}
}
+ }
- item {
- SectionHeading(
- title = "Callbacks",
- description = "Click the list items to invoke a callback"
- )
- }
-
- items(10) { index: Int ->
+ @Composable
+ private fun SectionHeading(title: String, description: String) {
+ Column {
Text(
- text = "Item $index",
- modifier = GlanceModifier
- .fillMaxWidth()
- .padding(horizontal = 16.dp, vertical = 8.dp)
- .clickable {
- Log.i("ScrollableAppWidget", "Click from list item $index")
- }
+ modifier = GlanceModifier.fillMaxWidth().padding(top = 8.dp),
+ text = title,
+ style = TextStyle(
+ fontSize = 16.sp,
+ textDecoration = TextDecoration.Underline,
+ fontWeight = FontWeight.Bold,
+ textAlign = TextAlign.Center
+ )
)
- }
- item {
- SectionHeading(
- title = "Compound buttons",
- description = "Check buttons below"
- )
- }
- item {
- var checked by remember { mutableStateOf(false) }
- CheckBox(
- checked = checked,
- onCheckedChange = { checked = !checked },
- text = "Checkbox"
+ Text(
+ text = description,
+ style = TextStyle(fontSize = 12.sp),
+ modifier = GlanceModifier.fillMaxWidth().padding(16.dp)
)
}
}
}
-
-@Composable
-private fun SectionHeading(title: String, description: String) {
- Column {
- Text(
- modifier = GlanceModifier.fillMaxWidth().padding(top = 8.dp),
- text = title,
- style = TextStyle(
- fontSize = 16.sp,
- textDecoration = TextDecoration.Underline,
- fontWeight = FontWeight.Bold,
- textAlign = TextAlign.Center
- )
- )
- Text(
- text = description,
- style = TextStyle(fontSize = 12.sp),
- modifier = GlanceModifier.fillMaxWidth().padding(16.dp)
- )
- }
-}
-
/** Activity opened by clicking a list adapter item in [ScrollableAppWidget]. */
class ListClickDestinationActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/TypogryaphDemoAppWidget.kt b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/TypogryaphDemoAppWidget.kt
new file mode 100644
index 0000000..dee09c1
--- /dev/null
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/TypogryaphDemoAppWidget.kt
@@ -0,0 +1,154 @@
+/*
+ * 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.glance.appwidget.demos
+
+import android.content.Context
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.glance.GlanceId
+import androidx.glance.GlanceModifier
+import androidx.glance.GlanceTheme
+import androidx.glance.appwidget.GlanceAppWidget
+import androidx.glance.appwidget.GlanceAppWidgetReceiver
+import androidx.glance.appwidget.SizeMode
+import androidx.glance.appwidget.lazy.LazyColumn
+import androidx.glance.appwidget.provideContent
+import androidx.glance.background
+import androidx.glance.layout.Column
+import androidx.glance.layout.Spacer
+import androidx.glance.layout.fillMaxSize
+import androidx.glance.layout.fillMaxWidth
+import androidx.glance.layout.padding
+import androidx.glance.layout.size
+import androidx.glance.layout.wrapContentHeight
+import androidx.glance.text.FontFamily
+import androidx.glance.text.FontWeight
+import androidx.glance.text.Text
+import androidx.glance.text.TextAlign
+import androidx.glance.text.TextStyle
+
+/**
+ * Sample AppWidget showcases Glance text styles.
+ */
+class TypographyDemoAppWidget : GlanceAppWidget() {
+ override val sizeMode: SizeMode = SizeMode.Exact
+
+ override suspend fun provideGlance(
+ context: Context,
+ id: GlanceId
+ ) = provideContent {
+ Column(
+ modifier = GlanceModifier.fillMaxSize()
+ .background(GlanceTheme.colors.background).padding(8.dp)
+ ) {
+ Column {
+ Text(
+ "Text Component Demo Widget",
+ modifier = GlanceModifier.fillMaxWidth().wrapContentHeight(),
+ style = TextStyle(
+ fontWeight = FontWeight.Bold,
+ fontSize = 24.sp,
+ textAlign = TextAlign.Center
+ )
+ )
+ Spacer(GlanceModifier.size(16.dp))
+ Text(
+ "Glance text styles:",
+ style = TextStyle(fontSize = 18.sp)
+ )
+ Spacer(GlanceModifier.size(20.dp))
+ }
+
+ LazyColumn {
+ item {
+ Text(
+ "Display Large",
+ style = TextStyle(
+ fontSize = 57.sp,
+ fontWeight = FontWeight.Normal,
+ fontFamily = FontFamily.SansSerif
+ )
+ )
+ }
+ item {
+ Text(
+ "Headline Large",
+ style = TextStyle(
+ fontSize = 32.sp,
+ fontWeight = FontWeight.Normal,
+ fontFamily = FontFamily.SansSerif
+ )
+ )
+ }
+ item {
+ Text(
+ "Headline Small",
+ style = TextStyle(
+ fontSize = 24.sp,
+ fontWeight = FontWeight.Normal,
+ fontFamily = FontFamily.SansSerif
+ )
+ )
+ }
+ item {
+ Text(
+ "Title Medium",
+ style = TextStyle(
+ fontSize = 16.sp,
+ fontWeight = FontWeight.Medium,
+ fontFamily = FontFamily.SansSerif
+ )
+ )
+ }
+ item {
+ Text(
+ "Body Medium",
+ style = TextStyle(
+ fontSize = 14.sp,
+ fontWeight = FontWeight.Normal,
+ fontFamily = FontFamily.SansSerif
+ )
+ )
+ }
+ item {
+ Text(
+ "Label Large",
+ style = TextStyle(
+ fontSize = 14.sp,
+ fontWeight = FontWeight.Medium,
+ fontFamily = FontFamily.SansSerif
+ )
+ )
+ }
+ item {
+ Text(
+ "Label Medium",
+ style = TextStyle(
+ fontSize = 12.sp,
+ fontWeight = FontWeight.Medium,
+ fontFamily = FontFamily.SansSerif
+ )
+ )
+ }
+ }
+ }
+ }
+}
+
+class TypographyDemoAppWidgetReceiver : GlanceAppWidgetReceiver() {
+ override val glanceAppWidget: GlanceAppWidget = TypographyDemoAppWidget()
+}
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml b/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml
index 638118d..e74682e 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml
@@ -28,6 +28,7 @@
<string name="compound_button_widget_name">Compound buttons Widget</string>
<string name="error_widget_name">Error UI Widget</string>
<string name="font_widget_name">Font Demo Widget</string>
+ <string name="typography_widget_name">Typography Demo Widget</string>
<string name="scrollable_widget_name">Scrollable Widget</string>
<string name="image_widget_name">Image Widget</string>
<string name="ripple_widget_name">Ripple Widget</string>
diff --git a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/CheckBoxTest.kt b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/CheckBoxTest.kt
index 8b42c7c..a43fddd 100644
--- a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/CheckBoxTest.kt
+++ b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/CheckBoxTest.kt
@@ -57,7 +57,7 @@
}
}
- @SdkSuppress(minSdkVersion = 31)
+ @SdkSuppress(minSdkVersion = 31, maxSdkVersion = 32) // max is set due to b/283484546
@Test
fun check_box_checked_31() {
TestGlanceAppWidget.uiDefinition = checkedCheckBox
@@ -90,7 +90,7 @@
}
}
- @SdkSuppress(minSdkVersion = 31)
+ @SdkSuppress(minSdkVersion = 31, maxSdkVersion = 32) // max is set due to b/283484546
@Test
fun check_box_unchecked_31() {
TestGlanceAppWidget.uiDefinition = uncheckedCheckBox
@@ -123,6 +123,7 @@
}
}
+ @SdkSuppress(minSdkVersion = 29, maxSdkVersion = 32) // max is set due to b/283484546
@Test
fun check_box_modifiers() {
TestGlanceAppWidget.uiDefinition = {
diff --git a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetManagerTest.kt b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetManagerTest.kt
index ddfd0bfa..0656823 100644
--- a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetManagerTest.kt
+++ b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetManagerTest.kt
@@ -28,6 +28,7 @@
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
@@ -112,6 +113,7 @@
assertThat(result).isFalse()
}
+ @Ignore("b/285198114")
@Test
fun cleanReceivers() {
mHostRule.onHostActivity { activity ->
diff --git a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt
index 927111b..4887f75 100644
--- a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt
+++ b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt
@@ -633,9 +633,6 @@
internal inline fun <reified T : View> ListView.getUnboxedListItem(position: Int): T {
val remoteViewFrame = assertIs<FrameLayout>(getChildAt(position))
- // Each list item frame has an explicit focusable = true, see
- // "Glance.AppWidget.Theme.ListChildren" style.
- assertThat(remoteViewFrame.isFocusable).isTrue()
// Android S- have a RemoteViewsAdapter$RemoteViewsFrameLayout first, Android T+ do not.
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S) {
diff --git a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/StrictModeTest.kt b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/StrictModeTest.kt
index a2f2e22..d906533 100644
--- a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/StrictModeTest.kt
+++ b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/StrictModeTest.kt
@@ -44,6 +44,7 @@
import kotlin.test.assertIs
import org.junit.After
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
@@ -121,6 +122,7 @@
Truth.assertThat(CallbackTest.received.get()).containsExactly(1, 2)
}
+ @Ignore // b/277763853
@Test
fun lazyColumn_actionRunCallback() {
TestGlanceAppWidget.uiDefinition = {
diff --git a/glance/glance-appwidget/src/main/AndroidManifest.xml b/glance/glance-appwidget/src/main/AndroidManifest.xml
index a78692f..ab5123f 100644
--- a/glance/glance-appwidget/src/main/AndroidManifest.xml
+++ b/glance/glance-appwidget/src/main/AndroidManifest.xml
@@ -18,6 +18,7 @@
<application>
<activity
android:name=".action.ActionTrampolineActivity"
+ android:excludeFromRecents="true"
android:exported="false"
android:enabled="true" />
<activity
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceRemoteViewsService.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceRemoteViewsService.kt
index a9b49c7..2f0d9d6 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceRemoteViewsService.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceRemoteViewsService.kt
@@ -140,14 +140,25 @@
}
override fun getViewAt(position: Int): RemoteViews {
- return items().getItemView(position)
+ return try {
+ items().getItemView(position)
+ } catch (e: ArrayIndexOutOfBoundsException) {
+ // RemoteViewsAdapter may sometimes request an index that is out of bounds. Return
+ // an error view in this case. See b/242730601, b/254682488 for more details.
+ RemoteViews(context.packageName, R.layout.glance_invalid_list_item)
+ }
}
override fun getLoadingView() = null
override fun getViewTypeCount(): Int = items().viewTypeCount
- override fun getItemId(position: Int): Long = items().getItemId(position)
+ override fun getItemId(position: Int): Long =
+ try {
+ items().getItemId(position)
+ } catch (e: ArrayIndexOutOfBoundsException) {
+ -1
+ }
override fun hasStableIds(): Boolean = items().hasStableIds()
}
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ActionTrampoline.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ActionTrampoline.kt
index 0dae0d6..ffe8f34 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ActionTrampoline.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ActionTrampoline.kt
@@ -21,6 +21,7 @@
import android.content.Intent
import android.net.Uri
import android.os.Build
+import android.os.Bundle
import android.os.StrictMode
import android.widget.RemoteViews
import androidx.annotation.DoNotInline
@@ -42,7 +43,8 @@
internal fun Intent.applyTrampolineIntent(
translationContext: TranslationContext,
viewId: Int,
- type: ActionTrampolineType
+ type: ActionTrampolineType,
+ activityOptions: Bundle? = null,
): Intent {
val target = if (type == ActionTrampolineType.ACTIVITY) {
ActionTrampolineActivity::class.java
@@ -53,6 +55,7 @@
intent.data = createUniqueUri(translationContext, viewId, type)
intent.putExtra(ActionTypeKey, type.name)
intent.putExtra(ActionIntentKey, this)
+ activityOptions?.let { intent.putExtra(ActivityOptionsKey, it) }
}
}
@@ -99,9 +102,10 @@
val type = requireNotNull(intent.getStringExtra(ActionTypeKey)) {
"List adapter activity trampoline invoked without trampoline type"
}
+ val activityOptions = intent.getBundleExtra(ActivityOptionsKey)
allowUnsafeIntentLaunch {
when (ActionTrampolineType.valueOf(type)) {
- ActionTrampolineType.ACTIVITY -> startActivity(actionIntent)
+ ActionTrampolineType.ACTIVITY -> startActivity(actionIntent, activityOptions)
ActionTrampolineType.BROADCAST, ActionTrampolineType.CALLBACK ->
sendBroadcast(actionIntent)
ActionTrampolineType.SERVICE -> startService(actionIntent)
@@ -136,6 +140,7 @@
private const val ActionTypeKey = "ACTION_TYPE"
private const val ActionIntentKey = "ACTION_INTENT"
+private const val ActivityOptionsKey = "ACTIVITY_OPTIONS"
@RequiresApi(Build.VERSION_CODES.O)
private object ListAdapterTrampolineApi26Impl {
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ApplyAction.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ApplyAction.kt
index 2a5d2b4..ceba104 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ApplyAction.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ApplyAction.kt
@@ -94,6 +94,7 @@
}
},
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
+ action.activityOptions,
)
}
is StartServiceAction -> {
@@ -208,6 +209,7 @@
translationContext,
viewId = viewId,
type = ActionTrampolineType.ACTIVITY,
+ activityOptions = action.activityOptions,
)
}
is StartServiceAction -> {
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/StartActivityIntentAction.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/StartActivityIntentAction.kt
index ed387ab..6adb68f 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/StartActivityIntentAction.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/StartActivityIntentAction.kt
@@ -18,6 +18,8 @@
import android.app.Activity
import android.content.Intent
+import android.os.Bundle
+import androidx.glance.ExperimentalGlanceApi
import androidx.glance.action.Action
import androidx.glance.action.ActionParameters
import androidx.glance.action.StartActivityAction
@@ -25,7 +27,8 @@
internal class StartActivityIntentAction(
val intent: Intent,
- override val parameters: ActionParameters = actionParametersOf()
+ override val parameters: ActionParameters = actionParametersOf(),
+ override val activityOptions: Bundle?,
) : StartActivityAction
/**
@@ -34,15 +37,15 @@
*
* This action is supported by app widgets only.
*
- * The given intent will be wrapped in a [PendingIntent]. This means that if you create multiple
- * actions with this function, they will be conflated unless the underlying intents are
+ * The given intent will be wrapped in a [android.app.PendingIntent]. This means that if you create
+ * multiple actions with this function, they will be conflated unless the underlying intents are
* distinct from one another, as defined by [Intent.filterEquals]. For example, if you create two
* [Intent]s that target the same Activity but only differ by parameters, they will get conflated
* (the PendingIntent created by the first call to actionStartActivity will be overwritten by the
* second). A simple way to avoid this is to set a unique data URI on these intents, so that they
* are distinct as defined by [Intent.filterEquals]. There is more information in the class
- * documentation for [PendingIntent]. If you do not set one, the library will add a unique URI on
- * the intent you provide here.
+ * documentation for [android.app.PendingIntent]. If you do not set one, the library will add a
+ * unique URI on the intent you provide here.
*
* @param intent the intent used to launch the activity
* @param parameters the parameters associated with the action. Parameter values will be added to
@@ -50,5 +53,34 @@
*/
fun actionStartActivity(
intent: Intent,
- parameters: ActionParameters = actionParametersOf()
-): Action = StartActivityIntentAction(intent, parameters)
+ parameters: ActionParameters = actionParametersOf(),
+): Action = StartActivityIntentAction(intent, parameters, null)
+
+/**
+ * Creates an [Action] that launches an [Activity] from the given [Intent] when triggered. The
+ * intent should specify a component with [Intent.setClass] or [Intent.setComponent].
+ *
+ * This action is supported by app widgets only.
+ *
+ * The given intent will be wrapped in a [android.app.PendingIntent]. This means that if you create
+ * multiple actions with this function, they will be conflated unless the underlying intents are
+ * distinct from one another, as defined by [Intent.filterEquals]. For example, if you create two
+ * [Intent]s that target the same Activity but only differ by parameters, they will get conflated
+ * (the PendingIntent created by the first call to actionStartActivity will be overwritten by the
+ * second). A simple way to avoid this is to set a unique data URI on these intents, so that they
+ * are distinct as defined by [Intent.filterEquals]. There is more information in the class
+ * documentation for [android.app.PendingIntent]. If you do not set one, the library will add a
+ * unique URI on the intent you provide here.
+ *
+ * @param intent the intent used to launch the activity
+ * @param parameters the parameters associated with the action. Parameter values will be added to
+ * the activity intent, keyed by the parameter key name string.
+ * @param activityOptions Additional options built from an [android.app.ActivityOptions] to apply to
+ * an activity start.
+ */
+@ExperimentalGlanceApi
+fun actionStartActivity(
+ intent: Intent,
+ parameters: ActionParameters = actionParametersOf(),
+ activityOptions: Bundle? = null,
+): Action = StartActivityIntentAction(intent, parameters, activityOptions)
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/lazy/LazyList.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/lazy/LazyList.kt
index adb2d6e..47e619b 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/lazy/LazyList.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/lazy/LazyList.kt
@@ -16,10 +16,12 @@
package androidx.glance.appwidget.lazy
+import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.glance.Emittable
import androidx.glance.EmittableWithChildren
+import androidx.glance.ExperimentalGlanceApi
import androidx.glance.GlanceModifier
import androidx.glance.GlanceNode
import androidx.glance.layout.Alignment
@@ -56,6 +58,40 @@
)
}
+/**
+ * A vertical scrolling list that only lays out the currently visible items. The [content] block
+ * defines a DSL which allows you to emit different list items.
+ *
+ * @param activityOptions Additional options built from an [android.app.ActivityOptions] to apply to
+ * an activity start.
+ * @param modifier the modifier to apply to this layout
+ * @param horizontalAlignment the horizontal alignment applied to the items.
+ * @param content a block which describes the content. Inside this block you can use methods like
+ * [LazyListScope.item] to add a single item or [LazyListScope.items] to add a list of items. If the
+ * item has more than one top-level child, they will be automatically wrapped in a Box.
+ */
+@ExperimentalGlanceApi
+@Composable
+fun LazyColumn(
+ activityOptions: Bundle,
+ modifier: GlanceModifier = GlanceModifier,
+ horizontalAlignment: Alignment.Horizontal = Alignment.Start,
+ content: LazyListScope.() -> Unit
+) {
+ GlanceNode(
+ factory = ::EmittableLazyColumn,
+ update = {
+ this.set(modifier) { this.modifier = it }
+ this.set(horizontalAlignment) { this.horizontalAlignment = it }
+ this.set(activityOptions) { this.activityOptions = it }
+ },
+ content = applyListScope(
+ Alignment(horizontalAlignment, Alignment.Vertical.CenterVertically),
+ content
+ )
+ )
+}
+
private fun applyListScope(
alignment: Alignment,
content: LazyListScope.() -> Unit
@@ -244,10 +280,11 @@
internal abstract class EmittableLazyList : EmittableWithChildren(resetsDepthForChildren = true) {
override var modifier: GlanceModifier = GlanceModifier
var horizontalAlignment: Alignment.Horizontal = Alignment.Start
+ var activityOptions: Bundle? = null
override fun toString() =
"EmittableLazyList(modifier=$modifier, horizontalAlignment=$horizontalAlignment, " +
- "children=[\n${childrenToString()}\n])"
+ "activityOptions=$activityOptions, children=[\n${childrenToString()}\n])"
}
internal class EmittableLazyListItem : EmittableWithChildren() {
@@ -275,6 +312,7 @@
override fun copy(): Emittable = EmittableLazyColumn().also {
it.modifier = modifier
it.horizontalAlignment = horizontalAlignment
+ it.activityOptions = activityOptions
it.children.addAll(children.map { it.copy() })
}
}
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/lazy/LazyVerticalGrid.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/lazy/LazyVerticalGrid.kt
index 77a2e9d..9706a9f 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/lazy/LazyVerticalGrid.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/lazy/LazyVerticalGrid.kt
@@ -15,12 +15,14 @@
*/
package androidx.glance.appwidget.lazy
+import android.os.Bundle
import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.ui.unit.Dp
import androidx.glance.Emittable
import androidx.glance.EmittableWithChildren
+import androidx.glance.ExperimentalGlanceApi
import androidx.glance.GlanceModifier
import androidx.glance.GlanceNode
import androidx.glance.layout.Alignment
@@ -59,6 +61,43 @@
)
}
+/**
+ * The DSL implementation of a lazy grid layout. It composes only visible rows of the grid.
+ *
+ * @param gridCells the number of columns in the grid.
+ * @param activityOptions Additional options built from an [android.app.ActivityOptions] to apply to
+ * an activity start.
+ * @param modifier the modifier to apply to this layout
+ * @param horizontalAlignment the horizontal alignment applied to the items.
+ * @param content a block which describes the content. Inside this block you can use methods like
+ * [LazyVerticalGridScope.item] to add a single item or [LazyVerticalGridScope.items] to add a list
+ * of items. If the item has more than one top-level child, they will be automatically wrapped in a
+ * Box.
+ */
+@ExperimentalGlanceApi
+@Composable
+fun LazyVerticalGrid(
+ gridCells: GridCells,
+ activityOptions: Bundle,
+ modifier: GlanceModifier = GlanceModifier,
+ horizontalAlignment: Alignment.Horizontal = Alignment.Start,
+ content: LazyVerticalGridScope.() -> Unit
+) {
+ GlanceNode(
+ factory = ::EmittableLazyVerticalGrid,
+ update = {
+ this.set(gridCells) { this.gridCells = it }
+ this.set(modifier) { this.modifier = it }
+ this.set(horizontalAlignment) { this.horizontalAlignment = it }
+ this.set(activityOptions) { this.activityOptions = it }
+ },
+ content = applyVerticalGridScope(
+ Alignment(horizontalAlignment, Alignment.Vertical.CenterVertically),
+ content
+ )
+ )
+}
+
internal fun applyVerticalGridScope(
alignment: Alignment,
content: LazyVerticalGridScope.() -> Unit
@@ -239,11 +278,13 @@
override var modifier: GlanceModifier = GlanceModifier
var horizontalAlignment: Alignment.Horizontal = Alignment.Start
var gridCells: GridCells = GridCells.Fixed(1)
+ var activityOptions: Bundle? = null
override fun toString(): String =
"EmittableLazyVerticalGridList(modifier=$modifier, " +
"horizontalAlignment=$horizontalAlignment, " +
"numColumn=$gridCells, " +
+ "activityOptions=$activityOptions, " +
"children=[\n${childrenToString()}\n])"
}
@@ -277,6 +318,7 @@
it.modifier = modifier
it.horizontalAlignment = horizontalAlignment
it.gridCells = gridCells
+ it.activityOptions = activityOptions
it.children.addAll(children.map { it.copy() })
}
}
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/LazyListTranslator.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/LazyListTranslator.kt
index 2698f76..1998e8c 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/LazyListTranslator.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/LazyListTranslator.kt
@@ -67,6 +67,7 @@
0,
Intent(),
FILL_IN_COMPONENT or FLAG_MUTABLE or FLAG_UPDATE_CURRENT,
+ element.activityOptions,
)
)
val items = RemoteCollectionItems.Builder().apply {
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt
index 805c1f7..7bd787f 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt
@@ -80,6 +80,7 @@
0,
Intent(),
FILL_IN_COMPONENT or FLAG_MUTABLE or FLAG_UPDATE_CURRENT,
+ element.activityOptions,
)
)
val items = RemoteCollectionItems.Builder().apply {
diff --git a/glance/glance-appwidget/src/main/res/layout/glance_invalid_list_item.xml b/glance/glance-appwidget/src/main/res/layout/glance_invalid_list_item.xml
new file mode 100644
index 0000000..a3b4968
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/layout/glance_invalid_list_item.xml
@@ -0,0 +1,21 @@
+<?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.
+ -->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Invalid list item requested"/>
\ No newline at end of file
diff --git a/glance/glance-appwidget/src/main/res/layout/glance_list.xml b/glance/glance-appwidget/src/main/res/layout/glance_list.xml
index fe0fa2d..c189fd8 100644
--- a/glance/glance-appwidget/src/main/res/layout/glance_list.xml
+++ b/glance/glance-appwidget/src/main/res/layout/glance_list.xml
@@ -19,6 +19,7 @@
app:glance_isTopLevelLayout="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:listSelector="@android:color/transparent"
android:divider="@null"
android:theme="@style/Glance.AppWidget.Theme.ListChildren"
style="@style/Glance.AppWidget.List"/>
diff --git a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_auto_fit.xml b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_auto_fit.xml
index d71b95f..f0ee58f 100644
--- a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_auto_fit.xml
+++ b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_auto_fit.xml
@@ -21,5 +21,6 @@
android:layout_height="wrap_content"
android:divider="@null"
android:numColumns="auto_fit"
+ android:listSelector="@android:color/transparent"
android:theme="@style/Glance.AppWidget.Theme.GridChildren"
style="@style/Glance.AppWidget.VerticalGrid"/>
diff --git a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_five_columns.xml b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_five_columns.xml
index 2cb9b3d..d77d31c 100644
--- a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_five_columns.xml
+++ b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_five_columns.xml
@@ -21,5 +21,6 @@
android:layout_height="wrap_content"
android:divider="@null"
android:numColumns="5"
+ android:listSelector="@android:color/transparent"
android:theme="@style/Glance.AppWidget.Theme.GridChildren"
style="@style/Glance.AppWidget.VerticalGrid"/>
diff --git a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_four_columns.xml b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_four_columns.xml
index 6a2d0a4..10e3df1 100644
--- a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_four_columns.xml
+++ b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_four_columns.xml
@@ -21,5 +21,6 @@
android:layout_height="wrap_content"
android:divider="@null"
android:numColumns="4"
+ android:listSelector="@android:color/transparent"
android:theme="@style/Glance.AppWidget.Theme.GridChildren"
style="@style/Glance.AppWidget.VerticalGrid"/>
diff --git a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_one_column.xml b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_one_column.xml
index a207b2db..4d3bc8b9 100644
--- a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_one_column.xml
+++ b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_one_column.xml
@@ -21,5 +21,6 @@
android:layout_height="wrap_content"
android:divider="@null"
android:numColumns="1"
+ android:listSelector="@android:color/transparent"
android:theme="@style/Glance.AppWidget.Theme.GridChildren"
style="@style/Glance.AppWidget.VerticalGrid"/>
diff --git a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_three_columns.xml b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_three_columns.xml
index f52b24e..254dd1b 100644
--- a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_three_columns.xml
+++ b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_three_columns.xml
@@ -21,5 +21,6 @@
android:layout_height="wrap_content"
android:divider="@null"
android:numColumns="3"
+ android:listSelector="@android:color/transparent"
android:theme="@style/Glance.AppWidget.Theme.GridChildren"
style="@style/Glance.AppWidget.VerticalGrid"/>
diff --git a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_two_columns.xml b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_two_columns.xml
index b6c7b9d6..07a1f76 100644
--- a/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_two_columns.xml
+++ b/glance/glance-appwidget/src/main/res/layout/glance_vertical_grid_two_columns.xml
@@ -21,5 +21,6 @@
android:layout_height="wrap_content"
android:divider="@null"
android:numColumns="2"
+ android:listSelector="@android:color/transparent"
android:theme="@style/Glance.AppWidget.Theme.GridChildren"
style="@style/Glance.AppWidget.VerticalGrid"/>
diff --git a/glance/glance-appwidget/src/main/res/values-as/strings.xml b/glance/glance-appwidget/src/main/res/values-as/strings.xml
new file mode 100644
index 0000000..0ce6cddd
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-as/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance এপৰ ৱিজেটৰ আসোঁৱাহ"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033"><b><tt>"GlanceAppWidget"</tt></b>" বিচৰা সময়ত "<b><tt>"adb logcat"</tt></b>" ব্যৱহাৰ কৰি সঠিক আসোঁৱাহটো পৰীক্ষা কৰক"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-bn/strings.xml b/glance/glance-appwidget/src/main/res/values-bn/strings.xml
new file mode 100644
index 0000000..c178749
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-bn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance App উইজেট সংক্রান্ত সমস্যা"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"আসল সমস্যাটি কী তা "<b><tt>"adb logcat"</tt></b>"-এর সাহায্যে চেক করুন, "<b><tt>"GlanceAppWidget"</tt></b>"-এর জন্য সার্চ করা হচ্ছে"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-bs/strings.xml b/glance/glance-appwidget/src/main/res/values-bs/strings.xml
index 111f2bc..9873eac 100644
--- a/glance/glance-appwidget/src/main/res/values-bs/strings.xml
+++ b/glance/glance-appwidget/src/main/res/values-bs/strings.xml
@@ -17,6 +17,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Pogreška widgeta aplikacije Kratki pregled"</b></string>
- <string name="glance_error_layout_text" msgid="2863935784364843033">"Konkretnu pogrešku provjerite koristeći "<b><tt>"adb logcat"</tt></b>" i potražite "<b><tt>"GlanceAppWidget"</tt></b></string>
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Greška vidžeta aplikacije Glance"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"Provjerite konkretnu grešku koristeći "<b><tt>"adb logcat"</tt></b>" i pretraživanjem "<b><tt>"GlanceAppWidget"</tt></b></string>
</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-et/strings.xml b/glance/glance-appwidget/src/main/res/values-et/strings.xml
new file mode 100644
index 0000000..665dc58
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-et/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Rakenduse Ülevaade vidina viga"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"Kontrollige konkreetset viga tööriistaga "<b><tt>"adb logcat"</tt></b>", sisestades otsingu "<b><tt>"GlanceAppWidget"</tt></b></string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-eu/strings.xml b/glance/glance-appwidget/src/main/res/values-eu/strings.xml
new file mode 100644
index 0000000..28c7e98
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-eu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance aplikazioaren widgetaren errorea"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"Errore zehatza ikusteko, erabili "<b><tt>"adb logcat"</tt></b>" bertan "<b><tt>"GlanceAppWidget"</tt></b>" bilatzeko"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-fr-rCA/strings.xml b/glance/glance-appwidget/src/main/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..726a961
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-fr-rCA/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Erreur provenant de la librairie Glance App Widget"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"Vérifiez l\'erreur exacte en utilisant "<b><tt>"adb logcat"</tt></b>", en recherchant "<b><tt>"GlanceAppWidget"</tt></b></string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-gl/strings.xml b/glance/glance-appwidget/src/main/res/values-gl/strings.xml
new file mode 100644
index 0000000..d8ba4d6
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-gl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Erro do widget da aplicación Glance"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"Comproba o erro exacto usando "<b><tt>"adb logcat"</tt></b>" e buscando "<b><tt>"GlanceAppWidget"</tt></b></string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-gu/strings.xml b/glance/glance-appwidget/src/main/res/values-gu/strings.xml
new file mode 100644
index 0000000..bd5a3da
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-gu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance ઍપ વિજેટમાં ભૂલ"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033"><b><tt>"adb logcat"</tt></b>"નો ઉપયોગ કરીને, "<b><tt>"GlanceAppWidget"</tt></b>" શોધીને ચોક્કસ ભૂલ ચેક કરો"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-it/strings.xml b/glance/glance-appwidget/src/main/res/values-it/strings.xml
new file mode 100644
index 0000000..1f0c434
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-it/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Errore del widget dell\'app Glance"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"Controlla l\'errore esatto con "<b><tt>"adb logcat"</tt></b>", cercando "<b><tt>"GlanceAppWidget"</tt></b></string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-ka/strings.xml b/glance/glance-appwidget/src/main/res/values-ka/strings.xml
new file mode 100644
index 0000000..71c5995
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-ka/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance აპის ვიჯეტის შეცდომა"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"შეამოწმეთ ზუსტი შეცდომა "<b><tt>"adb logcat"</tt></b>"-ის მეშვეობით, მოიძიეთ "<b><tt>"GlanceAppWidget"</tt></b></string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-kk/strings.xml b/glance/glance-appwidget/src/main/res/values-kk/strings.xml
new file mode 100644
index 0000000..1619cee
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-kk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance App Widget қатесі"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"Қатені дәл анықтау үшін "<b><tt>"adb logcat"</tt></b>" мәнін қолданыңыз және "<b><tt>"GlanceAppWidget"</tt></b>" іздеңіз."</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-kn/strings.xml b/glance/glance-appwidget/src/main/res/values-kn/strings.xml
new file mode 100644
index 0000000..846ab94
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-kn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance ಆ್ಯಪ್ ವಿಜೆಟ್ ದೋಷ"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033"><b><tt>"adb logcat"</tt></b>" ಬಳಸಿಕೊಂಡು ನಿಖರವಾದ ದೋಷವನ್ನು ಪರಿಶೀಲಿಸಿ, "<b><tt>"GlanceAppWidget"</tt></b>" ಅನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-lv/strings.xml b/glance/glance-appwidget/src/main/res/values-lv/strings.xml
new file mode 100644
index 0000000..764469a
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-lv/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance lietotnes logrīka kļūda"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"Atrodiet precīzu kļūdu ar rīka "<b><tt>"adb logcat"</tt></b>" palīdzību, izmantojot meklēšanas vaicājumu "<b><tt>"GlanceAppWidget"</tt></b>"."</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-ml/strings.xml b/glance/glance-appwidget/src/main/res/values-ml/strings.xml
new file mode 100644
index 0000000..83b80a6
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-ml/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance ആപ്പ് വിജറ്റ് പിശക്"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033"><b><tt>"adb logcat"</tt></b>" ഉപയോഗിച്ച് യഥാർത്ഥ പിശക് പരിശോധിക്കുക, "<b><tt>"GlanceAppWidget"</tt></b>" എന്നത് തിരയുന്നു"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-mn/strings.xml b/glance/glance-appwidget/src/main/res/values-mn/strings.xml
new file mode 100644
index 0000000..3c0adc2
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-mn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Гялс харах аппын виджетийн алдаа"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033"><b><tt>"Adb logcat"</tt></b>" ашиглан, "<b><tt>"GlanceAppWidget"</tt></b>"-г хайж тодорхой алдааг шалгана уу"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-mr/strings.xml b/glance/glance-appwidget/src/main/res/values-mr/strings.xml
new file mode 100644
index 0000000..9678594
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-mr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance अॅप विजेट एरर"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033"><b><tt>"GlanceAppWidget"</tt></b>" शोधून, "<b><tt>"adb logcat"</tt></b>" वापरून नेमकी एरर तपासा"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-my/strings.xml b/glance/glance-appwidget/src/main/res/values-my/strings.xml
new file mode 100644
index 0000000..1c0e468
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-my/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance အက်ပ်ဝိဂျက်အမှား"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033"><b><tt>"GlanceAppWidget"</tt></b>" ရှာဖွေရာတွင် "<b><tt>"adb logcat"</tt></b>" သုံးပြီး အမှားအတိအကျကို ရှာနိုင်သည်"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-nb/strings.xml b/glance/glance-appwidget/src/main/res/values-nb/strings.xml
new file mode 100644
index 0000000..3a79062
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-nb/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Modulfeil med Kort fortalt-appen"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"Sjekk den nøyaktige feilen ved å bruke "<b><tt>"adb logcat"</tt></b>" og søke etter "<b><tt>"GlanceAppWidget"</tt></b></string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-ne/strings.xml b/glance/glance-appwidget/src/main/res/values-ne/strings.xml
new file mode 100644
index 0000000..224c701
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-ne/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance एपको विजेटसम्बन्धी त्रुटि"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033"><b><tt>"adb logcat"</tt></b>" प्रयोग गरी "<b><tt>"GlanceAppWidget"</tt></b>" खोजेर यथार्थ त्रुटि पत्ता लगाउनुहोस्"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-or/strings.xml b/glance/glance-appwidget/src/main/res/values-or/strings.xml
new file mode 100644
index 0000000..65b9858
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-or/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance ଆପ ୱିଜେଟରେ ତ୍ରୁଟି"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033"><b><tt>"adb logcat"</tt></b>" ବ୍ୟବହାର କରି, "<b><tt>"GlanceAppWidget"</tt></b>" ସନ୍ଧାନ କରି ପ୍ରକୃତ ତ୍ରୁଟି ଯାଞ୍ଚ କରନ୍ତୁ"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-pa/strings.xml b/glance/glance-appwidget/src/main/res/values-pa/strings.xml
new file mode 100644
index 0000000..6892ffb
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-pa/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance ਐਪ ਵਿਜੇਟ ਸੰਬੰਧੀ ਗੜਬੜ"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033"><b><tt>"adb logcat"</tt>" ਦੀ ਵਰਤੋਂ ਨਾਲ "</b>", "<b><tt>"GlanceAppWidget"</tt></b>" ਦੀ ਖੋਜ ਕਰ ਕੇ ਸਟੀਕ ਗੜਬੜ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-pl/strings.xml b/glance/glance-appwidget/src/main/res/values-pl/strings.xml
new file mode 100644
index 0000000..f537ca9
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-pl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Błąd widżetu aplikacji W skrócie"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"Sprawdź dokładny błąd w "<b><tt>"adb logcat"</tt></b>" (wyszukaj "<b><tt>"GlanceAppWidget"</tt></b>")"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-sl/strings.xml b/glance/glance-appwidget/src/main/res/values-sl/strings.xml
new file mode 100644
index 0000000..376e740
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-sl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Napaka pripomočka za aplikacijo Hitri pregled"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">"Preverite točno napako tako, da z mehanizmom "<b><tt>"adb logcat"</tt></b>" poiščete "<b><tt>"GlanceAppWidget"</tt></b>"."</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-ta/strings.xml b/glance/glance-appwidget/src/main/res/values-ta/strings.xml
new file mode 100644
index 0000000..dac5671
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-ta/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531"><b>"Glance ஆப்ஸ் விட்ஜெட் பிழை"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033"><b><tt>"adb logcat"</tt></b>" என்பதைப் பயன்படுத்தி சரியான பிழையைக் கண்டறியவும், "<b><tt>"GlanceAppWidget"</tt></b>" தேடப்படுகிறது"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-ur/strings.xml b/glance/glance-appwidget/src/main/res/values-ur/strings.xml
new file mode 100644
index 0000000..00e7a24
--- /dev/null
+++ b/glance/glance-appwidget/src/main/res/values-ur/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="glance_error_layout_title" msgid="3631961919234443531">""<b>"Glance App Widget کی خرابی"</b></string>
+ <string name="glance_error_layout_text" msgid="2863935784364843033">""<b><tt>"GlanceAppWidget"</tt></b>" کو تلاش کرتے ہوئے "<b><tt>"adb logcat"</tt></b>" کا استعمال کر کے اصل خرابی کو چیک کریں"</string>
+</resources>
diff --git a/glance/glance-appwidget/src/main/res/values-v29/themes.xml b/glance/glance-appwidget/src/main/res/values-v29/themes.xml
index 38f23cc..235e848 100644
--- a/glance/glance-appwidget/src/main/res/values-v29/themes.xml
+++ b/glance/glance-appwidget/src/main/res/values-v29/themes.xml
@@ -16,23 +16,6 @@
<resources>
<style name="Glance.AppWidget.Theme" parent="android:Theme.DeviceDefault.DayNight"/>
- <style name="Glance.AppWidget.Theme.ListChildren" parent="">
- <!--
- AbsListView sets a list item to be clickable if the focusable is not explicitly set.
- This has effect of list items showing up as numbered when Voice access is activated
- (even if they don't have any click listeners). See ListItemAccessibilityDelegate. In
- order to prevent this, we explicitly set focusable as true here.
- -->
- <item name="android:focusable">true</item>
- </style>
- <style name="Glance.AppWidget.Theme.GridChildren" parent="">
- <!--
- AbsListView (extended by GridView) sets a list item to be clickable if the focusable is
- not explicitly set. This has effect of list items showing up as numbered when Voice
- access is activated (even if they don't have any click listeners). See
- ListItemAccessibilityDelegate. In order to prevent this, we explicitly set focusable as
- true here.
- -->
- <item name="android:focusable">true</item>
- </style>
+ <style name="Glance.AppWidget.Theme.ListChildren" parent=""/>
+ <style name="Glance.AppWidget.Theme.GridChildren" parent=""/>
</resources>
diff --git a/glance/glance-appwidget/src/main/res/values/strings.xml b/glance/glance-appwidget/src/main/res/values/strings.xml
index 68257b2..ab97195 100644
--- a/glance/glance-appwidget/src/main/res/values/strings.xml
+++ b/glance/glance-appwidget/src/main/res/values/strings.xml
@@ -15,6 +15,12 @@
-->
<resources>
+ <!-- The title of a ui area that is shown to a developer when there is an error in their App
+ Widget that has been made with the Glance framework. [CHAR_LIMIT=NONE] -->
<string name="glance_error_layout_title"><b>Glance App Widget Error</b></string>
+ <!-- The body of an error message shown to a developer when there has been an error with their
+ App Widget that has been made with the Glance framework. "adb logcat" is a technical
+ command and should not be translated. "GlanceAppWidget" is the exact term the developer
+ needs to search for and should not be translated. [CHAR_LIMIT=NONE]. -->
<string name="glance_error_layout_text">Check the exact error using <b><tt>adb logcat</tt></b>, searching for <b><tt>GlanceAppWidget</tt></b></string>
</resources>
\ No newline at end of file
diff --git a/glance/glance-appwidget/src/main/res/values/themes.xml b/glance/glance-appwidget/src/main/res/values/themes.xml
index 06219df..3c448ef 100644
--- a/glance/glance-appwidget/src/main/res/values/themes.xml
+++ b/glance/glance-appwidget/src/main/res/values/themes.xml
@@ -16,23 +16,6 @@
<resources>
<style name="Glance.AppWidget.Theme" parent="android:Theme.DeviceDefault" />
- <style name="Glance.AppWidget.Theme.ListChildren" parent="">
- <!--
- AbsListView sets a list item to be clickable if the focusable is not explicitly set.
- This has effect of list items showing up as numbered when Voice access is activated
- (even if they don't have any click listeners). See ListItemAccessibilityDelegate. In
- order to prevent this, we explicitly set focusable as true here.
- -->
- <item name="android:focusable">true</item>
- </style>
- <style name="Glance.AppWidget.Theme.GridChildren" parent="">
- <!--
- AbsListView (extended by GridView) sets a list item to be clickable if the focusable is
- not explicitly set. This has effect of list items showing up as numbered when Voice
- access is activated (even if they don't have any click listeners). See
- ListItemAccessibilityDelegate. In order to prevent this, we explicitly set focusable as
- true here.
- -->
- <item name="android:focusable">true</item>
- </style>
+ <style name="Glance.AppWidget.Theme.ListChildren" parent=""/>
+ <style name="Glance.AppWidget.Theme.GridChildren" parent=""/>
</resources>
diff --git a/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/layout/LazyColumnTest.kt b/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/layout/LazyColumnTest.kt
index 22c6a6c..0e0032c 100644
--- a/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/layout/LazyColumnTest.kt
+++ b/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/layout/LazyColumnTest.kt
@@ -16,6 +16,8 @@
package androidx.glance.appwidget.layout
+import android.os.Bundle
+import androidx.glance.ExperimentalGlanceApi
import androidx.glance.appwidget.lazy.EmittableLazyColumn
import androidx.glance.appwidget.lazy.EmittableLazyListItem
import androidx.glance.appwidget.lazy.LazyColumn
@@ -247,6 +249,18 @@
assertThat(column.getTextAtChild(1)).isEqualTo("2 - Bob")
}
+ @OptIn(ExperimentalGlanceApi::class)
+ @Test
+ fun canTranslateActivityOptions() = fakeCoroutineScope.runTest {
+ val options = Bundle()
+ val root = runTestingComposition {
+ LazyColumn(activityOptions = options) {}
+ }
+
+ val column = assertIs<EmittableLazyColumn>(root.children.single())
+ assertThat(column.activityOptions).isSameInstanceAs(options)
+ }
+
private fun EmittableLazyColumn.getTextAtChild(index: Int): String =
assertIs<EmittableText>((children[index] as EmittableLazyListItem).children.first()).text
diff --git a/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/layout/LazyVerticalGridTest.kt b/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/layout/LazyVerticalGridTest.kt
index 0e686ff..974657e 100644
--- a/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/layout/LazyVerticalGridTest.kt
+++ b/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/layout/LazyVerticalGridTest.kt
@@ -17,7 +17,9 @@
package androidx.glance.appwidget.layout
import android.annotation.TargetApi
+import android.os.Bundle
import androidx.compose.ui.unit.dp
+import androidx.glance.ExperimentalGlanceApi
import androidx.glance.appwidget.lazy.EmittableLazyVerticalGrid
import androidx.glance.appwidget.lazy.EmittableLazyVerticalGridListItem
import androidx.glance.appwidget.lazy.GridCells
@@ -262,6 +264,18 @@
assertThat(verticalGrid.getTextAtChild(1)).isEqualTo("2 - Bob")
}
+ @OptIn(ExperimentalGlanceApi::class)
+ @Test
+ fun canTranslateActivityOptions() = fakeCoroutineScope.runTest {
+ val options = Bundle()
+ val root = runTestingComposition {
+ LazyVerticalGrid(GridCells.Fixed(1), activityOptions = options) {}
+ }
+
+ val grid = assertIs<EmittableLazyVerticalGrid>(root.children.single())
+ assertThat(grid.activityOptions).isSameInstanceAs(options)
+ }
+
private fun EmittableLazyVerticalGrid.getTextAtChild(index: Int): String =
assertIs<EmittableText>((children[index] as
EmittableLazyVerticalGridListItem).children.first()).text
diff --git a/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt b/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt
index 340ea7b..8f27c64 100644
--- a/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt
+++ b/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt
@@ -197,6 +197,7 @@
}
@Test
+ @Suppress("deprecation") // For backwards compatibility.
fun tileProviderReturnsResources() = fakeCoroutineScope.runTest {
val tileRequest = RequestBuilders.TileRequest.Builder().build()
val tileFuture = tileServiceClient.requestTile(tileRequest)
@@ -217,6 +218,7 @@
}
@Test
+ @Suppress("deprecation") // For backwards compatibility.
fun tileProviderReturnsTimelineResources() = fakeCoroutineScope.runTest {
val tileRequest = RequestBuilders.TileRequest.Builder().build()
val tileFuture = tileServiceClientWithTimeline.requestTile(tileRequest)
diff --git a/glance/glance/api/1.0.0-beta02.txt b/glance/glance/api/1.0.0-beta02.txt
index 0b4edd4..6fc7e87 100644
--- a/glance/glance/api/1.0.0-beta02.txt
+++ b/glance/glance/api/1.0.0-beta02.txt
@@ -54,6 +54,9 @@
property public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Object> LocalState;
}
+ @kotlin.RequiresOptIn(message="This API is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalGlanceApi {
+ }
+
@androidx.compose.runtime.ComposableTargetMarker(description="Glance Composable") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.TYPE, kotlin.annotation.AnnotationTarget.TYPE_PARAMETER}) public @interface GlanceComposable {
}
@@ -170,8 +173,11 @@
public final class StartActivityActionKt {
method public static androidx.glance.action.Action actionStartActivity(android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static androidx.glance.action.Action actionStartActivity(android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
method public static inline <reified T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static inline <reified T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
method public static <T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(Class<T> activity, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static <T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(Class<T> activity, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
}
}
diff --git a/glance/glance/api/current.txt b/glance/glance/api/current.txt
index 0b4edd4..6fc7e87 100644
--- a/glance/glance/api/current.txt
+++ b/glance/glance/api/current.txt
@@ -54,6 +54,9 @@
property public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Object> LocalState;
}
+ @kotlin.RequiresOptIn(message="This API is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalGlanceApi {
+ }
+
@androidx.compose.runtime.ComposableTargetMarker(description="Glance Composable") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.TYPE, kotlin.annotation.AnnotationTarget.TYPE_PARAMETER}) public @interface GlanceComposable {
}
@@ -170,8 +173,11 @@
public final class StartActivityActionKt {
method public static androidx.glance.action.Action actionStartActivity(android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static androidx.glance.action.Action actionStartActivity(android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
method public static inline <reified T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static inline <reified T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
method public static <T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(Class<T> activity, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static <T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(Class<T> activity, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
}
}
diff --git a/glance/glance/api/restricted_1.0.0-beta02.txt b/glance/glance/api/restricted_1.0.0-beta02.txt
index 0b4edd4..6fc7e87 100644
--- a/glance/glance/api/restricted_1.0.0-beta02.txt
+++ b/glance/glance/api/restricted_1.0.0-beta02.txt
@@ -54,6 +54,9 @@
property public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Object> LocalState;
}
+ @kotlin.RequiresOptIn(message="This API is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalGlanceApi {
+ }
+
@androidx.compose.runtime.ComposableTargetMarker(description="Glance Composable") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.TYPE, kotlin.annotation.AnnotationTarget.TYPE_PARAMETER}) public @interface GlanceComposable {
}
@@ -170,8 +173,11 @@
public final class StartActivityActionKt {
method public static androidx.glance.action.Action actionStartActivity(android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static androidx.glance.action.Action actionStartActivity(android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
method public static inline <reified T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static inline <reified T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
method public static <T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(Class<T> activity, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static <T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(Class<T> activity, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
}
}
diff --git a/glance/glance/api/restricted_current.txt b/glance/glance/api/restricted_current.txt
index 0b4edd4..6fc7e87 100644
--- a/glance/glance/api/restricted_current.txt
+++ b/glance/glance/api/restricted_current.txt
@@ -54,6 +54,9 @@
property public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Object> LocalState;
}
+ @kotlin.RequiresOptIn(message="This API is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalGlanceApi {
+ }
+
@androidx.compose.runtime.ComposableTargetMarker(description="Glance Composable") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.TYPE, kotlin.annotation.AnnotationTarget.TYPE_PARAMETER}) public @interface GlanceComposable {
}
@@ -170,8 +173,11 @@
public final class StartActivityActionKt {
method public static androidx.glance.action.Action actionStartActivity(android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static androidx.glance.action.Action actionStartActivity(android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
method public static inline <reified T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static inline <reified T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
method public static <T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(Class<T> activity, optional androidx.glance.action.ActionParameters parameters);
+ method @androidx.glance.ExperimentalGlanceApi public static <T extends android.app.Activity> androidx.glance.action.Action actionStartActivity(Class<T> activity, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
}
}
diff --git a/glance/glance/src/main/java/androidx/glance/ExperimentalGlanceApi.kt b/glance/glance/src/main/java/androidx/glance/ExperimentalGlanceApi.kt
new file mode 100644
index 0000000..d107fcd
--- /dev/null
+++ b/glance/glance/src/main/java/androidx/glance/ExperimentalGlanceApi.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.glance
+
+@RequiresOptIn("This API is experimental and is likely to change in the future.")
+@Retention(AnnotationRetention.BINARY)
+annotation class ExperimentalGlanceApi
diff --git a/glance/glance/src/main/java/androidx/glance/action/StartActivityAction.kt b/glance/glance/src/main/java/androidx/glance/action/StartActivityAction.kt
index 902a93e..73b92aa 100644
--- a/glance/glance/src/main/java/androidx/glance/action/StartActivityAction.kt
+++ b/glance/glance/src/main/java/androidx/glance/action/StartActivityAction.kt
@@ -18,26 +18,31 @@
import android.app.Activity
import android.content.ComponentName
+import android.os.Bundle
import androidx.annotation.RestrictTo
+import androidx.glance.ExperimentalGlanceApi
/** @suppress */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface StartActivityAction : Action {
val parameters: ActionParameters
+ val activityOptions: Bundle?
}
/** @suppress */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class StartActivityComponentAction(
val componentName: ComponentName,
- override val parameters: ActionParameters
+ override val parameters: ActionParameters,
+ override val activityOptions: Bundle?,
) : StartActivityAction
/** @suppress */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class StartActivityClassAction(
val activityClass: Class<out Activity>,
- override val parameters: ActionParameters
+ override val parameters: ActionParameters,
+ override val activityOptions: Bundle?,
) : StartActivityAction
/**
@@ -49,8 +54,24 @@
*/
fun actionStartActivity(
componentName: ComponentName,
- parameters: ActionParameters = actionParametersOf()
-): Action = StartActivityComponentAction(componentName, parameters)
+ parameters: ActionParameters = actionParametersOf(),
+): Action = StartActivityComponentAction(componentName, parameters, null)
+
+/**
+ * Creates an [Action] that launches the [Activity] specified by the given [ComponentName].
+ *
+ * @param componentName component of the activity to launch
+ * @param parameters the parameters associated with the action. Parameter values will be added to
+ * the activity intent, keyed by the parameter key name string.
+ * @param activityOptions Additional options built from an [android.app.ActivityOptions] to apply to
+ * an activity start.
+ */
+@ExperimentalGlanceApi
+fun actionStartActivity(
+ componentName: ComponentName,
+ parameters: ActionParameters = actionParametersOf(),
+ activityOptions: Bundle? = null,
+): Action = StartActivityComponentAction(componentName, parameters, activityOptions)
/**
* Creates an [Action] that launches the specified [Activity] when triggered.
@@ -61,8 +82,24 @@
*/
fun <T : Activity> actionStartActivity(
activity: Class<T>,
- parameters: ActionParameters = actionParametersOf()
-): Action = StartActivityClassAction(activity, parameters)
+ parameters: ActionParameters = actionParametersOf(),
+): Action = StartActivityClassAction(activity, parameters, null)
+
+/**
+ * Creates an [Action] that launches the specified [Activity] when triggered.
+ *
+ * @param activity class of the activity to launch
+ * @param parameters the parameters associated with the action. Parameter values will be added to
+ * the activity intent, keyed by the parameter key name string.
+ * @param activityOptions Additional options built from an [android.app.ActivityOptions] to apply to
+ * an activity start.
+ */
+@ExperimentalGlanceApi
+fun <T : Activity> actionStartActivity(
+ activity: Class<T>,
+ parameters: ActionParameters = actionParametersOf(),
+ activityOptions: Bundle? = null,
+): Action = StartActivityClassAction(activity, parameters, activityOptions)
@Suppress("MissingNullability")
/* Shouldn't need to specify @NonNull. b/199284086 */
@@ -73,5 +110,21 @@
* the activity intent, keyed by the parameter key name string.
*/
inline fun <reified T : Activity> actionStartActivity(
- parameters: ActionParameters = actionParametersOf()
+ parameters: ActionParameters = actionParametersOf(),
): Action = actionStartActivity(T::class.java, parameters)
+
+@Suppress("MissingNullability")
+/* Shouldn't need to specify @NonNull. b/199284086 */
+/**
+ * Creates an [Action] that launches the specified [Activity] when triggered.
+ *
+ * @param parameters the parameters associated with the action. Parameter values will be added to
+ * the activity intent, keyed by the parameter key name string.
+ * @param activityOptions Additional options built from an [android.app.ActivityOptions] to apply to
+ * an activity start.
+ */
+@ExperimentalGlanceApi
+inline fun <reified T : Activity> actionStartActivity(
+ parameters: ActionParameters = actionParametersOf(),
+ activityOptions: Bundle? = null,
+): Action = actionStartActivity(T::class.java, parameters, activityOptions)
diff --git a/glance/glance/src/test/kotlin/androidx/glance/action/ActionTest.kt b/glance/glance/src/test/kotlin/androidx/glance/action/ActionTest.kt
index 763fe17..5dcc349 100644
--- a/glance/glance/src/test/kotlin/androidx/glance/action/ActionTest.kt
+++ b/glance/glance/src/test/kotlin/androidx/glance/action/ActionTest.kt
@@ -18,6 +18,8 @@
import android.content.ComponentName
import android.content.Context
+import android.os.Bundle
+import androidx.glance.ExperimentalGlanceApi
import androidx.glance.GlanceModifier
import androidx.glance.findModifier
import androidx.test.core.app.ApplicationProvider
@@ -44,11 +46,15 @@
fakeCoroutineScope = TestScope()
}
+ @OptIn(ExperimentalGlanceApi::class)
@Test
fun testStartActivity() {
- val modifiers = GlanceModifier.clickable(actionStartActivity(TestActivity::class.java))
+ val modifiers = GlanceModifier.clickable(
+ actionStartActivity(TestActivity::class.java, activityOptions = Bundle.EMPTY)
+ )
val modifier = checkNotNull(modifiers.findModifier<ActionModifier>())
assertIs<StartActivityClassAction>(modifier.action)
+ assertThat((modifier.action as StartActivityClassAction).activityOptions).isNotNull()
}
@Test
diff --git a/gradle.properties b/gradle.properties
index 723390d..58fa1e5 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,5 @@
-org.gradle.jvmargs=-Xmx8g -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParallelGC -Dkotlin.daemon.jvm.options=-XX:MaxMetaspaceSize=1g -Dlint.nullness.ignore-deprecated=true -Dorg.gradle.configuration-cache.internal.load-after-store=false
+# TODO(https://github.com/spdx/spdx-gradle-plugin/issues/16) remove `-DSPDXParser.OnlyUseLocalLicenses=true`
+org.gradle.jvmargs=-Xmx8g -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParallelGC -Dkotlin.daemon.jvm.options=-XX:MaxMetaspaceSize=1g -Dlint.nullness.ignore-deprecated=true -Dorg.gradle.configuration-cache.internal.load-after-store=false -DSPDXParser.OnlyUseLocalLicenses=true
org.gradle.daemon=true
org.gradle.configureondemand=true
org.gradle.parallel=true
@@ -13,6 +14,7 @@
org.gradle.unsafe.configuration-cache-problems=warn
org.gradle.unsafe.configuration-cache.max-problems=4000
+android.lint.printStackTrace=true
android.builder.sdkDownload=false
android.uniquePackageNames=false
android.enableAdditionalTestOutput=true
@@ -66,7 +68,7 @@
# Disallow resolving dependencies at configuration time, which is a slight performance problem
android.dependencyResolutionAtConfigurationTime.disallow=true
-android.suppressUnsupportedOptionWarnings=android.suppressUnsupportedOptionWarnings,android.dependencyResolutionAtConfigurationTime.disallow,android.experimental.lint.missingBaselineIsEmptyBaseline,android.experimental.lint.version
+android.suppressUnsupportedOptionWarnings=android.suppressUnsupportedOptionWarnings,android.dependencyResolutionAtConfigurationTime.disallow,android.experimental.lint.missingBaselineIsEmptyBaseline,android.experimental.lint.version,android.lint.printStackTrace
# Workaround for b/162074215
android.includeDependencyInfoInApks=false
# Allow multiple r8 tasks at once because otherwise they can make the critical path longer: b/256187923
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b706d0b..4d3aebb 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -28,7 +28,7 @@
cmake = "3.22.1"
dagger = "2.44"
dexmaker = "2.28.3"
-dokka = "1.8.10-dev-203"
+dokka = "1.8.20-dev-214"
espresso = "3.6.0-alpha01"
espressoDevice = "1.0.0-alpha05"
grpc = "1.52.0"
@@ -37,10 +37,11 @@
incap = "0.2"
jcodec = "0.2.5"
kotlin = "1.8.21"
-kotlinBenchmark = "0.4.7"
+kotlinBenchmark = "0.4.8"
kotlinNative = "1.8.21"
kotlinCompileTesting = "1.4.9"
kotlinCoroutines = "1.6.4"
+kotlinCoroutines171 = "1.7.1"
kotlinSerialization = "1.3.3"
ksp = "1.8.20-1.0.11"
ktlint = "0.46.0-20220520.192227-74"
@@ -53,6 +54,7 @@
paparazzi = "1.0.0"
paparazziNative = "2022.1.1-canary-f5f9f71"
skiko = "0.7.7"
+spdxGradlePlugin = "0.1.0"
sqldelight = "1.3.0"
retrofit = "2.7.2"
wire = "4.5.1"
@@ -98,7 +100,7 @@
checkerframework = { module = "org.checkerframework:checker-qual", version = "2.5.3" }
checkmark = { module = "net.saff.checkmark:checkmark", version = "0.1.6" }
constraintLayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.0.1"}
-dackka = { module = "com.google.devsite:dackka", version = "1.3.1" }
+dackka = { module = "com.google.devsite:dackka", version = "1.3.3" }
dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" }
daggerCompiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" }
dexmakerMockito = { module = "com.linkedin.dexmaker:dexmaker-mockito", version.ref = "dexmaker" }
@@ -167,6 +169,7 @@
kotlinCoroutinesAndroid = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinCoroutines" }
kotlinCoroutinesSwing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinCoroutines" }
kotlinCoroutinesCore = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinCoroutines" }
+kotlinCoroutinesCore171 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinCoroutines171" }
kotlinCoroutinesGuava = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-guava", version.ref = "kotlinCoroutines" }
kotlinCoroutinesPlayServices = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-play-services", version.ref = "kotlinCoroutines" }
kotlinCoroutinesTest = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinCoroutines" }
@@ -174,7 +177,7 @@
kotlinCoroutinesRx3 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-rx3", version.ref = "kotlinCoroutines" }
kotlinDaemonEmbeddable = { module = "org.jetbrains.kotlin:kotlin-daemon-embeddable", version.ref = "kotlin" }
kotlinKlibCommonizer = { module = "org.jetbrains.kotlin:kotlin-klib-commonizer", version.ref = "kotlin" }
-kotlinMetadataJvm = { module = "org.jetbrains.kotlinx:kotlinx-metadata-jvm", version = "0.6.0" }
+kotlinMetadataJvm = { module = "org.jetbrains.kotlinx:kotlinx-metadata-jvm", version = "0.6.1" }
kotlinSerializationCore = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinSerialization" }
kotlinSerializationProtobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "kotlinSerialization" }
kotlinStdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
@@ -242,7 +245,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" }
@@ -253,6 +256,7 @@
skikoWindowsX64 = { module = "org.jetbrains.skiko:skiko-awt-runtime-windows-x64", version.ref = "skiko" }
skikoLinuxX64 = { module = "org.jetbrains.skiko:skiko-awt-runtime-linux-x64", version.ref = "skiko" }
skikoLinuxArm64 = { module = "org.jetbrains.skiko:skiko-awt-runtime-linux-arm64", version.ref = "skiko" }
+spdxGradlePluginz = { module = "org.spdx:spdx-gradle-plugin", version.ref = "spdxGradlePlugin" }
sqldelightAndroid = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" }
sqldelightCoroutinesExt = { module = "com.squareup.sqldelight:coroutines-extensions", version.ref = "sqldelight" }
sqliteJdbc = { module = "org.xerial:sqlite-jdbc", version = "3.36.0" }
diff --git a/gradle/verification-keyring.keys b/gradle/verification-keyring.keys
index 9d82f9b..7ddd517 100644
--- a/gradle/verification-keyring.keys
+++ b/gradle/verification-keyring.keys
@@ -692,6 +692,57 @@
=Mtq5
-----END PGP PUBLIC KEY BLOCK-----
+pub 13D979595E6D01E1
+uid Maarten Mulders <mthmulders@apache.org>
+
+sub 8B794AD8CE1926C6
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBF8LXXYBCACuy3HnrpWl7boi98G4wG1ZrhBiYImyfQd1M+dvH3GF3Vqt2NYv
+Nv8vryhUkMi8uu233KrYx2/kVK0RomMYWtUrSbQIdykytd0/VsoEk82ysN21ld9P
+PfnNF7L0egnw1KEhcPzghqOsEY3ahqgTYqoiHLD/isLifMUJkJuoLlGx4XfQdpcy
+RrSyjzf4/7XUYaYZ5OkhRHCZKGy75PNwibalNMm8H3+paqbwextv3PswVXOZWR6o
+uyeiPgoemoM0T2ZcZdKIxrUZiVae8HJltyEca9hjqQF7zzofiTXW3qS3J3bPsylO
+lPLr/NZ3vyUtuGc3V7nuUIVvpjy8nAzZOtGrABEBAAG0J01hYXJ0ZW4gTXVsZGVy
+cyA8bXRobXVsZGVyc0BhcGFjaGUub3JnPokBVAQTAQgAPgIbAwULCQgHAgYVCgkI
+CwIEFgIDAQIeAQIXgBYhBILJ7A5SxHqTaoSeARPZeVlebQHhBQJghv3xBQkK1cR7
+AAoJEBPZeVlebQHhmvkH/juGFbuOfBCv7bV4uzpQEYdHZ5y4SuA6IQYw65gGaee3
+qVbpnd/Qau77fAOXVEYhRrlOpkLyfseTMavCl2KiR1x56y3k3FsOaH7FHoiPLBP4
+2h9//ZOB2nEN+cSg4xRsyiknRCFhjls1VxKuI/kYEaXVuTezccpgj+eUtn8xfvm7
+Rv+UeJyd5Uln0oGoPEtaltEzvnuHv4iKQm+4AK7+LAqv5irOC3dhn5K+zRWzJq2V
+H+AwsWZtiS5FpjcV2Jt+iWANTkdK5MLuugOGGcqsbQsG5rZs+xMb4uTnBwo9hF2W
+k1a0uYyCqC7FV3BeFLze6qDDN+jDyOn0MbWPKPsE1EOJAVQEEwEIAD4CGwMFCwkI
+BwIGFQoJCAsCBBYCAwECHgECF4AWIQSCyewOUsR6k2qEngET2XlZXm0B4QUCYIb9
+cgUJCtXD/AAKCRAT2XlZXm0B4YVpB/99S3tG4fvPU4QsRjigQKY3VzfKhTi9lzgo
+H8FvpmUqnU0Ag1oUz9ZixZyNTU6LFoW0vwLraYR9vEkz2MU9M8LPzk1R/LbSk45Q
+apoXECuJ8Rg24cbdy3Xrj37f1hFrrmByUGnhvITNbBnKpPqucPO5LJIqI1H5tJbr
+RZ+27XhVGL0qo/5xOlli4PlSdx8jESu1X9AVsb5NbN1iPoORt1HwwK2Mx7sqwpmA
+gZ70tONGYLhAEt8AIiA9T9rFCQmJ3NqKxpYKsD2eWu8bsijQy7V31+r+TMXVpRqw
+8VKcHLOslZ1VxmVLIje79K75jIh7v3Q46xNxA/LnHVuV4iTksRDLiQFUBBMBCAA+
+AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEEgsnsDlLEepNqhJ4BE9l5WV5t
+AeEFAmB7OsIFCQrV3swACgkQE9l5WV5tAeGbnggAkRlglEy7aEx5jCZueecm2cAG
+RjEaIDs7PNG4LYWUsYryVnxSxnHYPit4NcOMZwrs2vDSehp1+VKiJAG9i5lk01+O
+cJHoLur6Lc2FpdEvEh8AC3nJ8nj/WuRG+M0VB2aB2jDWo4eAD0kFOxbdMWXMaUe6
+ngQtX0TYm/OFHPrzdkkaBMeEKO6JZ5ktJwpk7Z7HbxYg/XYCXeLIkrU9UkMt3g5X
+FnTrBeryTKLvEPFFr3foMGLS7YWgaM5VtRMl7t1ViLXp2J5rcvmB8IsZSZ9XfBNQ
+p8HR5sxTrhQNejgiFc2ep87k5soH5xQCs/DoOkIJB1dxR5ww8Nbhr8eaCGoOdbkB
+DQRfC112AQgApyhKFxKtBxc6x6m0m4G8LGB16PK0ZtuUvRUmQ9+VffXojLQI53p4
++lN+m7ocQSogOQ21EysQ01wQ9mFoZymyv4E4YmChvBTPnSFZ5jkmphKIAbT5G0O5
+faK7Mlvmlnr2To8fwxTjyCg0eAtJ4NfNF6HKyli8fx54T8tOm9qSxXYri+AkQ428
+F1KUapplob9JOsSfnEiMuaeL0C9QjoCXy6bS5lstSWX6ZeXCIYtwVNFldjy7e/Pa
+rPL1czG1d5PwCzDVXU76sqvvipdY0kcmf+9sHsT0bHxC+vpmzC0e1C2KDANaI5Rr
+UtumeL2AA01azwKtjpi2+xfsGUiJB8NPMQARAQABiQE8BBgBCAAmAhsMFiEEgsns
+DlLEepNqhJ4BE9l5WV5tAeEFAmB7OnoFCQrV3oQACgkQE9l5WV5tAeFGjwgAo/Qk
+kB8s+mEHCbNP16ScQvbnDcDCjqRmKRb/YVqJHVLWSa0sOEHCayssialUIJ4X+FNt
+dPzONwfzqD1MtAazl1+Vti/LpOKEUwWKEB/8h/DwOtFKeobomWlyW8Aq72EHmc0W
+MbhVcmvi2h70G8f6vEwSN4VwO8etmNu4HoX09pBo3eCgH6is/x9v9ixOHLddCWmy
+bh6GPLcIDvGjJZ8xHNTFlI/dhu3gnrHqAaXQQ+9bzv95Z4SG5Ou5w0O1W+A7aUCU
+VFqKJKoHvVsSYp1NK5Wjr6DJi7QqgDSidmx1abDsuiZkc5jmU8GOQTZaFQbcA3ej
+EFdqDmDrjH4tGHiSRQ==
+=uxEi
+-----END PGP PUBLIC KEY BLOCK-----
+
pub CB43338E060CF9FA
sub C59D5D06CF8D0E01
-----BEGIN PGP PUBLIC KEY BLOCK-----
@@ -2094,6 +2145,53 @@
=RGVX
-----END PGP PUBLIC KEY BLOCK-----
+pub 4DBF5995D492505D
+uid Sean Leary <stleary@gmail.com>
+
+sub BE0F021FCB5F68A0
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQGNBGBFmccBDADIusjFY82nMHFXYxY1b5eIWtyaXTQxv/bXfjR2Yb16dURgFjai
+OeuYzapF7vVqNV8/H7Sya0W9z4OWf0ZttWhtQFcmhF90586OArXEikKcFgO8EL+l
+u3CrufcWEsbr8P1EKRWJnfdZ0wgJlvvJ7HfF8lr9Wu56vVgfohdgsWfADWkUbg3X
+XGwyxfYmXtvrSUEsuDwjzNvlbD5GijvC9/T0TeQosfaX7AyeXXwbxolFGFtxitBz
+Afkym8nQCOF5jfSj7fzafmhtngQBfeenSsoxpkTxOx6+SdVMksWswBBueQWTYBCI
+lULMmuRRkCHWgQ9+LDu3eypqCS9k0RU+EXkgpMLK63QYWj3pkZSdnR/HROTDvNTc
+DCoRHWZm+ytdQVefFNpLybnMJacfdle2v8QcSgp4utplhz4sNn7/lyis4cMpvqxL
+bB4jzNsd4jqvgBZUmjoVumppHhEqnj5HrMoP+Soq7zNgCFXVDazxWaKV7G666yVL
+Kfh7wjV3cJmdqAkAEQEAAbQeU2VhbiBMZWFyeSA8c3RsZWFyeUBnbWFpbC5jb20+
+iQHUBBMBCAA+FiEEhmFs08TwgD5zN0pDTb9ZldSSUF0FAmBFmccCGwMFCQPCZwAF
+CwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQTb9ZldSSUF3wMwv9ELzyLLCShZau
+oGXUmf1OMbIKG6FBIdCLKKV1KE/gIysB2Uzl/qFku3e8Q5uzREj1p1E5rWXc74dR
+dEoPOJfbZ/Obcsy+zcdFaVhqKgYBOQh+yT8pKC5BgHnjhQbBFVWBSCbGaNNbRpNh
+xFlq4cofRLsqrNvVQkWdWlxerOuKz6jEC97RskPZpsg5xlEt/4iTQhFujlpx2xZW
+TCnc/MhJbDJRzHvc5dnEiqjvBlA7WMGl/q2qU0fMILDwmdGYe9z0DgQHXQ4WpBjC
+8AlSr9kBF+rE3L2N6moZb5Xl4jq6NGSGafKRAbtVnh9IDF3xGjzTLwnqCDMYBB40
+zun4eTAzf24ZHQJSSsKziMti5fXOxJPrmQeiPX6ncYmTdmrdzLeqcaPZdruxBxgQ
+kM6wP33BE2h9DF6yOAeyp69nrqdwRKn7alk68ARA6dFplh/o5nt9GT5L18ahbeXN
+iaYiZNfe/T8Jj3BlY82L+bJ5+e4+AGFLnFqa6EyayhX51aAxEAlRuQGNBGBFmccB
+DADoQoRd+G8n4axz1k8ynj1Xl6ClWaEOP+T6c0GZ+/MjsUtzxz/RXxKQdgxvz7EC
+NHN41U/73SWisDBuYppUg/72urhzL9kPs6ePq6XMrV+1hWs4oK8F0ECMw6yn80HI
+HmtEIDMuzZkjtxfsBPYpcKnoNDtVuqPxsMmmsetutKfInXrhbMWOxutvxIKqBtVL
++7Va18WdNIXPiS3K8kdpWa59h/wgWIb/GveVnqWACEvkaRyCeZrnWYqznrM9lJDt
+FDNFPDh+PfGiuYsL8D8sT7U1eh9K3ms3KE5z63Ic5pjJuULsMgFgfhnfZGAQqLSW
+2wsBWJEmX2u0c53njT5KRZRxvjPU8WvKQGMMrBT+ddyKRFj3+PaJqmTCRy04b0+R
+QC8ZiIGeYFK+JqAq8e4bDyXSVRhi30lpo38CXVry/InNmnOxqWcRJF4xw9MaJt/T
+AO+/IZTgwRSX+1IH8SW8928is+5LLhvWKfSApZb9D254NqvFFO15UDxIoC/chcQX
+V5UAEQEAAYkBvAQYAQgAJhYhBIZhbNPE8IA+czdKQ02/WZXUklBdBQJgRZnHAhsM
+BQkDwmcAAAoJEE2/WZXUklBdfmkL/1kUYZbreYCriYE4kQteZ0narPcGmAEJVxRz
+KBIMhnMF3r+kVBq1QZU4b3bI72YDj6MEfRcMsNtd2aLFfsnlHF++fyEhxtga9Y3t
+n4kuGb03sUE0YQhYqER70d4jzizMrMy7x98bYsTK82IdS1tBggzGAWX+0NsMhoxT
+ydXjkUenDd2/Kdh2PSijLLvwSNb1xTbTX2fpzD0bmwLQ4ZW62nYpRpZ9uPHZj0NU
+SHd069EtlJQnY7b26AOFVWghL0qshq2AeVLdbCjzZ1HTgzf8Ow6runKpYRmeHDGb
+hOXpdPlUB3QKB154zkYYSX4U7t8yVZTc5QwkL0f1U2C4N0f+xIwPLBqHWcOXH1B2
+SAILfV8oxpXbBnbHUKoi3C1nHGJZbC2DHy/1veXGWRSOZVmSu4Zpoimb3DVP/jAM
+0OqTDNdwq4qS9nNs1kB4+DsACLWnwjVPQh+r4ejqH21EwmyxRCq5gX+dSFnfiXn5
+nGg4NAU6QuXCv40L42QGWo2w0iHMVw==
+=84CK
+-----END PGP PUBLIC KEY BLOCK-----
+
pub 6525FD70CC303655
uid Stephane Nicoll <snicoll@apache.org>
@@ -2187,6 +2285,221 @@
=wp39
-----END PGP PUBLIC KEY BLOCK-----
+pub 1A2A1C94BDE89688
+uid Michael Osipov (Java developer) <1983-01-06@gmx.net>
+uid Michael Osipov <michaelo@apache.org>
+
+sub A3F393B5D034A0A3
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBEzxj6sBCADGV4szLvjBwrAOKYWw3efASDI2yo5Aq4oevm9cUB4G9G/D/fuR
+XhodLaG2smZLd8sNafWTSbPHswsZtMAjHGzka9Uj4Ow0etl3+kTh0DE6Loezkj7s
+nut/6JJ8RGmLf+NqJJhxS6kCCAND8GnNIu1gGY+nZ0rVO7ZkPwtUR1H/MnoZ3cC1
+6Ual63UOjgsNhmmaiCFyedzxitUVdGqeYktPt/rp/NqJ5zPs1SLX9vbFNTQ5iVKw
+EszDiYSOTBSZ2kVlygGD2JZGIa+uQ2yGqVJthXXlcG8sineNJAPnkNyW8Ie2uYeS
+VFgXoFPJDWXYsFC4APNIAdV2x6+OZybsrOzNABEBAAG0NE1pY2hhZWwgT3NpcG92
+IChKYXZhIGRldmVsb3BlcikgPDE5ODMtMDEtMDZAZ214Lm5ldD6JAVgEEwEIAEIC
+GwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAhkBFiEEaoFLH4acK76rfLcnGioc
+lL3ologFAmKcaZoFCRltQO8ACgkQGioclL3olojy+ggAlvYoTPTCsOiFbbxTGofp
+6AqsTVyDE7p2wma0tqwuuD8bHqE+eSvBuRfr08mrDD10MTIlMD8Iof0fhDB1ettO
+d0+fUHioT5SpPFGO3Lh6veWn3szDYs74seHOJuJEThamKAltYJZkTBg2BeRqY8qZ
+m5SJJJ8OoPrMoAFpcSRsa+VteGw71ZnwnuiHvWWbr93VosQSGw63F56q4FE67JRe
+SgpILpahCr370oRqKTGGXUtHt/mGcsr0GmHc3esDH45YsIiB+/RxnEusAkt/QXTx
+D1T1cRMapE0Fq+IhFW7UcHi9jsdO+3V0g1nGbeElLgLDcuUCiRRv+xMrop5xFGty
++YkBQQQTAQIAKwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4ACGQEFAmC33G8F
+CRWngEQACgkQGioclL3oloh/ZAf6A/ztHZSBBMLHiO4oeFun/xzz1NNvf5tB3jLY
+41RQZAvUwNPGtUe7Pb6todkdC92otEampNtnjNss12Wn4kpB9q8km9ZxZQxfAWnh
+sDvqg4uVj2dFw/q0WQXAjwXQgruABALFQoEK/ERA67YPIHhZDiHZt0tRh4c1qF/p
+yFoip3MMkUJAaQoEtCuy7hMG1SsCvamBGdFiw8Nqf5mv1BokRGSGoffhA5u/M0np
+G0ZYkuU3089N6c5O8nHzyZBup8zgWyq+bqV2C/WZGZroQjIczw1i9zYKuUAug6Qx
+pm2svsmKQgli1mup1oOS0jqOww+1d8PAHD3vNcTNYP23Vh/jWYkBQQQTAQIAKwIb
+AwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4ACGQEFAl7RZtAFCRPBCqUACgkQGioc
+lL3olog29AgAm97Fr2vD9sZ2Tjl6O1uDq0US7h4k6VL6fcUy1zmcFKDhxBphlALS
+HjPTl0qwQSfJD4+HQKl+XqVvbeLjWOpMS/7fsEYePE25XEwpVt8KOXYMZda9xMwF
+ksesSU+r8cr+WC5iEHGnVluQ0vh6h8bQXYnIHaFDmEFZoEMFN5frjtfwxs8VSdsc
+E4LrH1P8qBecQ8PkshEFqVyUqK4f5Qn6EbUkbpjmBwTMnQq7ztqCNpMuCFZJ0NnE
+82GbPexHjSIPYo2NT85YyLtKCitgFDFKbOOXnO20JvlGVfTQloMtsynGhhcMeLeI
+q1jqJrEcTLcyZqjXAFlDdxbuPihM0vEtqIkBQQQTAQIAKwIbAwYLCQgHAwIGFQgC
+CQoLBBYCAwECHgECF4ACGQEFAlzvvcsFCRHfYaAACgkQGioclL3oloiXIQf+MKlg
+tw14PV5Eaf5yLHg5ByJNiyQlHV+HYGYy7lcgxcDKkYEU1aAW5COtOXlcLezuXfV8
+UiHOeFevCRys3KcbXj9z2pgCzvZTB6A/kpEcday5NDMJK+iXCWmIKVtdULTfK3sK
+ErY4VqPvGuuq7J39KvGpXCjmQzi/xM1UtjEdyhc38OBJycXdibciJ4GIsUMebjXY
+aUGw0/s0ZjwC37EwnbjRVnGzzyRrAvCRzUI925bprzNbNoNvj5BzXyEqONs3aLJD
+m0K3sZES+VczCB3uwWNG3BObcxnysEjkeeJsajs01dlpm5VQofa5ySSSdPkeAhdA
+Er0tWaMFJcrmshocuYkBQQQTAQIAKwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgEC
+F4ACGQEFAlsF2L0FCQ/1fJIACgkQGioclL3oloiYvgf9GvYF8hH0qiR5u1f+PgGn
+55WatuqjnnbQ0HvAAVAcdlw8WRUPFRWAl4Px1ocMjJnjok+p1s3IUCp0Tsiok68l
+rw3KZDM/Za798OZe1OIqJajPR4eJpftQGojfrLmJl2tKUiO5wseqR9XQ8owfshXJ
+otoklJwZHE7py0oPiNu58Zj/fgAMfxML3DTq4PKtwAVZKPV2ablluC48L8ZxlXrJ
+LO28SH5kUtOrBjw9dbEA7sCGkNmoZD0dg/xYRrEFHQC1Gm5zKq8kAlY3y5E8m6Rk
+6OK3EDoWf4K8YMOq5kmT/gJAuUK7ONe8CEXcHzhb3Sid6LfTL7Qlx4yuHTJbcBhI
+yIkBQQQTAQIAKwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4ACGQEFAlkTZpcF
+CQ4DCmwACgkQGioclL3oloirnQf/d3hl7BnCNCfI5XBRGT1BfDmzb58Co5GyBBbk
+sgrDY2C2qdoxZAt688DCYJTssDMXWyONyaxZsogXV3x8M2WtLM/9LTHOQhZ7UH6h
+4PY+vy2oN4GFBf7kRoauUDE8R3uJWTN2yusxFNmpuYibamrlsAQOxUy+UyqK0Z8L
+jSgsW2lHsLHcSOHcNzV0MkUYlH+Kdrahy3FysJupEvPYMJuc3UIkX+bk7HJP8O1/
+J8HXf153Ipkq9/LWqPB7wCm77lTR9P3b2Fcv7SOXwFeFUwavoRpHwzXjSiTcl9PF
+50bJngcWTUOG4ow26EfgEjnIuUpw/SoDxUMG/gogtEsR3TIBXIkBQQQTAQIAKwIb
+AwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4ACGQEFAlc3B38FCQwgE9QACgkQGioc
+lL3olojJRgf6AspowCAoDhd6hB6t0P84fFbbJnTy0dGY6h+oznZ5OgOpk9Oy/WH5
+U/DA12BNe/x/ec4onoVOGvIWdiVoUwouvc/waTqRw0KrxZ5tX9WNC/Zp5hJYE+Lp
+lirQYilcKt1GgYERAC6JukX6WPrGNMD8df43+fu3Vg+rlRd6shoYM0QQ2PdQxAvt
+YhnsG5Zq2TbhEQBM6e/9Jx5F/DERSUdtcxr5H0RHRIifVJAFx7nDSNFaDzlhiZ/5
+CzB2MooD8Oa2L6snfLbNvE+3HPnZ+411E461PlheeGUqu6SeKTrCn9k7FDapDDT6
+taEULmb440vBtgItNdkSgsVzZqhH2HkqvYkBQQQTAQIAKwIbAwYLCQgHAwIGFQgC
+CQoLBBYCAwECHgECF4AFCQot0LcFAlNdEg0CGQEACgkQGioclL3olojf1wgAxE6m
+JEki3uQh7iFYsXo2iN5g6IWxOBPmjSoNpHPEGW6U30bJDLigALQPCbPp3wC0BYZH
+Ocwe7375thoILHmVrLzOq4Uzt449alSuKm22sfYouxiBTNqaDBMQDXhbUry+3Cnq
+nmf1fwv7AChdKhhPVSz94z5IaeeTxJzEaBwEdO2m4ZgJhx4YSf/68ueBAW6QaunD
+ldZ6fctKQfdS3pPVCdiYp4+DDdPBJD/eh1mR12VUHgdt+dnTtDJJtsXtvXN2oUyY
+nLtO7Bc1UhbqUesfimBqNRn0ojGpB8heF8zyDfkOBfYaqtswgPVQ5CfHJbuT31FF
+j5fUOwc8e294n7iqwokBPgQTAQIAKAIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgEC
+F4AFAlNc+WYFCQot0LcACgkQGioclL3oloh1mggAj3+JdFCp9bpUdaLXKmJMkcUn
+pguvw7yLksAprQtS+rEW6n5qH6tqkvDwVbL9xhnW/1SCv1KFJz2VXuT3znu6h+Va
+dUNm5H2VGHcvSo4gRbK+oOWBCU+kl/Fcz/BiPI7783FDKsmIVZAztrNO1cwqYTl1
+Hh4NwRPGCzB3NnraFM/qJijGTQ15nr4EkK2tQ++DWd1x9cMG2QNqYZr7jtlDghEW
+ZQNLv08QQd2yrmnqgaUHbnTBbJbEIuOVpYlG4iVdli3gsTimv8Z3O2/3JhYr7lQU
+/7FLroguJLuMcQmx8FeKsZXzCuA32h6YrP+cBUDsR+PTbKT5Kop1tEe0BRwXBYkB
+PgQTAQIAKAIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AFAlDct/gFCQXMW8kA
+CgkQGioclL3olojNNAf9ENJq8IVjjGsiZIUUOHhGh2v01F0M772ETHUuopt2yYmx
+e6Yl8DtuaUZvuwx1qiFx9kS+0A+RkltUASajLwgoJX7Y52mupKV7kW/Rk9TQT3s1
+VQSRf8EDR5HZfzuVvaZGA5pXkTcFZg3xcy2S6aGMEzPEBme3KTO+9TDqwPQOiAOa
+AG1qEJCJMKqjgnq8TelDou7H2KeP2vA2i+wASUvuP9ZwrFSoN2ZwHQ8Y4fsC1/9X
+jAcXdEGpwWQFs210n29XjLRvFFfxPDmyoyNHMPyxqp1HwExog0PabU8k5nEKE2Yj
+V6Wf6irrvCVOx+pftkYLW+6RuMPYUr0OOYuIZpyW7IkBPgQTAQIAKAUCTPGPqwIb
+AwUJAZixAAYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQGioclL3ologDIgf/
+fBEwBhrgGEsabTcTTmMCmfXMIElrFBIp03yem1czJ4Z7QnEviyxe+TYbdGC7rFa+
+vuc6NAhtY2RqtndQnTrIO4sCt2WW30CFzSv/KZhu53YKv6YFhGaplQJgADVCuR6V
+pzDtvM/ZCRchYq6MDXhk9y40t4WRXALVAyVibgCwKQjwCneRNFhU//FdmxfqAyon
+ig5wga77wu79TwwazVBS41lgTEYEIvVbLx1ZCR22LkgpsTHKjeBbpCksyak1ky/Z
+WzU3lr2U/ADccetUze+BRpAmBJM11SycFG6o+ZhUhTxQsMGD0PVVVyfh1/5kMm7e
+CVTPwB9FRWRQCzl4A+t7SrQkTWljaGFlbCBPc2lwb3YgPG1pY2hhZWxvQGFwYWNo
+ZS5vcmc+iQFVBBMBCAA/AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgBYhBGqB
+Sx+GnCu+q3y3JxoqHJS96JaIBQJinGmrBQkZbUDvAAoJEBoqHJS96JaIqBEH/AoH
+W0qcJ+G9YraN6TPMjCVWH2jsCPz6BvfZraTtqIazlUWaqvO5QcgFU8XnxfCsPJ1E
+YsSFdqSQmjTCx6vK0ZYvMUnFCLaIKhOEJK4HKLcgkzpuiBT4EH6rj/9VgrT9V7Tu
+dwCHi2qen5a2E1QxdCsZIVBrd0KCDK5ty3L06Inrmg4f2tD1f/OW0j3UbiH1QBJs
+n12htZxA1+BdKLBRComEpVNyUC4TQZIT9yygIElORkO3nE2imt1ZZv4+LxmPsqH2
+kw01O1wfElQWT7piJr0Ekm8er4ijtBoE0uOCLP2bE18p2kkuf1JoW+O1EGF2p5rJ
+aeCSFRNUlnk1SJ05tJ2JAT4EEwECACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4B
+AheABQJgt9xvBQkVp4BEAAoJEBoqHJS96JaIwegH+wXPQAGFidWUqrIlshn7zvRf
+AFeuvbshvFq3Ux0E8AP1KKtW0i7TQboNARFdLUHW1S59rOAy/+39UtHDAENfuDKb
+MUx/5+lWEN4xZee5VtTHNa8kDqKcKpnXtI1uhpH1x3Gk8jV3s7IXVzqhPXJpW7wP
+wy2/8Se0PSATOhVruZF388HFPVI0TR+MtAAZEpxOndvpM0vqqGyi9d69ZtFV4WQZ
+BpwCtH3tl90Z2PAcq6ydhoxnS3+e9uXXr2RZdjlgHRsMKabcKMR++4YgtAabELuh
+HLYSDC38w0r2cKZy8WevzaJFb1xdcB4fzsl3N7RlQv9GZEcZhqJW/hSsrx7FS3WJ
+AT4EEwECACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheABQJe0WbpBQkTwQql
+AAoJEBoqHJS96JaImrwIALwSGR5chRsC3S003HIdaryTVO1wXlReMAeD4c5rG5fN
+OnsXwXxoluMYvbQnTNxnfErCGD1nfickWfrSpUSTZ4gcfCh3QfX5l2j9BQof4EQA
+b8WXEmdzB/ranGppGQM7KVsE8kq5g9rYJoGrBNorlYrvEEymf+kF0L4l5uSc47f5
+JMWIij4yCEWxAoYHxrnl204A5JIo9rAYNzQ8eeYYe5R/Pa5BC1fEs8EbM6n8bRMX
+XIbnJrzT99LGj7v0LyPBoDC/8hPhnrCTRps4D3oiVI2eMX13XATBphT6Gysdkf8+
+6FtC5kCoGCIZUSs6ibxgs+83DxRm38Ifzj0NJU1XXSeJAT4EEwECACgCGwMGCwkI
+BwMCBhUIAgkKCwQWAgMBAh4BAheABQJc773LBQkR32GgAAoJEBoqHJS96JaIDKcI
+ALX8tvbSpvFjwB+D6/A22qOHnyHd5br1+W2yCKtU96MJsx90Sx0WikQj4l/ZoLpS
+IaWcZCI2OsiACRrIE73zn7hNx3dNkU+Hj3jj52wmGjv5uuJcNGA/TkWUdIpG4YTe
+vULvtAeqfG7YLFdvuPmhrKdvDPj9e0I0gY479zdHJ9y8Kxtd1hJ6p23jpiA1heqC
+wvICgd8EhCcSl9b3SLVLtCr9idQg8GBbV1q5KbxX6ocx3uYq5Cn3jJ8ANR4G+Jnj
+ccfTokZaaH6hQrkqyRXzXWJzBHxdGsoIVqlYeoAsY3lBizRn9QhhTlY1m1fBTKLW
+lH58e8WbGRFJuOKXLoDzXxCJAT4EEwECACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMB
+Ah4BAheABQJbBdjdBQkP9XySAAoJEBoqHJS96JaIAwkH/RdJNz5W6W5qrW/34EUm
+j+H1jN7gyb0Pp0eB4S4cetDLEUqXCa114zEiU0HEq5jhDFDCCxfhbwH22JIAZGLs
+cE5Fpzp2yiIMWSwwfUijaGeO3gTFkglQWvnWxhwsbq5BYeogPjPNCPibJ+qm8E9M
+qQXXjbnuodjdb9JFYse2M+Q+Rx/5GLcqOQM6QCyYz3ucu0zRNs41mrqewR9BkLLl
+ilFkvT6/+sR07un21VTPz41SxAimQQeGkgPKx1kVcH1bVsXx7tBNamVdhPUm7Wa9
+qLGk2u8wYGT+oERbvT9BN416r/cigixYk+AdsqrdNOvzaBVuf2Kdi5B1bLF01H4u
+xIKJAT4EEwECACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheABQJZE2arBQkO
+AwpsAAoJEBoqHJS96JaIY+QH/0LAblRWIi5s1Jh5tFumzjlVOYCYWf1gH5bUg9u7
+VPMQr/WBUmfDuDH7vjRp5tdkIOaQ/UC40tysuMgXC6ppDVhofaUffOVeTbjZMcGy
+9zBvexUJLCce5bMuTE6q5G1SHDkeijteA8GJA/98VzU7vGEWjnta8lIvK7IfzlCQ
+WlJE9GA7gmJDOOR6Nj7CXCIIgJr18rRf/8jaZp6ipI4oRZ+qK53yvhAU6vLvfqu8
+w6uuNMPX3cRVEGlEz5l4JBlJ+b4MfoG1MdlfQMqHwIlwGMX9kr8s4LjcHveA52zJ
+/7/NS9Nu+h8+xnLmPdBPZiq1AXug9YMT0HCn8104uHhEEMOJAT4EEwECACgCGwMG
+CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheABQJXNweKBQkMIBPUAAoJEBoqHJS96JaI
+NSQIAMNiyOn92XhnKA3vaonxmnkRujP4UP52Rv2Vda53dtColqQwylNWr/6ielS1
+o053q0+3T4/22TlrTtmq1aQQy4HrW/oLhGTZvpAFD+DEuNCKPWL/uwrCCifQ2UE3
+EhOJTZlG6TFq+RRT+tsCUy/ZFmOkxdbqrZmydRuRcPumN/crdsw65I6mrMKfSuzR
+UvbuIqjoTrODeWTOk5ROw6liU8aYH69XnTE8rGR4vvkB8YjaQHo38LMvouIXuRXu
+wAo8KQDJa+kLk6xz0AOl4U1ByeSfio2cBEO7g/p5V5T533P1k0P68pJC2i33Hvxt
+yXibzM7bghrh7EtX+tLXD+d5u/OJAT4EEwECACgFAlNdEPACGwMFCQot0LcGCwkI
+BwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEBoqHJS96JaI2egH/0bU6bLcnP1gt5wI
+jL4RY35F17J08WrgT+se+e5SeEPFS6+YCozXZieMNDOdjxDnTt++wc9by5/bzhmv
+8kBL+3IVdUmhros6wd6HTnazpnip8ZvFxILb4qnnwiwt7j4Yce3gn02RmVD3wPPY
+0mww7UslyzwL03dgkEJSuWPz7dMKdNWdEQ02N2zmyIjTr7EJcoxG3TrH0gYEnQ3D
+Qtxyb0KC9tgqUwvVXWYF8iPGoNItnmrUklNA/aSEbHdpmpGpHUq/doMELsvKMVJe
+dKYGaUiQuwNJP5dEbYEuCYX4g2x5O17aUm9whCr9ZwIDabD2rY86gt39kn8oTqhJ
+zZC7EdW5AQ0ETPGPqwEIAL0ipe2SrZ+fByA9rCqThVkkDLuvrxPHHt2rwZiKcjhp
+n7V8p3laP6YVoxJqXEj3WGms6HjV8BZa9TThHaQyNOZsbcstIxC1JbVeI8a9pdpq
+jtBtKJ+cg8PiIVi/eHXZomcX8sK6VA3ULvVyDVOsNWQMyzmEKQE3pQXUOLpIOfzE
+/vlNEng2pGGnxXHSpBn1FMGBElOIjcTOazXI5ekVZ+zZcZ6kCGZvnYQKG30jFaym
+ymxcRw+SmIdH3Ds8a+SbKki6kOyCNPgNpRhK789IVpu+2ycg6UHKo+kAvYlPSA/f
+tbvMmyz+I9G4x2ZUTB0DsalI14wki04GG0OkJsspYoUAEQEAAYkBPAQYAQgAJgIb
+DBYhBGqBSx+GnCu+q3y3JxoqHJS96JaIBQJinGm6BQkZbUEPAAoJEBoqHJS96JaI
+yioIAIk3qs9E6vOhEZicQdbw5VDJ/0YBJ2Wp5qQUqV4P3pK22AP53GiRQE4gMOrO
+kUGGn3gDUGHB3Y0jWJKScYO78xSLfQCWfRjfVqDIZP8Eq/T8+klbw+CbWDQfBpOx
+BO9GYV1tQMe1YuWJRQqFpMdTYYiUmEXnRv+rYtA39dbpUcBVHen7S+wHn+1Iy+OJ
++ug0g0RAunlXbnL3JLTstIIz37HDUbtpf4usUxh3V/mevYeY1UbNWPVXZVQtomAV
+zEHRFF4THi8PBQRDDB9bp+HWW97wDWlrdEMis1kUG1qLHtO0qUi3WpJB6uyPuCxS
+6xdEoXWEx5a94ARTKMocpZrfYlGJASUEGAECAA8CGwwFAmC33FQFCRWngCkACgkQ
+GioclL3ologplQf+ORhN2Uys7Iaa2it3v+aB+xqb17noTXxzhnkE41/jXCwMnKbJ
+/79qFq93McdHxDDCjTyz+UZuaDg1hCoILNuNDWS0PtBzlk1yaPuJPkEUpHGTpSkN
+rrlgeTUi6YbbimBVB2ngvAO91X7TDJQ0GerdKbKOpNjicPOoYKRXBcy4Trfq8Fxf
+SAZSZC5tmlHLzmEYYEHbNsuh3aVjVmwVtS3BRfBI2Zn9gX2CWUuMI48tLAYVt+Jy
+kA6buIcvfG1DjAsQOj0sw1/fCc3zppIHe6F8bWcV3m7gqeTQ4Gdjkt7glF3kiLxa
+moAYFrLMPPO5QX+/xcfbNcuIBk3lld5wKLWrdYkBJQQYAQIADwIbDAUCXtFnAgUJ
+E8EK1wAKCRAaKhyUveiWiM1QB/9qugzb8U1BW8NYaz7May9qs4B8PLXfHPsVtjJB
+hDGTs3ZxXt9+BTfQTRmtdNTMER68iPDRLdtCzTBfNZvb8NmpeFIkL/E9j5O6UK4s
+40x23lqJ0eiSDUHQHZeWq7m4S+J2VALA30jeDXRoHYgtbkrIWxoNH7mC+5/kEQMF
+Dj/Kbh2n/4nSQzd0T8+v2OmPikBPrZ33uAt+aZx8NKck502BVwezC5YOXaIgZvIV
+++4zfiApCXJ+wx4lHItFRuTUIGgmwO1bjjMWTDSiMI/6pHCzD8fQUCZ/7GezvatI
+MR+3PpQiE1Tr7ToVORYPY9neaT6myy4PbUs1rN1j9/RMmj5uiQElBBgBAgAPAhsM
+BQJc772HBQkR2MncAAoJEBoqHJS96JaIC6oH/jnXBsqqk7x1MzYY5LM0N33TOVWJ
+/mECxufILyi3YU++bbp72hyGbvbwwVrJfEj5OBGpW2vl+ldowRn3ohx6+ccIL3t0
+ZxNU0nszs2FPCENmq3tQCEPX+Dqyr3NjGxzm2n6b8YHPMDtsOxH15OZRASPCBbFY
+A/U+M8U7rqqFptH3YXsWrf6o9FZG02ZiWX6EnjvjxcxTCzC106YRirFsjzKzksRD
+lA3A1zG5m86FcWtpgaEop8fP0Cdmzdeb36px2RMPMB9jhntdWYw0YDXjU+QCCQrN
+UnqcpFFTU0MLcpoN7FQoESKxzqiq5JPaeGRFCLe4YoavLIhFgpz+BuR5z0GJASUE
+GAECAA8CGwwFAlsF2O8FCQ/1fMQACgkQGioclL3oloi2pAgAim45ptLM+0l91EEL
+YkD1WbBo6LpBlWu985BYloRSdpA1eDWQxQTzBy+LfyUCfoNBtUSqt4yDl9WQ2XeJ
+1ly/F9/oC9BmBjxFi2pQwcEb8YFenzfmPiTTgx8j6ewqYnnhPbyCBycp3gKcqo4j
+Q6RjAvtMtSJtuRvniPLXiKzjNYx6/v2W8Q2rS2reqGy3WGrz9AjaoCD4nwCsqgQO
+4i2BBKvgMxnFxYiNi0UU9HpxZGFL3EhwK4x8U1uwXvIw2v8ffI8oEy4G5oV70dS0
+gNoyaI2CadFqTrExOUqq4M2qwZCbudV9a8uyn9iGF/FT44orzTU22/559YQ9Bb9k
+RR9RqokBJQQYAQIADwIbDAUCWRNm1wUJDgMKrAAKCRAaKhyUveiWiJ6QCAC7qDzE
+dv4jphwiQHB1ryHxtu0BMh4kNX+mIim4v1yWiBHDsJlSnxaABrdii56LNdBTOQTj
+7biT0Frwa4dQpG3tclS7l4bhKWXcO6fL7E4Z7qj8xwlHN1QQEFZ+xzKCzLA+LN0B
+3qJ/NVgpC7S+JqiBl36Wtp0znVZxe6PKXwQ06epVnkquspwQLKLBa3sI3u8DrekY
+FWn2B9cJ4yCTZYgGj8Xb3fkMdxyFt/edkimcJCWm6/QRSWC3JDBtQND5DQtC8NCr
+Q2dENvpd7z9jVBgRwRN+NmGZLPZNYN2ioi0JMu0rTkW549935mL0ixFE/cNZWwXt
+U0jiRl5Alo8HyltfiQElBBgBAgAPAhsMBQJXNwevBQkMIBQEAAoJEBoqHJS96JaI
+asgH/jxCg3JtOU12aBJKtZAmo5UHcTPsBUkCfB49cvwpwwCk36+txqSZhLQmwUmM
+QP0Yvulm7k+YhWyAtYK9JHFUt7tTxQCaKNL9Hv3g7vLLVEXI6i/NBztonilJb9El
+zBY3uWwtjRvb7LtQtF9BqfYhGxZ017kv1JbaV7+8kHbi5+Zd7RYQfdMYSLTKpY0J
+1gDzCPi321uIHIcOsGbYaU/ZA8Uiqb6EYxLPS3UcyBOoU133f8cv1hscLtNjqzO2
+CVzRjgqBGP1Zx9rLYPgD9yzvln0ZlM39OvbEoUPILPDGIpZwGnFkLwoHOJEgUT4/
+nhWiUL9FEk6WUJW8iyVK2d5xAamJASUEGAECAA8CGwwFAlNc+ZEFCQot0OIACgkQ
+GioclL3oloicoAgAw1z+LdwSxXt+LTQM09e3slTmLZZuy2qNGNqC4RQrL5iEZ2x/
+U1pLhxhxplH8VxP8Rm6LpsGcQ9IxzFrz+IXQpeGRNzxW+5o8ERXvDzXuEfMc2uXB
+95h5N12HhhxxG16z49Z2fHq7P2jFlHzQ2BVHfrQrB2b0yYTfqe1nAI8dpphA2ZWx
+ncKK6ISG3hfLsVbgzfw3Q8TK8cvjZarPrBLT3aR/MBCniV7/oKnOoCrs7WMiJPmY
+YpFFTBVtQE9adq8yMi4NUYD5ClnrBtpAScmjzQFS276RCbLKK4xvcIR0iJ1vFHwf
+dYIWJtT908OOYgKULmMmxxOOk+fmF+pTKT9Nw4kBJQQYAQIADwIbDAUCUNy4NAUJ
+BcxcBgAKCRAaKhyUveiWiMDtB/42zg1rFFwYC7GxCXjg5B6F5BCY0jYAhGZ5esWM
+z9B8kNBEXU06qZ/iMmTobWDvg/OBsVn9JuOdA14ZHQquvA5+9REgB12v6EGZvSB2
+M0LQt50aeqMMkJPrbEKUtVbHlsCJGCp8ABMt4Gmkp6kfAS3OKcWHxF+FINO6C/xK
++6LYQfdZ38SmG+yv41OE0D3TvncbhvhULByJ0GEHoQ73R84eFi5Fr5pTyzwmaD8M
+z7IffYE/sxpSF3c3l3bstpi9VWTYgnqvcAVkzADNe8sxQTPWqcykQJbZuO53LVL+
+TaxNJz1qvtTaSf9ZDIRhajFnlPSUvNax1GdbHK42O7H2ULmriQElBBgBAgAPBQJM
+8Y+rAhsMBQkBmLEAAAoJEBoqHJS96JaI0Z0H/RrPB0/oetTbeHKMqwkZqfl8T3vo
+qInt/dShli2BOp7X/UL0NLQHCFYz1pkjDlDLMhpN4kTI6/7OK2l8ha0WeI5hgNlA
+nFQcuRbgwrjerDMlWXAW10tHAPptBJdvv3y3+I6jDj2nMGsOSG0f8+z55mrvBIVY
+FD1oraEEzCrfmGnubsVbsy8vbvxpR8Uo6x3R+TIMjtJ74fXczC+gAUBdn1aLYLve
+l6J+kF1873OKfFaIzxvi1I44gbfxWy0Hd6wTX4LEQ0JrxbaOIIpb0RO2xP4w51lW
+nTkUyTmIOtAfpcNxqIzJjYoir41vgaegw20EnoHgJiCD5OB6Xzn03h+rTXI=
+=GKWd
+-----END PGP PUBLIC KEY BLOCK-----
+
pub 99CE9D9F22DC5C99
uid Benjamin Gehrels (used for *@gehrels.info) <pgp-key@gehrels.info>
uid Benjamin Gehrels <benny.gehrels@abi-05.info>
@@ -3664,238 +3977,6 @@
=8STR
-----END PGP PUBLIC KEY BLOCK-----
-pub 3D12CA2AC19F3181
-uid Tatu Saloranta (cowtowncoder) <tatu.saloranta@iki.fi>
-
-sub 575D6C921D84AC76
------BEGIN PGP PUBLIC KEY BLOCK-----
-Version: BCPG v1.68
-
-mQINBGL4BxIBEAC+lX44fd/zrVQPzdKygarBd/X0bBpGakT++Kfk4UBGl3q+wd2G
-R9puB9R377ds8hU7U3To8sHguUZo6DbD9Gb/is/WajSb9g92z+rMow3KbqfCYqWr
-kaIj27OJgbziFcnMAtvGoFRfaPI/7TOwEw3jT7B87RXeiATX4iL8fzMUmkfZm0Hk
-qjnepMQeaz3KzMY4DfBcI45kwzl3EIBFIlk428mhBU5iAAANoyPsimfqEPRCUDjx
-vT8g7PvpkBdNZgRS6R9vLxyzKi/f5KswZIMvop/pRXIhAKDhCCyr2GD+T3JoIKp9
-kvS1MQucWeX8+TFWh5qEA3e06Xu0JSdPCEej0BH06EiTMsAOU5bWqgLAO9DVpS32
-I092KAuMJlEPCnz7IGXVkeNY5KYrlsmoKrBO3GF/zsCyiZDvSULkVJcrtBCYOrgq
-HRIzvJWQaTJ5V15MD8CZIELyjCGZ8Jy8hdZpaTjYalw0bUq+yRAqMD5slp6A1tnv
-jyqVTgU+yRGq2HB90vJ0D3P1w4xRDuNF8c02futO415Yc/qkyh3/5AjGSoocrlfX
-cMreJXpQWVsvXn3NsitjsA6XOJpMOgipCDxfvn8SSLl9fWNJf55j7fCkBokF/lIi
-81RVQbyjVCOV0OEqHJLP9asPHyAFvUppNWtcvViPxVmb52djnw/x/61WVQARAQAB
-tDVUYXR1IFNhbG9yYW50YSAoY293dG93bmNvZGVyKSA8dGF0dS5zYWxvcmFudGFA
-aWtpLmZpPokCVAQTAQgAPhYhBCgRjAcMsioBdaLo1D0SyirBnzGBBQJi+AcSAhsD
-BQkJZgGABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJED0SyirBnzGBnxsQALTJ
-d/chCW8zWgR6x9ZDfU2f5fgMhi8jjILCieiQdQ/vec3QqCVLpJmE+l6MrI75E7GY
-eL8Iu0DXO26nHHSEbDa9kGk+ohdODbOd+y6KE5t6qPFaHSG5Gj1iiQ7libmrO7EZ
-qPQzl4fwmzUvl/2x+kaL5WsC4SxbwTG2mGo8WRCz+hqM40yeBeKYxpTlN2VBrlU2
-xkJ1I0rQITtHwck1dClgf4up13uBna7TlCBJc7vio3OwAFbXTPHEL+efrn8zk0au
-J+cwocHmm4d9shGiwiSUAOEnQ8FZ08IwO5MoOUWKz/ARYLuR6FAd8HqFERbfUxU2
-AlcyLSAhSi0c+j2Gi9PFkNTABEDHpdTosaAgKpbYdGke/2sfA0BKmcNRIfGjs+W0
-GnX2c7tP6qc7iFCCP0TjXvR8jnCmH8BT1JiSN5C/JPH0hDE1Zvmvgs0hid48e6Zv
-k1yXvEdtd/rH0uM3yUs28EfdcqokhwKZi5duUeizgG1gGNCW8RGvhi5ks1bABK9i
-52JMZznINMb35mZ0bEK7YLi3K8DE2hfIU6yg8WnlXlx3eOK4e6jWxWbjuEmUJ7BE
-ZWvz5IJ9nFI1UAIq7Ug7ruM+CH8ntpHueuGp6goq39+0lTd/1Sc29kVadg/DXQtC
-mDDrw4Btpz8hXthmTnNVvP/GUu5K1fttW3gNU/ofuQINBGL4BxIBEACwpcarOeEN
-5TztQDTvemc+DXZuWirmHv1TyJmjOhU0hGGMzEnKKU6VZlUIg5YQNYknUOfOf/05
-pgQmsEhjjI8NBD3Cys6SVQ6wOlkA+KpDKs/dXwyJttYE+EG/IMzjwZW2DbF50Hkm
-T2VK/oFhRSf0Par+cbVQ/mNLAVC7ueZWBVXldezqVvk3tDYYZef9T8Qlf999LVXF
-giMzRFrzLLcd2KEHAX4se65FTxIfFYYCrshFIKDRi4IWNzQqtPV7mb94wXY0Vwse
-5mMEgjmieGPjBGYne2JU0xYNBxtly1y3aeDXcxNlNrcS/Ake9AqWAYU4agtocCef
-b1pt5Q3li0qg3PsVKDJ5qWDceb+kgcUuHgtwHFCVICoQUMsv9p5F/kWL38/OWcTR
-2lQ4tGerE2dmlyqFWu7mpELckAfXSpJobZltUbp8CO679g0lk+OJWSmxddlVybdX
-CFaAeOKQb0woQOkR1vo2tJHyGmGr20Eea+UX+kdLojVQwYCqICdvnK4YpHuhpT5c
-rzk6lohfZpBPMHdpR7FQQZeQEW5EbcFNfoUEwsgb2qkG+hQIL5Q7wRajHkGaG3Wu
-hY2xEyoHuLSb20hP5hI2uhtxswUl/+IOjjZtDCjzLz59Q+ADkDZYM+PN3eR0UJDq
-YKly49KTuz23zLluNjNwqo8K0y05XGCQMwARAQABiQI8BBgBCAAmFiEEKBGMBwyy
-KgF1oujUPRLKKsGfMYEFAmL4BxICGwwFCQlmAYAACgkQPRLKKsGfMYGQbQ//bxZq
-IUIrPa86oXELq19E+OFTvCKVQzgohiaKPS6Hx2rgtvPS2bJvO+rXlAvRAFyI8sX7
-Dq0deeZP0pXefidjpfjKz1bhW8Wf7RU6QOKc0Eyl8/YqCVZign1DzJlF1r2mrkZa
-0VRNLjh86P/Y1T7ZhrAiR0PNv++LEgNsPbL8Tu1ryWl8vWFdlos40W8xleP1nBU1
-9OWheOPU9VYN80eBD5ij2Cn0LCxJQdyNOpVD03P3Ycauk9OHOVCd+UVX2A7VwemX
-b4wRDL59gAfSGyYLHYqAF1XJbOXkheTPRsttxXRIkzvA/gjpmQmioNU3UhiMZ1EJ
-kbJ42loFPv7YplbmBXoMAKJF1402+sOVusC1FULMQQtpZvC/bgobqEqdTzhZa/Hr
-KA45BFpcaTO80jJto8kiZR7infwX1gBGrYgwXisxiiYPI5yVwAvYTcNnU1nD9Vk5
-iyTgx0BNBG1hLPaZBtkYarDmUo0KyYf0Y8mQZmd7U0nOHptdkR+5yND5yO29/wGf
-se1KeZcRNGgcYQFKGw72HDiYsOELiiwsFqyUMWPLEwQJave/tO4SYSY1wP4rA3IA
-IU24GMQFZ64lljAKQCRXLwDKK2tMyHz8I+GT+0+bbpz4ojkEmxCDxXfgUy1362tG
-FdEbaZ88HZxTa30iXtOXOLvWIYRp8hv3pSb8id8=
-=hALf
------END PGP PUBLIC KEY BLOCK-----
-
-pub 3D12CA2AC19F3181
-uid Tatu Saloranta (cowtowncoder) <tatu.saloranta@iki.fi>
-
-sub 575D6C921D84AC76
------BEGIN PGP PUBLIC KEY BLOCK-----
-Version: BCPG v1.68
-
-mQINBGL4BxIBEAC+lX44fd/zrVQPzdKygarBd/X0bBpGakT++Kfk4UBGl3q+wd2G
-R9puB9R377ds8hU7U3To8sHguUZo6DbD9Gb/is/WajSb9g92z+rMow3KbqfCYqWr
-kaIj27OJgbziFcnMAtvGoFRfaPI/7TOwEw3jT7B87RXeiATX4iL8fzMUmkfZm0Hk
-qjnepMQeaz3KzMY4DfBcI45kwzl3EIBFIlk428mhBU5iAAANoyPsimfqEPRCUDjx
-vT8g7PvpkBdNZgRS6R9vLxyzKi/f5KswZIMvop/pRXIhAKDhCCyr2GD+T3JoIKp9
-kvS1MQucWeX8+TFWh5qEA3e06Xu0JSdPCEej0BH06EiTMsAOU5bWqgLAO9DVpS32
-I092KAuMJlEPCnz7IGXVkeNY5KYrlsmoKrBO3GF/zsCyiZDvSULkVJcrtBCYOrgq
-HRIzvJWQaTJ5V15MD8CZIELyjCGZ8Jy8hdZpaTjYalw0bUq+yRAqMD5slp6A1tnv
-jyqVTgU+yRGq2HB90vJ0D3P1w4xRDuNF8c02futO415Yc/qkyh3/5AjGSoocrlfX
-cMreJXpQWVsvXn3NsitjsA6XOJpMOgipCDxfvn8SSLl9fWNJf55j7fCkBokF/lIi
-81RVQbyjVCOV0OEqHJLP9asPHyAFvUppNWtcvViPxVmb52djnw/x/61WVQARAQAB
-tDVUYXR1IFNhbG9yYW50YSAoY293dG93bmNvZGVyKSA8dGF0dS5zYWxvcmFudGFA
-aWtpLmZpPokCVAQTAQgAPhYhBCgRjAcMsioBdaLo1D0SyirBnzGBBQJi+AcSAhsD
-BQkJZgGABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJED0SyirBnzGBnxsQALTJ
-d/chCW8zWgR6x9ZDfU2f5fgMhi8jjILCieiQdQ/vec3QqCVLpJmE+l6MrI75E7GY
-eL8Iu0DXO26nHHSEbDa9kGk+ohdODbOd+y6KE5t6qPFaHSG5Gj1iiQ7libmrO7EZ
-qPQzl4fwmzUvl/2x+kaL5WsC4SxbwTG2mGo8WRCz+hqM40yeBeKYxpTlN2VBrlU2
-xkJ1I0rQITtHwck1dClgf4up13uBna7TlCBJc7vio3OwAFbXTPHEL+efrn8zk0au
-J+cwocHmm4d9shGiwiSUAOEnQ8FZ08IwO5MoOUWKz/ARYLuR6FAd8HqFERbfUxU2
-AlcyLSAhSi0c+j2Gi9PFkNTABEDHpdTosaAgKpbYdGke/2sfA0BKmcNRIfGjs+W0
-GnX2c7tP6qc7iFCCP0TjXvR8jnCmH8BT1JiSN5C/JPH0hDE1Zvmvgs0hid48e6Zv
-k1yXvEdtd/rH0uM3yUs28EfdcqokhwKZi5duUeizgG1gGNCW8RGvhi5ks1bABK9i
-52JMZznINMb35mZ0bEK7YLi3K8DE2hfIU6yg8WnlXlx3eOK4e6jWxWbjuEmUJ7BE
-ZWvz5IJ9nFI1UAIq7Ug7ruM+CH8ntpHueuGp6goq39+0lTd/1Sc29kVadg/DXQtC
-mDDrw4Btpz8hXthmTnNVvP/GUu5K1fttW3gNU/ofuQINBGL4BxIBEACwpcarOeEN
-5TztQDTvemc+DXZuWirmHv1TyJmjOhU0hGGMzEnKKU6VZlUIg5YQNYknUOfOf/05
-pgQmsEhjjI8NBD3Cys6SVQ6wOlkA+KpDKs/dXwyJttYE+EG/IMzjwZW2DbF50Hkm
-T2VK/oFhRSf0Par+cbVQ/mNLAVC7ueZWBVXldezqVvk3tDYYZef9T8Qlf999LVXF
-giMzRFrzLLcd2KEHAX4se65FTxIfFYYCrshFIKDRi4IWNzQqtPV7mb94wXY0Vwse
-5mMEgjmieGPjBGYne2JU0xYNBxtly1y3aeDXcxNlNrcS/Ake9AqWAYU4agtocCef
-b1pt5Q3li0qg3PsVKDJ5qWDceb+kgcUuHgtwHFCVICoQUMsv9p5F/kWL38/OWcTR
-2lQ4tGerE2dmlyqFWu7mpELckAfXSpJobZltUbp8CO679g0lk+OJWSmxddlVybdX
-CFaAeOKQb0woQOkR1vo2tJHyGmGr20Eea+UX+kdLojVQwYCqICdvnK4YpHuhpT5c
-rzk6lohfZpBPMHdpR7FQQZeQEW5EbcFNfoUEwsgb2qkG+hQIL5Q7wRajHkGaG3Wu
-hY2xEyoHuLSb20hP5hI2uhtxswUl/+IOjjZtDCjzLz59Q+ADkDZYM+PN3eR0UJDq
-YKly49KTuz23zLluNjNwqo8K0y05XGCQMwARAQABiQI8BBgBCAAmFiEEKBGMBwyy
-KgF1oujUPRLKKsGfMYEFAmL4BxICGwwFCQlmAYAACgkQPRLKKsGfMYGQbQ//bxZq
-IUIrPa86oXELq19E+OFTvCKVQzgohiaKPS6Hx2rgtvPS2bJvO+rXlAvRAFyI8sX7
-Dq0deeZP0pXefidjpfjKz1bhW8Wf7RU6QOKc0Eyl8/YqCVZign1DzJlF1r2mrkZa
-0VRNLjh86P/Y1T7ZhrAiR0PNv++LEgNsPbL8Tu1ryWl8vWFdlos40W8xleP1nBU1
-9OWheOPU9VYN80eBD5ij2Cn0LCxJQdyNOpVD03P3Ycauk9OHOVCd+UVX2A7VwemX
-b4wRDL59gAfSGyYLHYqAF1XJbOXkheTPRsttxXRIkzvA/gjpmQmioNU3UhiMZ1EJ
-kbJ42loFPv7YplbmBXoMAKJF1402+sOVusC1FULMQQtpZvC/bgobqEqdTzhZa/Hr
-KA45BFpcaTO80jJto8kiZR7infwX1gBGrYgwXisxiiYPI5yVwAvYTcNnU1nD9Vk5
-iyTgx0BNBG1hLPaZBtkYarDmUo0KyYf0Y8mQZmd7U0nOHptdkR+5yND5yO29/wGf
-se1KeZcRNGgcYQFKGw72HDiYsOELiiwsFqyUMWPLEwQJave/tO4SYSY1wP4rA3IA
-IU24GMQFZ64lljAKQCRXLwDKK2tMyHz8I+GT+0+bbpz4ojkEmxCDxXfgUy1362tG
-FdEbaZ88HZxTa30iXtOXOLvWIYRp8hv3pSb8id8=
-=hALf
------END PGP PUBLIC KEY BLOCK-----
-
-pub 3D12CA2AC19F3181
-uid Tatu Saloranta (cowtowncoder) <tatu.saloranta@iki.fi>
-
-sub 575D6C921D84AC76
------BEGIN PGP PUBLIC KEY BLOCK-----
-Version: BCPG v1.68
-
-mQINBGL4BxIBEAC+lX44fd/zrVQPzdKygarBd/X0bBpGakT++Kfk4UBGl3q+wd2G
-R9puB9R377ds8hU7U3To8sHguUZo6DbD9Gb/is/WajSb9g92z+rMow3KbqfCYqWr
-kaIj27OJgbziFcnMAtvGoFRfaPI/7TOwEw3jT7B87RXeiATX4iL8fzMUmkfZm0Hk
-qjnepMQeaz3KzMY4DfBcI45kwzl3EIBFIlk428mhBU5iAAANoyPsimfqEPRCUDjx
-vT8g7PvpkBdNZgRS6R9vLxyzKi/f5KswZIMvop/pRXIhAKDhCCyr2GD+T3JoIKp9
-kvS1MQucWeX8+TFWh5qEA3e06Xu0JSdPCEej0BH06EiTMsAOU5bWqgLAO9DVpS32
-I092KAuMJlEPCnz7IGXVkeNY5KYrlsmoKrBO3GF/zsCyiZDvSULkVJcrtBCYOrgq
-HRIzvJWQaTJ5V15MD8CZIELyjCGZ8Jy8hdZpaTjYalw0bUq+yRAqMD5slp6A1tnv
-jyqVTgU+yRGq2HB90vJ0D3P1w4xRDuNF8c02futO415Yc/qkyh3/5AjGSoocrlfX
-cMreJXpQWVsvXn3NsitjsA6XOJpMOgipCDxfvn8SSLl9fWNJf55j7fCkBokF/lIi
-81RVQbyjVCOV0OEqHJLP9asPHyAFvUppNWtcvViPxVmb52djnw/x/61WVQARAQAB
-tDVUYXR1IFNhbG9yYW50YSAoY293dG93bmNvZGVyKSA8dGF0dS5zYWxvcmFudGFA
-aWtpLmZpPokCVAQTAQgAPhYhBCgRjAcMsioBdaLo1D0SyirBnzGBBQJi+AcSAhsD
-BQkJZgGABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJED0SyirBnzGBnxsQALTJ
-d/chCW8zWgR6x9ZDfU2f5fgMhi8jjILCieiQdQ/vec3QqCVLpJmE+l6MrI75E7GY
-eL8Iu0DXO26nHHSEbDa9kGk+ohdODbOd+y6KE5t6qPFaHSG5Gj1iiQ7libmrO7EZ
-qPQzl4fwmzUvl/2x+kaL5WsC4SxbwTG2mGo8WRCz+hqM40yeBeKYxpTlN2VBrlU2
-xkJ1I0rQITtHwck1dClgf4up13uBna7TlCBJc7vio3OwAFbXTPHEL+efrn8zk0au
-J+cwocHmm4d9shGiwiSUAOEnQ8FZ08IwO5MoOUWKz/ARYLuR6FAd8HqFERbfUxU2
-AlcyLSAhSi0c+j2Gi9PFkNTABEDHpdTosaAgKpbYdGke/2sfA0BKmcNRIfGjs+W0
-GnX2c7tP6qc7iFCCP0TjXvR8jnCmH8BT1JiSN5C/JPH0hDE1Zvmvgs0hid48e6Zv
-k1yXvEdtd/rH0uM3yUs28EfdcqokhwKZi5duUeizgG1gGNCW8RGvhi5ks1bABK9i
-52JMZznINMb35mZ0bEK7YLi3K8DE2hfIU6yg8WnlXlx3eOK4e6jWxWbjuEmUJ7BE
-ZWvz5IJ9nFI1UAIq7Ug7ruM+CH8ntpHueuGp6goq39+0lTd/1Sc29kVadg/DXQtC
-mDDrw4Btpz8hXthmTnNVvP/GUu5K1fttW3gNU/ofuQINBGL4BxIBEACwpcarOeEN
-5TztQDTvemc+DXZuWirmHv1TyJmjOhU0hGGMzEnKKU6VZlUIg5YQNYknUOfOf/05
-pgQmsEhjjI8NBD3Cys6SVQ6wOlkA+KpDKs/dXwyJttYE+EG/IMzjwZW2DbF50Hkm
-T2VK/oFhRSf0Par+cbVQ/mNLAVC7ueZWBVXldezqVvk3tDYYZef9T8Qlf999LVXF
-giMzRFrzLLcd2KEHAX4se65FTxIfFYYCrshFIKDRi4IWNzQqtPV7mb94wXY0Vwse
-5mMEgjmieGPjBGYne2JU0xYNBxtly1y3aeDXcxNlNrcS/Ake9AqWAYU4agtocCef
-b1pt5Q3li0qg3PsVKDJ5qWDceb+kgcUuHgtwHFCVICoQUMsv9p5F/kWL38/OWcTR
-2lQ4tGerE2dmlyqFWu7mpELckAfXSpJobZltUbp8CO679g0lk+OJWSmxddlVybdX
-CFaAeOKQb0woQOkR1vo2tJHyGmGr20Eea+UX+kdLojVQwYCqICdvnK4YpHuhpT5c
-rzk6lohfZpBPMHdpR7FQQZeQEW5EbcFNfoUEwsgb2qkG+hQIL5Q7wRajHkGaG3Wu
-hY2xEyoHuLSb20hP5hI2uhtxswUl/+IOjjZtDCjzLz59Q+ADkDZYM+PN3eR0UJDq
-YKly49KTuz23zLluNjNwqo8K0y05XGCQMwARAQABiQI8BBgBCAAmFiEEKBGMBwyy
-KgF1oujUPRLKKsGfMYEFAmL4BxICGwwFCQlmAYAACgkQPRLKKsGfMYGQbQ//bxZq
-IUIrPa86oXELq19E+OFTvCKVQzgohiaKPS6Hx2rgtvPS2bJvO+rXlAvRAFyI8sX7
-Dq0deeZP0pXefidjpfjKz1bhW8Wf7RU6QOKc0Eyl8/YqCVZign1DzJlF1r2mrkZa
-0VRNLjh86P/Y1T7ZhrAiR0PNv++LEgNsPbL8Tu1ryWl8vWFdlos40W8xleP1nBU1
-9OWheOPU9VYN80eBD5ij2Cn0LCxJQdyNOpVD03P3Ycauk9OHOVCd+UVX2A7VwemX
-b4wRDL59gAfSGyYLHYqAF1XJbOXkheTPRsttxXRIkzvA/gjpmQmioNU3UhiMZ1EJ
-kbJ42loFPv7YplbmBXoMAKJF1402+sOVusC1FULMQQtpZvC/bgobqEqdTzhZa/Hr
-KA45BFpcaTO80jJto8kiZR7infwX1gBGrYgwXisxiiYPI5yVwAvYTcNnU1nD9Vk5
-iyTgx0BNBG1hLPaZBtkYarDmUo0KyYf0Y8mQZmd7U0nOHptdkR+5yND5yO29/wGf
-se1KeZcRNGgcYQFKGw72HDiYsOELiiwsFqyUMWPLEwQJave/tO4SYSY1wP4rA3IA
-IU24GMQFZ64lljAKQCRXLwDKK2tMyHz8I+GT+0+bbpz4ojkEmxCDxXfgUy1362tG
-FdEbaZ88HZxTa30iXtOXOLvWIYRp8hv3pSb8id8=
-=hALf
------END PGP PUBLIC KEY BLOCK-----
-
-pub 3D12CA2AC19F3181
-uid Tatu Saloranta (cowtowncoder) <tatu.saloranta@iki.fi>
-
-sub 575D6C921D84AC76
------BEGIN PGP PUBLIC KEY BLOCK-----
-Version: BCPG v1.68
-
-mQINBGL4BxIBEAC+lX44fd/zrVQPzdKygarBd/X0bBpGakT++Kfk4UBGl3q+wd2G
-R9puB9R377ds8hU7U3To8sHguUZo6DbD9Gb/is/WajSb9g92z+rMow3KbqfCYqWr
-kaIj27OJgbziFcnMAtvGoFRfaPI/7TOwEw3jT7B87RXeiATX4iL8fzMUmkfZm0Hk
-qjnepMQeaz3KzMY4DfBcI45kwzl3EIBFIlk428mhBU5iAAANoyPsimfqEPRCUDjx
-vT8g7PvpkBdNZgRS6R9vLxyzKi/f5KswZIMvop/pRXIhAKDhCCyr2GD+T3JoIKp9
-kvS1MQucWeX8+TFWh5qEA3e06Xu0JSdPCEej0BH06EiTMsAOU5bWqgLAO9DVpS32
-I092KAuMJlEPCnz7IGXVkeNY5KYrlsmoKrBO3GF/zsCyiZDvSULkVJcrtBCYOrgq
-HRIzvJWQaTJ5V15MD8CZIELyjCGZ8Jy8hdZpaTjYalw0bUq+yRAqMD5slp6A1tnv
-jyqVTgU+yRGq2HB90vJ0D3P1w4xRDuNF8c02futO415Yc/qkyh3/5AjGSoocrlfX
-cMreJXpQWVsvXn3NsitjsA6XOJpMOgipCDxfvn8SSLl9fWNJf55j7fCkBokF/lIi
-81RVQbyjVCOV0OEqHJLP9asPHyAFvUppNWtcvViPxVmb52djnw/x/61WVQARAQAB
-tDVUYXR1IFNhbG9yYW50YSAoY293dG93bmNvZGVyKSA8dGF0dS5zYWxvcmFudGFA
-aWtpLmZpPokCVAQTAQgAPhYhBCgRjAcMsioBdaLo1D0SyirBnzGBBQJi+AcSAhsD
-BQkJZgGABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJED0SyirBnzGBnxsQALTJ
-d/chCW8zWgR6x9ZDfU2f5fgMhi8jjILCieiQdQ/vec3QqCVLpJmE+l6MrI75E7GY
-eL8Iu0DXO26nHHSEbDa9kGk+ohdODbOd+y6KE5t6qPFaHSG5Gj1iiQ7libmrO7EZ
-qPQzl4fwmzUvl/2x+kaL5WsC4SxbwTG2mGo8WRCz+hqM40yeBeKYxpTlN2VBrlU2
-xkJ1I0rQITtHwck1dClgf4up13uBna7TlCBJc7vio3OwAFbXTPHEL+efrn8zk0au
-J+cwocHmm4d9shGiwiSUAOEnQ8FZ08IwO5MoOUWKz/ARYLuR6FAd8HqFERbfUxU2
-AlcyLSAhSi0c+j2Gi9PFkNTABEDHpdTosaAgKpbYdGke/2sfA0BKmcNRIfGjs+W0
-GnX2c7tP6qc7iFCCP0TjXvR8jnCmH8BT1JiSN5C/JPH0hDE1Zvmvgs0hid48e6Zv
-k1yXvEdtd/rH0uM3yUs28EfdcqokhwKZi5duUeizgG1gGNCW8RGvhi5ks1bABK9i
-52JMZznINMb35mZ0bEK7YLi3K8DE2hfIU6yg8WnlXlx3eOK4e6jWxWbjuEmUJ7BE
-ZWvz5IJ9nFI1UAIq7Ug7ruM+CH8ntpHueuGp6goq39+0lTd/1Sc29kVadg/DXQtC
-mDDrw4Btpz8hXthmTnNVvP/GUu5K1fttW3gNU/ofuQINBGL4BxIBEACwpcarOeEN
-5TztQDTvemc+DXZuWirmHv1TyJmjOhU0hGGMzEnKKU6VZlUIg5YQNYknUOfOf/05
-pgQmsEhjjI8NBD3Cys6SVQ6wOlkA+KpDKs/dXwyJttYE+EG/IMzjwZW2DbF50Hkm
-T2VK/oFhRSf0Par+cbVQ/mNLAVC7ueZWBVXldezqVvk3tDYYZef9T8Qlf999LVXF
-giMzRFrzLLcd2KEHAX4se65FTxIfFYYCrshFIKDRi4IWNzQqtPV7mb94wXY0Vwse
-5mMEgjmieGPjBGYne2JU0xYNBxtly1y3aeDXcxNlNrcS/Ake9AqWAYU4agtocCef
-b1pt5Q3li0qg3PsVKDJ5qWDceb+kgcUuHgtwHFCVICoQUMsv9p5F/kWL38/OWcTR
-2lQ4tGerE2dmlyqFWu7mpELckAfXSpJobZltUbp8CO679g0lk+OJWSmxddlVybdX
-CFaAeOKQb0woQOkR1vo2tJHyGmGr20Eea+UX+kdLojVQwYCqICdvnK4YpHuhpT5c
-rzk6lohfZpBPMHdpR7FQQZeQEW5EbcFNfoUEwsgb2qkG+hQIL5Q7wRajHkGaG3Wu
-hY2xEyoHuLSb20hP5hI2uhtxswUl/+IOjjZtDCjzLz59Q+ADkDZYM+PN3eR0UJDq
-YKly49KTuz23zLluNjNwqo8K0y05XGCQMwARAQABiQI8BBgBCAAmFiEEKBGMBwyy
-KgF1oujUPRLKKsGfMYEFAmL4BxICGwwFCQlmAYAACgkQPRLKKsGfMYGQbQ//bxZq
-IUIrPa86oXELq19E+OFTvCKVQzgohiaKPS6Hx2rgtvPS2bJvO+rXlAvRAFyI8sX7
-Dq0deeZP0pXefidjpfjKz1bhW8Wf7RU6QOKc0Eyl8/YqCVZign1DzJlF1r2mrkZa
-0VRNLjh86P/Y1T7ZhrAiR0PNv++LEgNsPbL8Tu1ryWl8vWFdlos40W8xleP1nBU1
-9OWheOPU9VYN80eBD5ij2Cn0LCxJQdyNOpVD03P3Ycauk9OHOVCd+UVX2A7VwemX
-b4wRDL59gAfSGyYLHYqAF1XJbOXkheTPRsttxXRIkzvA/gjpmQmioNU3UhiMZ1EJ
-kbJ42loFPv7YplbmBXoMAKJF1402+sOVusC1FULMQQtpZvC/bgobqEqdTzhZa/Hr
-KA45BFpcaTO80jJto8kiZR7infwX1gBGrYgwXisxiiYPI5yVwAvYTcNnU1nD9Vk5
-iyTgx0BNBG1hLPaZBtkYarDmUo0KyYf0Y8mQZmd7U0nOHptdkR+5yND5yO29/wGf
-se1KeZcRNGgcYQFKGw72HDiYsOELiiwsFqyUMWPLEwQJave/tO4SYSY1wP4rA3IA
-IU24GMQFZ64lljAKQCRXLwDKK2tMyHz8I+GT+0+bbpz4ojkEmxCDxXfgUy1362tG
-FdEbaZ88HZxTa30iXtOXOLvWIYRp8hv3pSb8id8=
-=hALf
------END PGP PUBLIC KEY BLOCK-----
-
pub CC6346F2CE3872D9
uid Jisi Liu <liujisi@google.com>
@@ -4993,6 +5074,63 @@
=YwAJ
-----END PGP PUBLIC KEY BLOCK-----
+pub 01D734EE5EE9C3F8
+uid Stuart McCulloch (ECLIPSE SIGNING KEY) <mcculls@gmail.com>
+
+sub C753427AB202DB9B
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQINBFBdqooBEADuV8IhDi4Xvs1oYAnTXQz9MW+bU5uaxQyQcFzUwxacSdgAv+pj
+dZRFli8qs31HsddRmW6qCkCua/QXNQWCOcylcwAKmumct1Z/ZumYTRVGbsagneBa
+WVSoQdyftb83mI4DzFm2JyvGAPK67HjDGNb4Tn7Bt+cfVdlkgLDgAzEk1ZDVvCf6
+fBJi9yKKxq3JvOfk415QtdvrDzfyfEbhtNEui0k9vwUz9dsHABGkNLrob5dY62QB
+noBpqcPuaa4iYE3rpdSpJs0uReQPg01ts8ARx0tmzo0D0yWjiKnRjqmUaU8zEl7f
+r1D1GsGKQb4TZ0HaNZ8ork7JkA5iCtGd+oTmdZaaCK5ycXpzEG4KwK8OpOPjA3FU
+MLRjNTf1QsGFKL5tb+XZNXCdzB1QMJUAkyMIXMbRRNsEKWC/QUeFigzZKB4XRLGP
+wzkGNPrxlFZi+6UIFIx7kX2xqsSX1DV6IVQr5aKkqQIgm9YM6qp0F8tnPp/upK34
+tw1TK2mkjk547hrayHXyuB/u7jb22m5cDJDV823/daBznv3jBfQ1BfPkoJS9QyDk
+CW4f6XTMD13AY55YnAhMuEkqFxg+hQOSLpEy5k0dc8Z5hJMURS383a6x9qwGvJ3y
+MaXqm6R41aQy6wVnKZ24ZcXXQru9Dg6jvql65WGLDomhNyxGnq15Xik/AwARAQAB
+tDpTdHVhcnQgTWNDdWxsb2NoIChFQ0xJUFNFIFNJR05JTkcgS0VZKSA8bWNjdWxs
+c0BnbWFpbC5jb20+iQI3BBMBCgAhBQJQXaqKAhsDBQsJCAcDBRUKCQgLBRYCAwEA
+Ah4BAheAAAoJEAHXNO5e6cP42Y0QANbFQns8603eSwTkHXP3Zsbp1MKe1LkyiHD2
+zScs+bt4d8KwVrc9D428UtNUIaPultm+RMwXBGcenTz1BkULL1loE8ZKJ7UBaE6i
+SGCh1hq+eIHC5iMPhq3/KPAJiwFAbLGopK2yh7R1GeC9Yx5jGDglzqqngED0P75b
+5Dok7xkMv/oV5f6+FMYImehnd3q6XYpTcppOc6orUBgMEmDu69q6Q2FceCN0+9po
+4+E+bDt2BgdcdRl4zrnf7+d9QPp2A4AOeR2amIlUnfcUpCCxSe5udMLDkb6rkD9J
+cNVGDc9o0QVVCiCjzwhhEkzNrHwTppJLTFJ2XdGAo5rczwW59bXhhePowXRgvDJo
+4488nU9AENZngRcm9TM5S4UJXav4jejX+uSwR0hf7ejZ1HoATHFVx5kqSMSE/5Kn
+i3M5CbpJ6sGHPEgBDAEbB3ZrBWY6PBIXHFn6EmI/y/5Y65wKs6n1bPCuNhOCxFgF
+U/aUgv1mAFQtkSPKi1t8FUugGd7C/ArvhWD0uxDUBNtcoKRNKmZZznRZ5LYSXVRI
+G7SjHbVqi6B5TQH6nqH/z3byqCAsrhrZ4rufXtZzthTXy8kkQmj7xq0+qFVoChTr
+cw20t98cunZlrx4/qK/S0Fo8Zkt5GmFl1VJUWZ/Dv7Yc0iSJj2zxs+herB6UsgiO
+AaYgqY9/uQINBFBdqooBEACvzlaXkY9aRuc8DUSL9gAKHCHssHcMiytQ4boPG6h1
+6DyCUIYITs9TE1Ed/Edp9YqsKZPUl5f7/BfVtkwxRgetaY79H+2NB98fpkB5wGOo
+WECj9RU/Xdy9+fCJvbehSBuImzR80eCf+Cc++Xy8A1dC54dsOLyA3eY9/NX48upr
+xdDaXXNxPwUhl62/j3kN3kRJVuXzg9IERPUe6yFkKvNAOIIX5Ne5dpf9DwKmW1B3
+i02q6Hs+IUic4m2eQ/byPpEl1OXCjppxpiasLWSzo1xD7MFyIKvucxYYfkT+rPWE
+JzAg/l1TZCZNuOyNpca3DTQyX8TyHZh67IygiKfi5yeZRRqs+RLECcK5NeDpUGrk
+QWIJoOdgk+UucFWpNZFvLr3Ptc/OF/gAR+gypKJLJ0n2NnSZhzy+MMfM+rn/vhOQ
+sz+2UJFmsp+mhfPoyfKG0ZD+GI5doWKhwbOcN4+idEx23dUc+wLTaGMUJTXaNKBb
+6Vuj5dsqzlLBfoRe+d0VhxtBYkljqagg75Zub79KdXlv/3Smi2UNLVPQ3Y08hBN1
+Q02fFMZW09kBNxvwLLG060RGDsaCa94eA3VvFQME0rCV/60hIkhFzhrWEojcFKn7
+r5r3BRfMiVZXg01lsS9AQejfSngbvdnMY+mS/Ij6VcE2QH+Mq4fRBfIEY7zQCm8+
+FQARAQABiQIfBBgBCgAJBQJQXaqKAhsMAAoJEAHXNO5e6cP4urAP/iVdYGWlcMte
+fWdUxGTUwva3xGBBVcy+iWcnsPkFVvbATz6XWjZLaOvLLNKKzPXUFZvo0XRI4Ele
+1Ll5hdAO4v/ky8p8C5KvjQcKLwkjYAgDkcnqzG1ILU3YYTWvWRuonFsH27soPRjb
+A+cAys5+R9hhBEdsHJDUvBK04sx6AASpWsAUhHnViu6juXHOvVKRejKShUtTad5U
+WxN0s3hunKM2cr8Yqk1LbhA15KnUgfaByg0IiOfDJylf1+6wrLRv5JUzFe7DCO+y
+JejJ2kGzBOKQtGB96/Qn85i6mzGKLjxa1nDzfK0nEaHlLzLPIHKbf5cSxyBzkHbL
+gV2FL4XmaxSi84wXE7AftmbfanovKDrU3myncOMP+h1JRJIHyrI2/08UfgTXty8x
+kf9M2fNKWZIpIt3//W9e/WRrhFWTeugJpKJGaZOS/pHN58ry2ItBIUtMs5tzgkH+
+un+eWV9TobCeCUmAL2Sd41qKvyLhicfvRrMulmvNEUnEyfZaZUuEAwC8qdWY92PB
+dweXf5b6oNoxXFQY/LjmmutuII1lfG0UH/EDk/4DvqFxHab+ZLQdexb5D1dMno7Y
+HZUvNM2HBfQSQJghYxlLgR/dWoSiGVkZqxnIHaLL3cy0KatfrtmWn3tJcse3C1c2
+Bx1HfIQGzU2e0dHlGBhNVD+d31gs8Aq9
+=I4v2
+-----END PGP PUBLIC KEY BLOCK-----
+
pub 3C27D97B0C83A85C
sub 4BC7B9A81C39EBA0
-----BEGIN PGP PUBLIC KEY BLOCK-----
@@ -5053,6 +5191,78 @@
=3VLr
-----END PGP PUBLIC KEY BLOCK-----
+pub 9EB80E92EB2135B1
+uid Slawomir Jaranowski <sjaranowski@apache.org>
+uid Slawomir Jaranowski <s.jaranowski@gmail.com>
+
+sub E3F6790A5A167F5A
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQINBGHDIagBEADpzdCwVjVlHuo8qpu9HtmqNpEW4TB7y6+NX7Q39mj8w+iVskE1
+sL0+BOCdP6ZMiQziWbOQ2FxCd3mD0ixZ7v1i7+0jowySPacJbVNaPPECP38gDte4
+RQwUTTCHgW8ADhYJBxSkA6RX0c5sZvi0fxgunZARs0pE68V4kUnAKiLvHerI3BBE
+kL1Pq6+CvT8K8/kU7kSk4SlgU9C09S3/CiHfb9k0ekYMJggvJV5MjqrYyLd0boBQ
+GWo8hWM4Reg/ye3+6301FDkmtza9bLwVW+euhPgzKYNoWMzOBj2pqjfWk0jF0TRR
+4iOW9aATlIZ2z3/NH3SuufW0HylmMEIbtxZ4bA0wverDje32YGYebEb73xui66Cf
+Ezj/mZPhyRDA3tV+LulyEy3CgMmDhpTSoN2eRTeXe3rq39fgoVFBE6lzJkQeNlbw
+lrFhdYEQhSddMReRlRHFeQYpbMWiS3lW2e0Zp7zjGKLqs5/0BcX+xuwBq2WaVKyx
+fqVNuO0xP8+J210B9I97Mv6CnJHg2US0q9cFOPyMIIaOtQAuzMLvmG6c1UlBaQm4
+N1PvV1ycKUpBFJv/qmNvhznjJHH5M+Yjm7Zp29g40XD1m9e4RdFq+3/4btJ6eyRn
+9eBRPp5xYNqjt4AApHUmSnWquihKXXw3sT7zsv5H8ZA1Ol4N1pFc51IM/wARAQAB
+tCxTbGF3b21pciBKYXJhbm93c2tpIDxzamFyYW5vd3NraUBhcGFjaGUub3JnPokC
+VQQTAQgAPwIbAwULCQgHAgMiAgEGFQoJCAsCBBYCAwECHgcCF4AWIQSEeJ0k33ej
+JDPOHweeuA6S6yE1sQUCYcMk6AIZAQAKCRCeuA6S6yE1sUy2D/0Z6TncCud4O+J6
+edm6RWrdU/rNx96XaDjai1Tu7IGSxHnwyYDdEL6E4AYTCMnkxFlG7AkTlTDCBGSk
+4V9i3GadHpu9BIPQvDawkE9qRpenSBizP/zxjBhnLBWX8Nis1ebI24668W7xZfSS
+YIvJ9l4qaj/2XF0+PNWUs7hF67sBijvHqsSy+ihfCem6bndJLKiO5mbgFIXP7Y2Q
+gyebjl/yQgnedfIv+R8ES6SBNXfVlrxtMwJmJIIYoNQaQaZR6wVOTfMmYAcUjZn8
+DVrT+a14lnLah1SHF/SDCLKTksuwD14vrUbBfV1wptdy10O+5rImsh14knlLNt7x
+3+iK9PCBQfJzuVQT33/4cWKK2YuRffghNzRMicm0oB3Efo8zOzqFdDj4e7tU2xSE
+0kJCruiDdU9i+iU/bO+vh8eHmXfv2S3XdMSmE77GTweGflihwFgM33J/ZDX78YC1
+GqM96Cbj7WLuOpleljjwZrxuRhSHe7wtnScM7WLhvfo2n2Fq8fASne2hcHN0lVdl
+EbeHUcHnQLTsIFL4O/lbABBfM666DFdXY2rXQqOUmSpC0CMa63AN2oa2Fkur56dP
+0CyYaE5OpFxbEbQIzC4W7YjX7whBTBhxs3M9G+gBtpXhHG3Zy2qkags6sszz2Sf2
+LmrN33T766464JRi2AY/V36yFe8ycbQsU2xhd29taXIgSmFyYW5vd3NraSA8cy5q
+YXJhbm93c2tpQGdtYWlsLmNvbT6JAlIEEwEIADwWIQSEeJ0k33ejJDPOHweeuA6S
+6yE1sQUCYcMisgIbAwULCQgHAgMiAgEGFQoJCAsCBBYCAwECHgcCF4AACgkQnrgO
+kushNbEibhAAtPwam2kB9+8Idf51p673s4prOmWRRV63HaXlvIMuT2JzPr+FO9w8
+HPWKXUjWVps6HAVMJo6c8drPtRtUqCS9CLEUwmdwOddsYGlu8C9x7SmV6qptZIRN
+Ga3P91Us0wYhMMI9Olp6UouHlG/VFvSKZTbLMGc9ClXDW9FtVXWlAi/Mei7zUzyA
+LujaE+ePagIqT6KPr/vUGpi2qcjVdobjkdtSImActsZAlYoER43TDj1libNJZtH4
+RTg9j9XUsa03Lco8Jm6LiPDvdZoayIJmYTsLa05ccRSYVpOy8oLgOx0aSaYIkydm
+w8TUOv6NkirmY/+jsOFFstc8cExTe0ogW7arIrRlBZbbCafuri/mVLvITseDWMty
+0vuVQZpeLecSEt3yf4xpf+rwaIZol81MigegscQs6u4ELaCRNmj8E993o0bB3SjI
+lkLjIUI8ZaCjJOkm1JY8RdjwYGhgQ8crWO7/E5zjtDEXNZcO1+IKSjxGpuIcxG0t
+orwcJHJ8x0DpxZ4LxLOyhVHI3cy2eXc/YCEmEnv1k1dRnzVBcosVP/junb0a4Aej
+PWnkQnW7uhp+w1oQ/uO/VcwhE/s+A2+hUmn6qMD7KDROut365kBtME21knRTdvWB
+28yhOZZEVYJLOiEe3jwNXqZrn+M8wN/qWD0yJzaeaSFYx0RtIQjkWtC5Ag0EYcMh
+qAEQANAPQUSHg5zmQMTMFZzapUgFg4UkD7w7OmL9F1+zCVmuvSD+eSrQtXK3ILSa
++EB4ZPAn3nwJBQNgr5CBWo5/sTWz0nxQK82a7WnCNHvfgOyFYGaZC/aXHM5V/LcC
+LGW1IVKsyhWQ9UGn94cwvdfOiVrR++PpT1PJw7ey3HTnvz3PEu7KenNQcfZtXc+H
+zQDF+0s4XjIGfnsTbHoEfE3myLdJ8OG0akyPy5gR6tn4d7QEl3BOKXma3SWOIehE
+VBxbJcDRucHUFZP98r745sqZI4CbVsuAiwvjncyDYDvadaphso5mmvYPTlXgkLcc
+ltPbcqgfWY1qrcI8HIAMvyJyZIUwHVwY8tDMz+rwSIzQXNm3Rmm6dEMfNfZl7eJx
+J2wG1H2aOFQdQBbEw60OTRuHxn813IqiCnMnwIf4rsYT1MTC0WyJRvL8hbxkwXsM
+LIXvPVJe7GcizfUbYzjdYlbx8ij2Ua+0z/pStzj1cXv1gBuFRH4Vr5V/HE70k/5y
+J35Sv2sJgaVPf7troE8V+LTUiJaZmxPWSORvmMzi27m2PtwHZLQZ9fKhl773p2C8
+NryJjn/WrE1pzaw/S9aKX7EXUIp/6gnIdi8rCOCJqdZGvMpl43hUO2tLhaD+UuBU
+Oz7SWqmsPnBRAt8+ENBQ65mrt8sVKp196HjRoywnVpAKH61nABEBAAGJAjYEGAEI
+ACAWIQSEeJ0k33ejJDPOHweeuA6S6yE1sQUCYcMhqAIbDAAKCRCeuA6S6yE1sSSu
+D/9EbHq+swI0tOsrD5E7kRJMCnzex9MknJVHH4hbso7alqdr0Cqom2Ea4KLVKb+2
+Tmkyc5vgqzw7ec2Up9kw7nWqN3ANThP2RPK2BqGNgYqYtilkAsDjDUMAZuIEdCq5
+TPgDqSVTTp0EYODqCezHPLd6QjRK1CbcNoX61ahUyu78I2OcNPQEvr3rn99sWeTU
+DoUEIUUJYSqyNOb/wNi8v2o6CGsW/l++huPhO2gSF/QgUQPc3OvIDg1EMidI2s6i
+SRRXUPfJfdL2rP5KCbrJxDVeI6qIK3MtachBaDLZabcBsArsxNKpx88o6yGuzM6A
+4bkcdnXpxHE3s7DkAk6EA05zaToB/3KoFnU0FuYRkl0MBKWcGT/p37iu+LiJFs19
+0negsnLVAlbwhT78Umd8WWd5LAZ91DAOxeUGH92T0xz1Rhuu66L32cY/gh/dZItL
+17xApmK5Q+N1E0B84DLOJ3NjuBOn9f4oazPMig+72q9ikLaEbILh03dxF5b9jcJw
+E9AKrphN+8L/OMaHaA270ZQZgUfdlsnAydGz7syt+J07IcWiE6ciZv8x1B+PtGWt
+kSkTFiY0ACKu0OiXgajQ75g2LVI2uXkezd8cyzD89a/c5QhvLV3fbwh/hpjHNaI2
+fUB7vVlzPnBDQ+imN5uNOymMNiLYjHGN2OXzU0XRDL7u0g==
+=cPzY
+-----END PGP PUBLIC KEY BLOCK-----
+
pub AB2DA4527F6FFC0B
uid Egor Andreevici <egor@squareup.com>
@@ -5414,6 +5624,53 @@
=Le9W
-----END PGP PUBLIC KEY BLOCK-----
+pub 5E975CB00C643DBF
+uid Xiaoming Jia <xiaoming.m.jia@gmail.com>
+
+sub 91A4BA316974A467
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQGNBGHvIbQBDACpPdbz5UIVIWR4cfXyyZEMOG0ayCzJQPsT4eq8XR0o5Y9egfAq
+dRXC8paInsaF/iVL8BJY6CNq4B3dUfJwKDcJiCiPbiQgknqF1HDBqQtCb4akW8f4
+Am1Q6qWxTcJBUtVjjlTMoWcCRwFNP1229ICL6XdfM5djqxOuIcCMIHC55YTldrDK
+5WWgcXC2NZgUbRn7/8dpaCn8iFAyhYjYKAk1lS8kSxCDvQNU9DtdAWtaCosoWBZ7
+mWWIeWp21erk4jgC145GujHYeqynf7VmdIB80u5OeIV6CwJx2ap8AgrKcOCON3Kp
+kYa7fsDGxq6Lbzbc0rzaIfK1wyGo56dMySDK1eZuOY9Es/wzaYfpzx88gn3rrcaw
+HwTKBoug+9z09m/rWy1DThW1gruYMUrxjeyhcdXlEeVrv9EdNCbbfKcg6MbrZ1mu
+Wc9DIAfSQ40Lv2sKxTyubZXxvoyEhD5LTqSKC0tRt9xKjHWWWSG+cyhXu/2hYmp1
+Dq7XvS1p8NKjD6cAEQEAAbQnWGlhb21pbmcgSmlhIDx4aWFvbWluZy5tLmppYUBn
+bWFpbC5jb20+iQHUBBMBCgA+FiEE1fRrwLhq9dxW31jwXpdcsAxkPb8FAmHvIbQC
+GwMFCQPCZwAFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQXpdcsAxkPb/HBAv9
+FHX6iGu5bNqqNJWeaX3QontSlzC20Ef1Ub9MGro9nyk0yRSpp07e40YvLtSWBZ/w
+AXQBSr3xSiKTmhspGpMfKjtgYGIaby/EIJnds+08EoNS8g0k8eNMKR/kJ4qbIbGT
+6Q6ZLtIx0wcqamwLPlUpcjFrQ3jnW6Uu3Q7d34LBItjU7H0ZdmApXb3aEBUah6hT
+ERhW+nzKSfjqaqQl3BlWausoCHjmFFgb9AD6u6skMWEH294Qtiht7K0VhZuLQF9L
+5ZtX/WQ75QVbiBDBkzMyKQ77B00lAV/pT8d5I3+FpcUs7V3rSR5nlq6LNkk5Mir1
+dGcwD00OpSwOko1TWLTPHW/AvORz/mRa5fraqEytujeRdOl5nQ/f5IeQqcg4ga9Q
+JAMxCA2WZYe37hc3SfAobBYFe6BPk7JPTLlRLA/aohNhMVopQ1HwLAB32+mq78p8
+gPc9LTnJOAUPTfOY8TRz9D0w0DaokrJ4VYbd3n0Ds6NPXxA+w3gsHsvIlNYHOsn2
+uQGNBGHvIbQBDADNSRxyLYyzfkdxF55RktDmgSKq9tskfR1QcrQgWvi96fJekLYL
+/a2hmJnbfUbqaILnkyUmIf7zONlCFv10U81prG9wxfXUTMuabpp+eXUFdbCZMc7R
+9JGXw5iaRWje+jh/GaeB8xY3cPbtfHkXZ7nWkQaq7b8DutJrAqo39NuprRaaujfU
+9PXj93tunJExqi2w++fjT1aQ36PaplXRZ2qWiRxAkaIUGxjVgLuOY1FWZJjWX2XM
+ypMesUSfUCV9IwlKCc8+55m4jfbtblPQHkbe5zvstxxfHdYQkGngp1rNWLHHSCT+
+Tf4Y4aR2J/E3mp6wSBVxgfguS3u9h1mY9fEfe2vSHWkWmYNm4iDAmsPn8KTuccbZ
+lB/cKIFS3AET8ZHwHqHuCb4TvUy8febp4yo5ZRniTVQSf2aA/izuwmKSmq0bX0hj
+GRBVdGR2jlD2ND73lkJXU7+3sIwY1ebNVzvl75Y7slmJNHsij24fkeZtcSmRQ7BL
+7ZpZ3fYiyi1/MxsAEQEAAYkBvAQYAQoAJhYhBNX0a8C4avXcVt9Y8F6XXLAMZD2/
+BQJh7yG0AhsMBQkDwmcAAAoJEF6XXLAMZD2/kY4MAKDX+NsPosjHt95895Z2H8A6
+JXOEt2F/LqUZ6XOqW1AAeLj+cGMWBDDQYNp/IkizV4iMynmlHlzgYivT+52xrUvE
+zOqMRUrDNTPrbkLUjc/Wm+TA2J2ZGUSjZZUmP1sBTqSIa1NCqWl1VRWZcmbckCHz
+5oyoeXKM0EKGnPwOZP0lf8M7f6QDUJY5DS/5RTIp+6BxHhtRi5uZBN5QLcamhIAD
+wR9fIlfoFfXEwEAQl5Z2YTnyMf/6/5FWVgAS1PPFqvI9H0HiWPx+XSfgJV6K10Gw
+RTtdhT12M4teNFsFUNhngsvO8WCZKsxz4CV+Ai8bSMmWpNsYk72CbRMoEHMrHuVX
+KKaKv70eFd+BaGTuLPd8hZgsDuKxU83OpS+LGOYV7Lb3sZNEeqWasWMqjeQC/CzE
+AE+Qfj0RuucswEZGZ2NWvwouGJcTvLAKaUelMr5IuWTkTZYmXww7ffu+Fps7qSMn
+U+mxOl6TkfoQw/cNRpZdMqwI/7119TnFeK5/AORupA==
+=QK1G
+-----END PGP PUBLIC KEY BLOCK-----
+
pub 40A3C4432BD7308C
uid Michael Schierl (Maven Project Release Key) <schierlm@users.sourceforge.net>
@@ -9006,6 +9263,50 @@
=S5Ep
-----END PGP PUBLIC KEY BLOCK-----
+pub AE5A7FB608A0221C
+uid Robert Scholte <rfscholte@apache.org>
+
+sub 38185785755267BD
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQMuBFKTz1wRCADOdMCDOKXlBuQpG7mnQ/5rppqhS0SXdKvNZ5pYrJKib1LLtlS/
+LOeABja3E1ky+znvTqnEEtai7fNhw36zPdUjhPKE0TZwn2aK5fyctkcfqBFsja3E
+ntJgzi4pa6gVn+MtIjCak71jv5SrC+LE0dkPM/GwupgPL7Ohfpf7HyAGjlpKihrQ
+syg6GmkpZKlhLVD+wg+nILrWngXS6Zz2I9M1rd6wfYVqH8tjYkKYNlexB4hL26zt
+f2MKX1MTRpdgO/jPEh8EI4K5qg0eT2x2e6qsii50WobmvraZfUFpQJysJlmt5jwe
+k/FWfxZ7Hlys8r88VYGa6sknvofGZfhFRZRbAQDhMzmNSQ0mBoveEA8/gd0FqVA+
+YzX8TY90YNeRQMjXJQgAt3kbBz6uyzAchGxSCyZpnS2dVFWqi6H8gqMjKmEnDn+g
+vG19F3STuAKYkJPfJZGwAVnZtTbqQ4R14WgjDuoqHPuFjRw5xrIaEVmb71gFKISP
+F8RIMw2jWygNeXbbXjRF2brEV4H+V6JXn6PnzlmBLIiB1zhzutMUu50FxnmclQxa
+gUxGMcZG/6PcQtiuhu9oKHUl1+E1fs/pexnsPK2gKkRdyUMnngHJ3aYm9vBFMWya
+draOg/6DBRTrvgoOVxzQHSFCSs9ttaHXbLDMD1e9K6DnVMKZVHdJVohNVwxsWxrh
+ibUDu0iH4Zp5MFgyx9L2kkP9kbL1hflIsTyQehDUwAgAwl/BklUfuOkw64xNZ9ww
+YZ/y4GTNuoDIdVkSArr0cKhiLR3u2Qsgy/K2CW5iuXMQGPBrYFfxcHO1Lge5Mvyt
+uYhLYvnH7gwfID/8r5Tjx7ktzoZehO2R4wfqyYfKwLoJGY19uj8hCBmKss3GOK7M
+JKLDKLZ3Lv0t4MTiaSmVsZEVRwYD3x70J7l3mUUwVHAK0QeKg9RczJQRd/i0lKzt
+OAA/d4gZYscWHbZi0dH/KxnqHzSUDkrLuWrYSdvgaln5tS9hG1ge0LFDxf82f1U9
++ckdxzYsu5FNjgu8GFZLbLshRri0kKPWqTBX/YPubApadVU94i0eXnqjmZMajXTm
+LbQlUm9iZXJ0IFNjaG9sdGUgPHJmc2Nob2x0ZUBhcGFjaGUub3JnPoh6BBMRCAAi
+BQJSk89cAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRCuWn+2CKAiHOT5
+AP0bECw/IDKybdLYSd9icYWeMzkBNAsQD00Dvd9bOZOXFQD/TpURVm08mUI6Jexa
+u7eNLxfRfsOlCmbzrzMiBAB8dvS5Ag0EUpPPXBAIAI8TJgzJdhJSlxV4FqbCE7DV
+LsZtzMEFdKEQQwOmEoC8aX9Bah4dPuVtqMLf/1p6+44zxfcZsmqU8JBFCa+1v5vF
+2DOXv1a2jyXa7mCPQ/D08W4i4XlH1Y173bOuRSueRYNqY97TRUw2NbFHFo78VtbK
+pUSabpgC0zSixFEl3hU6JB5kcmfJJxCHP9BosgyMNWkPqvgTQ8BO4VD9Augj+w3b
+YNZ1cTyYZ9VnaszPoT8ztbYVMhEExkbaLJFVfo2FF8lPIiuVkqDYhqMSwiFoqmgt
+wbszG/kPP/88GHXFgt+lGakqSCriVZhrpUFcTv9WxbkLB6muKLxpiE0Tvg/yN/cA
+AwUH/jpVa9OeOJFCbKXpkWEpDT+M0LbxQplFuunYkDcax0x5DpB0HiW8fUtC77ma
+C+55XgGyhqDxAA/pYBe46R1eCa4Zki4odTnLsN4HJ4aycLP/o1HBWT7WqydaRIAU
+HQsWTvbHNPzBt49WdcwfxAOyjecN124fX9Vaxmq+BumV5CHHUT2+ymvFsHygFZKV
+PI+M6WNK1e4pW1GPJYmHnHMNMAo1GBf/FsOU4/P3T/YuxtIbrb2xUBQlinyfKSBd
+0GbFeJ5fpo816bBtpE6ao9XUVmnWBSn/SgcNnpot0/xsAF3RlXMG6NkCw+TqiC5n
+ZpVrR6NW7MUYlGNwCynLFf1634SIYQQYEQgACQUCUpPPXAIbDAAKCRCuWn+2CKAi
+HJHUAP9+0eQdcPV6/NekAaDaySEUil6GqqrdJ778weiAKOvrtwEA1EV1n1Siq+96
+GRaLJzret1R51ugVfZjKo498Hp7vRZU=
+=l0nB
+-----END PGP PUBLIC KEY BLOCK-----
+
pub 3C0A8F4744F37328
sub D17266C6E05F9993
-----BEGIN PGP PUBLIC KEY BLOCK-----
@@ -9785,6 +10086,53 @@
=w1VQ
-----END PGP PUBLIC KEY BLOCK-----
+pub A9321EDAA5CB3202
+uid Werner Randelshofer <werner.randelshofer@bluewin.ch>
+
+sub D36DB5C489BAAC5B
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQGNBGBoC2ABDACyCWLqqAo9NeThE90hBoYomtgLci5I8+7PxSYeQfzUYjXzZcnh
+6d/zHaeC0zxGhT2LNe5i3p2e36xSeFDobjG2Il/nv+4jFCgbn3TZ2hEingPuPsg5
+isodOXHBSY9iHPTKInpiu+J79MWP9GVZ6GeOOgQaNSrNN3uDE1w3rukB2SrXGdfT
+/6YZIOtwWZVzc2m9lalPmOAyI4KLI/s37C8Ozfv3c+Bx11WRVzWVpBTo94fU4DPu
+Yzkx2Wxuc4TT5k6bQJI/GHi36M7xkUauXhkRCNvBz+LFVcFjtsv6S37L6RZib6mz
+jZTW+iyD4h66gqzg3hSRxv4YzHgR/Os26Br2ioZNzH6hJFtNktR4oN/2kydmj5Od
+WYjvdMmd/dMbZheZE3f8sziUKCyvWMIddnHAM81uDTXgWcMgYSa3npOGZhfk41z+
+w9o2f1kXIfdurqlA1n8np07PLw5Rfpjvbs7EZxPTJwcc1enaNyL64fb+YIUtFrcW
+Dt1zUMEDkbcZL1UAEQEAAbQ0V2VybmVyIFJhbmRlbHNob2ZlciA8d2VybmVyLnJh
+bmRlbHNob2ZlckBibHVld2luLmNoPokB1AQTAQgAPgIbAwULCQgHAgYVCgkICwIE
+FgIDAQIeAQIXgBYhBG6tdSs+Kzjo4iNte6kyHtqlyzICBQJgaA0gBQkSzATAAAoJ
+EKkyHtqlyzICv4wL/14Q5+HH7odJ6+Owe22fR5k5zTcop7FJL16vx9I6aY66NSZQ
+xYJFQl2eq/ukGFSzukVCpxKRnZYTatRiWf0rFLb3Q+TEAaaOhEgQ4rO9PcctYlqe
+yC7m/UMrv/mMizOGYzG4eco3V0jFYCWrat3KjGMumm8n8vZpQXizxFwnVHtF15o3
+Y7vajCkyi47RI1Dwth71UorTSoryGJUMHAk0jKV5SZZjCDrYBc4vib2b0Qqxjonw
+r/ug5h+R+c7Ho1I2KiAasT5UEL1R6VcEekgTkB7n8U24eh7u/HeRJA35sFxJOQ+8
+5Tf5ROs5E/lbjGGiVTX4YIErbe92w44NdsloQHdTBIOUQtIPuLWDuXvmBrkxYoYa
+pij0ERT3Np52iZ3X8X4dCDMH5hNK+LeCGTLqnLsXoUt+biUyDQzSRttrhNgvjW8o
+gMkHLG6XZGoERDm4g0u39tU4qoxauYREdBa5IDyBRJeAltsTFQGOh07sfIXVs9xd
+tNuQoz4UNVsaU3hu87kBjQRgaAtgAQwA9dZFGqc0/6pUKDUsT+2hMh0z5mISLc+x
+6v4wbAqiEcBE9uoKf0LniRfVeehmuJpiUPgOf3TyxNbxeWiFuJELZbnrYztAeRE6
+6Zxk6i2Mv+207fdlj3mhphdEWh4f/0AJa2PAmiwlcxq1O3VJ/Wfn3huCqIU5cmqn
+mGKH9LPaW1aJBxWl9+x6mmPVySxpTaQRrnNnumZf9K5lwGEsccvpkLP7J1Nlv7HL
+O8oliPCInEMcsrVqfiKU/bybxNW1wzPJxp8LNLaCNxuLNl4RCp7tPQuZgjcoCnz+
+JwcxnmNGI+FKqSsFXBZyNTWiQJuaFUQa0QON/+Qj3p+OyW15f+FfLjHI/BkNAi4n
+cNeeazAwuLCMJGMS+dLarHMbbAKLaH0UI062ch3Aq2Sa3io1gU6vYHvoKNMNfYdN
+woGX85EkzX6A9fm9jBviios1RLkpfO70MoxpWjl/rwHG57GOItWZ7O53ebs6HrFP
+dUYQs0Gz/lj+BaQPwDcMxADfYtGnYMepABEBAAGJAbwEGAEIACYWIQRurXUrPis4
+6OIjbXupMh7apcsyAgUCYGgLYAIbDAUJA8JnAAAKCRCpMh7apcsyAj39DACMEaGs
+skfZBBbF9BHklmN9OHbGKK4qfwY6f3Pl+QEC4m2y5Uaxgx4n0SJZ/p4YdVopRj07
+cdVYEkqJC31co0XPvfbjyBfhcH1BXkKQiYAZMUTqc+ILGHrY/vzP27Je+vck6M+n
+tQ/2rBBiPtD6Bj2RcuXupr6MiGavF5U5vzLUkYm49Oq2Wi5gIuBF8+6ipjnzrVl4
+HqGUlFEt8RK3W4I/ZWTJBlwxaIWoAIfkE54FtSqN4dY+LoNllMKbzjFBemXfZXHA
+FEH9cjNh5EvFKm53ff8X+WNgodiVaH+qv2VMZZngEtmj2Y94v5x5z+Q3vcoGH6FU
+dLjefYm5uwEhhBsTyz8gyBmoj8cBBnw3DZexyOPLGDj/3FSimww0HXf8RIR7Msc5
+GGMLXqSZ4WVZM59pFsqjmqfgl+C8WYWMLAt7sXJGuyl2LQoAtR5gpkPZqA0wQiIX
+e7/RgIs6TpqdS4uLh52KzW7VUXqywr+qH53RFujkS0KijW96LbblENk54Kk=
+=rtCH
+-----END PGP PUBLIC KEY BLOCK-----
+
pub 42575E0CCD6BA16A
uid Taro L. Saito <leo@xerial.org>
@@ -9833,6 +10181,141 @@
=6Iv0
-----END PGP PUBLIC KEY BLOCK-----
+pub 1FD507154FB9BA39
+uid Tam?s Cserven?k <tamas@cservenak.net>
+
+sub 8DC6F3D0ABDBD017
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQINBFAJOeEBEACn8aGYTnhyLS9SNi+SAdRU+pMPiqxdpxDMZczVee50y3LiRnCX
+biWqZyhzuHZTccgV9IMYFwxD490BioH8M80escHrMh2C50FCFglVYsZQG93jYJJR
+Bs7Zclx3DzqUPR46iES+Tb7wirWIZ2voP0/jSPCZ9sipba30ujO0FnP53QprH5jk
+poDzQ5M4EQqp1HPqepveikhZE19KSc9t5Lq0pMs2rDeEXElfBwHrg4V+dbZv9Db4
+57kWz6AQWfmqWr0262pQkCc4cy3LPMLkvKcH61T2aE1hm+L9IBI9UBkbL8xNXYVO
+CSG5XhVOSKpAjMHQn1kbxbLlFj04z70TYmT2ZvhFWZhsYIGs0DMgujZujGMWSVOr
+ajS/XGrfK5sgv9vhI1TLiKJpyzkEO+/ssNAJGnk3dlkJvr22EJjrUyKCwUTNxCAv
+vH70l5r/peJ+H7OHejr2UBNyFPi8uTFvBKi/Hj6xjVg01KsWREczkdKG3LlFK92Y
+9C4N2QCJBZJURpX/ITcHENo3sch0RhRR63gMKB+TcqCHCCBArjcSwAscBsehlVdi
+El8OmWickCxUv7Grsdgxkx4+9/SdimsSWARK08gVqmMx4h6jzTPFCqW62schBiFg
+gm2H7RALlZauiv8BGlvWLrzIc7ONbT2a4MEN8anUqrhrQ6FKhjO+nKaGlQARAQAB
+tCdUYW3DoXMgQ3NlcnZlbsOhayA8dGFtYXNAY3NlcnZlbmFrLm5ldD6JAjkEEwEC
+ACMFAlAJOeECGy8HCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRAf1QcVT7m6
+OfB1D/9StrqXL9xqDrZ+kRbF65U3fvGN83ucfGeJpfYWi3hSVc5mWZC8gnQPp+zI
+e3Bhso9Bvyh5oekACeJcPOnbxIs8mESGu8h2+piQkuSjjTUkqaXoVd/3sFsertFf
+SkuTNSYoRzL85GzEuk49iHX/C0cGUOj4Zc1ftXwgD8arvgbkE6UGwr/zmpqrjQGP
+h4VJI3bmu+EJVpzZNzf85o9peKIP2qZs6uMGlOXe+HSCqsvrCn4T0cllffAD2Bn4
+giTWILgx57W2o40tdU5bg2eGFb5RaBRWGL9Pqc8U/trSgOeqTJHLm/iNZQBtIkvN
+wYVLnOu99/yz2iw0O+Urjkwa5qqdCD+MABOmqgvAIBTFLJetIGGJ8MRno5/vvNE0
+jsJQ67oV+jmnKKgJh2wkGmHulnvrfbI6Uvz1cY/URyw7Fn/6I9yPrjO0wsfWQQQM
+4ABMjPNY5GPgPvc5/xyvI9vlMm4JIFkwWrnqpVarkukElembSY0ynoq69XJKKMk7
+k3WBO73/aHEbudVTO8lcBdXle69wbzSsnycSzhzuVdiaK+mO9zWr/H+WNbwNfK9k
+Q94vSW/Cs6yT03cQ7WgRdfZTDXLqmJ9tKxLHsKVsRnJVk/xUThzhetEARuzrUApI
+NzYBCqM5O3+5qK5T3OouhG0qcWq7LVnccUDFCb8VAkIbY8DLzdHJjsmMARAAAQEA
+AAAAAAAAAAAAAAD/2P/gABBKRklGAAEBAQBIAEgAAP/hABZFeGlmAABNTQAqAAAA
+CAAAAAAAAP/bAEMABQMEBAQDBQQEBAUFBQYHDAgHBwcHDwsLCQwRDxISEQ8RERMW
+HBcTFBoVEREYIRgaHR0fHx8TFyIkIh4kHB4fHv/bAEMBBQUFBwYHDggIDh4UERQe
+Hh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e
+Hv/AABEIAGQAZAMBIgACEQEDEQH/xAAbAAACAwEBAQAAAAAAAAAAAAAEBQADBgIH
+Af/EADMQAAIBAwMBBgMIAwEBAAAAAAECAwAEEQUSITEGE0FRYXEiMoEUFSMzQlKh
+sQeR8CRi/8QAGQEAAgMBAAAAAAAAAAAAAAAAAgMBBAUA/8QAIxEBAAICAwACAgMB
+AAAAAAAAAQACAxESITEEURMyM0FCkf/aAAwDAQACEQMRAD8A8ds7bCqufwwME46k
+1w8TBiVGN3K8VeLiMW4XI6edCT6jGhJLdOK2HQTBOSy+1tXEe0jKluc9a6kjUPH3
+Y+UYPr6Unudf2H4WoB+0O05BPA4oXJUhmK73NPZsIZpVlckMvQHxzXyS9jaUtK+S
+G59vAVirjXnJJU8nrQY1WaRsFjS3OHRGnxl7ZvZdQgE5kU84xQkt+zvkGs1b3LyA
+ZJphbZYg5qfyNpDiKzT6TcneN3Sgv8nabHdabBqSj4ofhY+h6VNPypBrQXVuup9m
+7yyK5YxEj38KcHOjWV2348hYniuxgTnJ+lUzs8Z4GeOB5UYFdZtjfDg4wfOhNTjK
+OC3XoMeFZb5NkdsDZmJ5AB9qlfG69c1KCMnqk6SAlfTIpNqCyZPWthDbpeabFdRY
+J2g0svbEHNad6KTHpkBmJuI5M+NCPE5PjWsnsB4ihX039oFVnGy3XKTNiBvHNXRW
+x3DrTwaec4IAq2OyAxkVBjhOaC2MBGOKc28e0DpVUUO0YAoqNelOrXUr3tuG2wyQ
+M49a1GhlFiO84U8e9Z6wiLuqgdTR2qXJSRNOtjmUrkkHAX1NWqPHuU8hyeM857T2
+hh1m7RQCRISMc5BpPIu9CjDnnFbftJolwNUE0Lhi8QJU8B/bypBNZwqSk8cls5GM
+SLj+aoZMaWZp4so1Jk2BUkHqKlW3oC3cqqwZVYgEVKqsuE9M7DassDjS7hwyMN0Z
+z1FaW6t1D9PhNedw2umSaEL7T7qcX9sAWhkxkDPOD41vNEvDd6RDOW7xZFGSP0nx
+FamG2zizG+RQHkQea1TOQp9zxQr26Fuqj2p4IY2BLHNT7PCxAVhmmtIoyameeDHQ
+ZqpomB5AFadtO/VuAFUS6eo5JU+uetC42SZSZ7uyTxRNtbliCeaNazIJIx9KsULC
+hYjOB4UJSE3+p1cXdvpOnG6l5YfKPM0Fpum3t1YR6zLdCMXJLFNmePDJNWWr289y
+X1KGKRAfw0YFtvv4UzvdQe87qFdqwqAAijAA9qPQ9sBWvRPutqrx2chIOF2nih41
+jkwrxrIniGXI/mjYxFdn7NIedp2H9rUHErRyiOVSrLRp3uBV61PGdcUJrN4qrtUT
+vgYxgZPhUph25t5Ie1V8Cp+OTeOPAjNSsa5qyTexu6DJqNzJJdS3lpYtawMdmzJK
+5xyMmtV/iu+P2+40uQ5SdO8jXyYdcfT+q9JuF0fVtGOhzWcQtwvwBeO6x+oHz/uv
+Lrjs3qPZ/tHYXGnypNFJdYgcHGQOWDD2zV9w2w2LjsmbXPTPRommbDVEmFx3EUvd
+565FA3r/AGO3/H1ExgdAibmb2rRzRW9+Q4wHx16UpvNISOXvGBkZTkbuQKsWq+kq
+0ueMzF/dayLlLeOC+Jl/LDnBb6D+utaG/wBD1jSre3Ms7NJIATHkkqcc01ttXmtr
+fu4wqlejY5B9DQ15f3l8RF3jbPLz9zQlKg7dsJyWU0AQGN75GAkZHXGTgYIpgsUR
+gZgc5HIrmaPZGEZgWxVUU2yTYR8OMUR17BXfk4t44SSr54PUUSkUKcIMGgnDLKR1
+Bo+2jlfB2ZrqzrStHK3XA9M+tNYRDdQM0nEicqw8/KlfdkT8/u4+lXwziCVwSPmw
+AfGiq69gWN+Tx/tVd3MnaO/NwfjExXAHAA4AH0qV6H2r7G/fuq/eMTQxb41DjdjL
+DPP9VKz7/GycnU1cfy8XE26hti8m1grAKwxhT/3NFS28epaQ2l3TGN+GilHWNx0Y
+UKE7gmQKdn6gP0+tMFJaBmyveRjfG37x4ir1fpmZb3ZFemXVyGkt7kCO/tsLOinh
+x4SL5g07ivldQkmCcf7oK+t11CCK9tpBFdxDMchHBHijeh/ilsF/FJI0ZBinT54W
+OGQ+JHmvrXFuPUlqX71HEoSRvgXGfSokYixj64oaC6YDBAYURHMJFyAB9aIRgokr
+vDtUvjJHhVAV2VS6bS3KnzplbrBF+JcYbcDgUovNZSykWH7J38Qb4SrYIHlUW0ds
+mu3oIXHAznDLyKo124lsFWIZAePcDn1phpWtaHesqmZreQdUlGP58aV9oLqHU9W7
+23ybO2j278Y3t6Z8K62uOxnU3z1YgmkXM0s6o8gwTgAnkHxzTZLWOW5LyOWPQA9P
+esbFIyIp70ozz/N5CtxHpyhFktbtvPJ+IGl4nkRmYKs5a1bcdt2VHkBUr6Y7gEgT
+RnB/bUpuiK2/c5hlidYpwcxTLg+ma4MBhmksCxAYb7Zj5+K0PcYsdUutPY/hPmSH
+2PUfQ11O73uikxn/ANNs2UOeTjwodydf8nelSFY1D5UElGH7WFV6zpttcgLcQJKA
+cqx+Yex6igo7xJZUnH5VyMOP2uPH/vKmsUxdNr8lRgjzqBLGoSNXZM3PDe6YDLZS
+yXVsPnt35dR/8nx9q6tNZgeMSW/AYHKmm067HB/S3ynypPqGlbp2ubEpFOfnjYfh
+y+/kfUUpGvkdW1bftKRqF7dyskR5B8TgCpcWt25/NRsjDc0Bb6a88rm2uJbe5T82
+FznHt5j1r5BDrcTMDEZNviTS9v8AcbxP6YZZm3smZ2Z7q4xgAjCj0rifVJpo3GQc
+jaEC/wAVRBp+pXsYIg7oF872PT19ab2mjR2akPJ30rfqK4xUhZ88kWaD32zO6u3c
+2+4AhgwG0eZra9i47VtMjiLyLKF+PDcg1ju1lvIlqqpw7yqBT/sXdaYzGz1Kcwyx
+JiFwcMT712J1k0zsxyxbJrfu0yfEl7kHzXmpVtpbXCQ4ju4pFJyGNSr3E+pm8n7m
+e7bko1vOvEiuMH3OK40R2FxMmeGXmpUpD/JLVf4iKidk15EvCqRIB5GmkMjMiEnn
+pUqUFId4U43W7KegGRQgJaIOeoqVKNi6yT2sNwQzriRR8MinDD61Ro9xLOZo5SG2
+HAbHJ96lShf2If8AlhennEG3AwrsB/urJGO5fepUojyA+zPdreJ7QYGDJS3WoIwS
+wGCMdKlSq2T1lvF5Wc6Zf3kNqI0uJNoY4yxqVKlDVdRlqm/J/9mJAjkEEwECACMF
+AlAJOiECGy8HCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRAf1QcVT7m6OXhP
+D/9sUBLIhjHbEv6gXHfQoWBmASz+aPeUxWX3BYoriZI19/HGCsGv5r2pdTBo3wia
+VBMRBvyeaxiTRin68ykvmKIwv4nlxUsxKMcUQ/3uQwrWoGv2OeZvVSB9USYstK8b
+Z3PPvPXvTcGqOqz2YFfVuHFbepVHAd+EjNeC3Ubf8+XAMdJNm9l0WIBY93nsppme
+80X9K32du7eUmn3evzLR2dgxcWWX4TIvua4qJa7STpjm9fGUqieexRkAtU44/0cA
+coImQL1WHEkq5tdYyMVPujIftuo6ByqOKLVPrbll3Z2jETFalmKqroieFzCCRTDc
+ujxVid9Z4UjSLjmkmpKY7IdRPr0ODaWmytceXfAIkR18qLi2kmrPpBhEpJm/3aNk
+aRIJjIj+7BvHfY5ZyNQD02Vno9DQ4A10eFm+YjHLNZDmHtmrvNxgsPk90n2I7D2D
+6mX/CPbJNpXErnYAOtkQJIXtMQUYRASbUY3ycf/YKmWrae25/EOE4kD3/lGeHDNm
+Hi1FxaLTrkYsM/+F31S0xQBWrRg9u3CiM+KBBbcZ9wyj56xJmzmrWKR8wlnI359k
+81S5kEAYnAzj2Q8sciBbycRNZYNvbWVEl7JiRx63XYpyiZ3u+k7zDo4B1Jvea/2n
+aCrGa1/KuLhWczOuZK+1Ps1Y88acU0fwMQb1MbnTHSJJprkCDQRQCTnhARAAu0/u
+U2Qn67vlAnerKeUVclj1oAlr2FqG9uauNEIL3KFa3n4YDKVrLl156+tOKZLV6FGv
+w+fGX2SjZw4Uq0SmGYe5BOM94hlYkb1ZzLicClfYEDPp335cvsaOxbgHgXSAKIz8
+1PaZZ3ZGNilqirLpjvwDOtNsqsRJ+L3nQjPF4J2WK7iI6BngebSPm8XPYX7gtAsy
+hp19mXqi3cMGGqTZnWaKvXI9ndwQlB8t/orPlWe7uc75uL2WORxpEZXJphIuI9yQ
+16ED30bKWmBeanZFkEGEvEtIQCfSq9JsotBS/3t8XMRyj8OsSSDfk0XYxqNhahoH
+0RVTcBFUcKCH/+g67So59vITzhGonf43tL0eS0BrlGdBiZiVn+i5IAvnpDC5OM+0
+PXLOZiC2s/i+KAUNgOTZdPgkCJraXg72IQ40Y1rfzcg48Rz19s+w00TG9R+jdDRC
+WUerW5TeUhNYVTevP7Vff3L72tjE8cZUJlxUAuak3vL0pB+ketIHH37L12mdbGWG
+ZqfebwhQkVMG+pL+AipXevwC7sCIOv/HrRgJNOfk7RhW2TJI2XS6rdRMKv+AJdWO
+Hw/eD873nir/T4C9jANk3XpUCOfEGGTwiD+vrcFGvqjcoSIZ1JVoS5ICsk770wxO
+GIhSZhzbvQ11N24Vvb9jSQIjVBqjcHRUk+koGu0AEQEAAYkEPgQYAQIACQUCUAk5
+4QIbLgIpCRAf1QcVT7m6OcFdIAQZAQIABgUCUAk54QAKCRCNxvPQq9vQFw4jEACL
+oK1pkiWsGAbLPi0OX62oNyrRP46wiAyfghlQMuZqO4HOvrX5Pdmbtswev8QO5qTm
+bi3wb1ocWMdf7O8t/eRyVf2gdVgsbuZoM4R/A60isQDLTnUDjJuswUfoNgI2LUR/
+eFhDOPQSnGMduNHuAEmAMyPodHqCdvOW+j9pIQtksFNTXqGNRNrH3SgBiRBR1fEw
+kTie2idDD6wBJ+f9h3j/r9y/lVBCqGzlDRoBG4XsZEytvJrhoXXzp6YdpJK4sPRY
+BBlsMtTwLxU2RdlqEXS858BxGqrXRj9SglioDCPi14a6ZJt9u+x17zY958dfXeqB
+9yaEQrL000Ai125kFIpUk7Rk07tk2xShHVoiDgnJGqWO4hxrVhZnq2IYqk+w9BK+
+ThepR7uPGyvlYnfXwAhA+eoJdPiLxavEpJl1YhS8lTxcCmE2iHRSiIl7cCnmRi48
+RiniWVMzEiXTlq1x6mzjyYwUe4jHmTlnM9g9CEmWNq20kR7HoLP9q3prn2YujCSW
+uQZ4PX0LAqRGzSWSLnaSd76lgTGaDBHoh8yiu/MTU7vLXVVRl7yUZ4HV566WsZ/V
+puyIqEIkvA6KTmSZUkqQZmGBddhB3Mo9xweScT99Xvr8h2SCtSwgSY7IcX8AxG7r
+DW7d9EtDX2WgEHfAd4GpO1K90M6KMCGAIYaj9gVMccihD/sEHl2IfFU34732vHQn
+DVb9dqve2Eg8VFWy/gA3W+iljxQaQowijKO2PeSGQE0AvHdHw9PNcRH9y4Cq6pyk
+nQWuQUZFuPswUdqMf1CttkYJBtX/B74drFxPuPANK4KSaZxImhQtT3Xq1hmoMKA/
++o5AQeDQP2oPIFY4mVvCcuODch5QUY97EXwkdIQVHRr5Np05j8HIKZQAs9QUS1oC
+cvwx1cDPpG+9jJuagTUZFgPSHEYYkqOs1Z34rAd5cir1d8VxLxDfbY0VvWAAHdun
+1gLvPRGUXFKqfMHqqXEANhkjfd9XRS6o6D0RxtHNjT/FFQZ0uwd91yd8EOXgrkay
+Ye+C8yTQDL2GkeLPBAjhZCTC6pXpj/AJI+q2IqiHvbQQLaVD/Nu5LfhIPClgHeQQ
+W5TJA4yRyOj0Ra7Trjdjm6kTZ7ieP2Szfc2DgD4xjJBjoxHXzCjpp8DjzfN/argg
+RdIpOunrNBiaqOOR8Ecwat8FuKUeu+FWlxYoMHO9Q043pd7xm1hbP0VJkZ7X/X9I
+imvyoH1rj5xn85PNau/Rk2M/iCYy6jDW186bK6lv9PYPd5T24p+K3cEz7TMqCgdY
+WSxilutzw+P/v+OF+nOhju7fE3jRIAAH/1GnsnXoNxZQbjleqr3bilEQDYOAbbGa
+jQlQ45HLK1Gc2XY14/tAyoBzsg==
+=Hz2w
+-----END PGP PUBLIC KEY BLOCK-----
+
pub D73C68EE4152C255
uid Eric Chang <erichang@google.com>
@@ -9978,6 +10461,226 @@
=qDUR
-----END PGP PUBLIC KEY BLOCK-----
+pub 3595395EB3D8E1BA
+uid Ralph Goers (CODE SIGNING KEY) <rgoers@apache.org>
+
+sub FE694B892910DD22
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQINBErygmoBEADbs8zVUn5ZwbsG3tqT4x6U7SZYOtd3WXOtHjuu9Cyp74rZ19Pi
+XNbYwIAoCgOI/nXVWwuOrNJH0pHaQ73slbNzLxo2ahQIkw9PbK4V3YXLai1r/W6T
+xU94s7WECoiH8uuRAZFwbei87/xwwTVnfwQjKBThom05LbOebtIGHkSg4Xl3b+Me
+5iqHYiw/QOujiKOqm05s1aTWtm45KB3/u80/5y+2+/vn9HXor61gibDkC/oclDuj
+J1GYPCIAUvj95vw5n6Eq46I6aoed3BWCLD+qXBz3QJjwIKTYLOHO9iTCjPk1UmAq
+NQhrENV7eeahFIDgL+b9wsm6CwuH36B7cdobsOltqBegpMczM+kwTbeaVwyI+S6Y
+jQflqUclFctJCRxZYzUUL3C5X/yvb8Bj+WmoEjm3mSMEPUC+KwWeVGaXIrdw/yzX
+Vziqu+PVWZYovNKsLGlL5zUJt3nV0xmDJdPuLRgheIfB2t4oqn0Ki/PzMLQhhX9+
+9zWc9WD9V8cIZtiSs1hRny5Ns33nQr0KkdGOj1lfVcZVrDv64VUSzofH2nGEWS+f
+h9gkgD3aLHppt2XCH7tJK+wU/NlR5/0j+j3QwAfG5pziD0zMjvnKREfJ3aqqu9jj
+8FgdJ5vJvo7hlq0zakD7qTUO0OJiELHcf8q0jfFdiqaocs4HZp1OO1w8hQARAQAB
+tDJSYWxwaCBHb2VycyAoQ09ERSBTSUdOSU5HIEtFWSkgPHJnb2Vyc0BhcGFjaGUu
+b3JnPokCNwQTAQoAIQUCSvKCagIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAK
+CRA1lTles9jhunOxEACwm5J1+TvPfwDA/HTKQcXwm8vfyAgf7HkUVoi1BRcJpqWn
+xa1KO3YIBj0luJkXw1D1LowLdH8/QHjjqxGliKqrKL+F7mDPlpuZ7mqj2JO+LUII
+OXMD8PLqjJ0rqaZ9u7IuWAHcFHoy+wApkqCQSFIMUTQREyoBgQiu2lgf4vGB3pEN
+O5Hsulky7BdWk/2v2ga1VdFBURh1Wykd4RLd6KLhonsnNe3CcParzzKTHG/JkTIT
+4o7wZy0erv8UG4OBU3Db28Q4DiCCnwWb2LA0Az9eC7WRaIfA+Tx0x4PgtIhS20/3
+GZp9C1DsTsHnIYy5KLhx9hReqiky0Hnkt9puLVWyhPdbG2K+7KZH8CX1elTrCLDP
+o25YwP1+xB9vmBoiKUwV60Ap5Jppup6k5CISfYzIE7wJ/pn7LXoE5m9H/rmWXQpq
+f4GrNvMOaAiXnvYR8N2qeQeMwYtbm/hZTk7mlrf1xgJ5aHq13T/jaxIbFBdvh32Y
+jPXNm53LcVf+H9uwy71dsmwCnnq6zxg83pBu2bpNb8d9MSg2MGT9yLdin3bvdnsy
+9Kd4D08YcbdYyyby5FHpMFtqWSVvoCwsvztVE2bTC/ruR+AdZGl1+FxooqDhxeTF
+V3Sxf9zA7mVKZgVEdULvmi1gT91YAVp+GBg/FY6pf264wneqzKrWmdxG4oM6fIkC
+HAQQAQoABgUCSvNg6QAKCRCZoDAp3foZnp+SD/0YFV69aE0B6jBz9urCCSv6zLLM
+r69LZFc5tWI84K0kzV9w9TBPx69Gibv525DlbCtGKsW6LRvivtM06nh7gvd7GfCw
+1mKNkOns24STyMg6P5AOjywxCgdrDvsz+L5m9hqgUihCId7GwonpFwwbrkQTT9Vr
+91szYoyjG1wX87ab3qaZYnZifHp0m8jzJjILDTm8hNIGvQMJsBQ72fqQZK5puJsP
+PP2IYPqu2bCn5POBNHsxML7HOH2x8mg3m7rs3kuVpuaOg+Z0ijJjDK2WmpfYOzEe
+tbX7pHXtoY7++/nOfvwnNrCpKpsuNZhL+lGO8SuKfF4bamKqLKNbu3V1ptIUiDHa
+G/kB7PJLDp7GQ5kSzwLGeJ3KJUNxtapNqSvcR4/m/QL+fZSN0KW+x0t5wpOze+BZ
+9dYjofhJLlzZ2rfQVszHwDsEa+ZFuBaIcCMp/s9cTS8veRemGn84v/jQ51mFxMOR
+AYOXKtfmASIeIRs2VnkUJvXklDKkhOW5OIs6kWFGf5jX7V7DcMes225iqN0xUQya
+A7Grqz7R4BAXc4jVaBi1oVFdfsVfDNROj6XMoe5UHVbbbl+GLUZWe201wGvRuchL
+Dn//tWs4IGpVly3drBP2/XzgkJ/7HF5aVDmbXz1//0sA9v9FQ4DlGrebbsOtoqst
+v5soDMDdZj/VL3RtzokCHAQQAQgABgUCSvNhDQAKCRCFj8TE9DhWo08eEACI7AZR
+nuCxqhjlPjlu2IpCJFAEalxwfhhbrS0ye24AeK5ocg2D41upNYd+FdV7IK5T4jf+
++sZgy6QUHoPW45Wvut1qxI5JLjFf65BD8DkgddS/llU2rXoQDdEdrIn9DiKsxFJM
+Jg8phu0iPmWtjOIR+Khr9g0Cj5aWU/saovxGJmHVYjUvsptENi8sIRyz4LGE+z33
+3phJ5fm97FtiYRcqIuUo3XP8xDlFbgJPB5kcFOaZtSxgMEj9jQN8cKWj8z5UXsvu
+PKdhoaC6fUvd7+kREHeWgcefopmP/LJfUheHmNlPYxGCLM+MwyOXVP0iW9L4w12M
+nGTTsHgDipDOniEnSxAHKQb8U7LCFK3VgsXbX/qVjbzn5wW1msBVr5VslSxXq3+q
+Agx75GuBfYxAcd4boCT0KtrkXDTTk1k47xL9Xn8miQ/LuU4ADzq6md3gQHvyyImL
+JH3KGKMkhhMq+Derbprgl1pzzmZ/dpiIp5fky14OY3/561fBjHoiJd1U59YDhBX7
+xWPBQT7VywCWELHk9RYSKkdpErv2GM/sk7xnzGDDKCULtiemp1oUrnawiVOopDCo
+yZI5cczyNO57evqXc/Nj4Wy6Vwbe/Eb1eQJgek/+8QcoYwrCqvOJ9UZAYw2tmnNf
+WBnSsizUtdWgbdz9BzG87F5w9lTjCjpPjCdSW4kCHAQQAQoABgUCSvO7pQAKCRAg
+XIZz3HQsfEjZEADcQ4FWZIwSCMB3aiADaaWPQcPqslBUUrzz1kEmWr+TiWscWpoZ
+eqLKDejbs6Ue3356ZUoGxi0+OI3O2uZeIv0KPdhOEA0Ry7axe3gzH1oq+CtLv+YV
+gkDJZlOU5flw5pf1zHw+V/eXgswhV/QguiyColBiqaBdusj/+d2utIY6QKooWA7z
+215lwaiJOg/QT9QCl2LRBMVMONBrnDsQ6VNH36/htpFCbc6NIcSEl0FPlvLgOlUk
+wjs4IsQuTGAbH54bt4MmpIwQXBaqzpnKDo1XQfrReXrbdvOkidv1AB2Zpk8VnQPp
+Sd9tKK5N9hg761fKY/NcuXDB7S2c4yjC1e6VeLvccrrWPNJmYjtJQw9pkuAN/Z5R
+ficCjMEznQF2igVJLU7mIuKneqcmjipJf4XBoYGTZXveNk83bHIJaOZ7Hvl6cM+Q
+WdFxM1nh4uqOlMS2ez7HPwyPmAKnnTdRxigXU+28g4FXU0M6BNYCkwH1g26cj0Lb
+/p32paZud9JariHpfsYA8BOdYymwG7pmW9SEr8cXC23dBNPc3q9x9wX/O8ojigvk
+hKH7IqmREGQRAa5Rr8yWszKiJFEy+Qav7dAGhLajdETlbfC1A2dhGg4qihDKttvu
+nW879kDr7/wlwJQVgb+cCct9OcBZUmWmhwNSTjut4rPXt5hVs9dwCFBTI4hGBBAR
+CgAGBQJK87wjAAoJEJsf2p88BiIxDqgAnR6QsJJHp/onWzM/kGahZm6V0pVrAKCE
+zrOSIlpEAGUJUosqLNYk5XNRF4hGBBARAgAGBQJK+wYTAAoJEBMuSdTkHtx+WxAA
+n01w9c2UA27Llq/FEaeT9X0gI1DZAJ9oNMDR1PoM4XFT+0tXBcjbX4kTVohGBBAR
+AgAGBQJK/IWkAAoJEMnHkk5RBH1mChkAn1aU9gM9TR7vAo+hNhJgvAYvQhcUAJ9s
+pL6c1tFvSb06F/LL+M354jK0ZIkEHAQQAQgABgUCSv4azAAKCRCKr4jW2E5Brmqr
+H/9dhFdIgjoWdhMIdV/J+/iJEX2I/WYFYjowM8JGaGvqnyMqhRMUtFW4lPfWVfTt
+3YWePlsnFm7ulty19h3XWP3kJcTzCTpDqypsZ39Eg8FajdjJTXaEFZDdoVuOWrzP
+WiTcf2OJj7UeVdOnvETE3AGWzYR0L8ZBrZcStGgsLqm5cIe1iWPx0YrbP18ESous
+GpOr+oUlW7FoA9rrbQnu9wYRoL8ykfMelrksIMQqqjwsCN7l9qsHCDuCrjtz/CQe
+iyozYbLVU3gaW9E2YWg05ANKA9aNdUYmZKxkBikEcgHUeT55rWML19f8sfJNF4fU
+6P2CTzuGLBT5ycvgkaUNq3im0bIZ0Bq/j/6d9nLLh+cd1HW1YB11kodM1k8zZhwP
+NKmOuo80B5DNvGEjeIvPRtPWFkNIUebbEa22g2+SLbLuhROc/M3YmQvH2h/GvGO7
+Xe2O+mGjFuS4+LWbarVvycXUKXdxTTjg5dwAgecR/OFZavTXNdEsut+YHWRrElqz
+dd3/wYrafHS+hNCSxSSnpXWrcWMpyoQN28Nkg6bQ97yTZO09pf0o7rWK00Y+ZzrI
+UIF/Bgv8bE7tUtQBKTQT2kIyqnLEJQgZ2stQhGVbZJ43qGIzj8ktfswX/nY1qWiS
+YDR7IAb6HZrhqQNzAP4sgijL9+eBJfaHM/Ywf9WUaiDfzRz50wnz5pPz+NtN8yA9
+neaqxGZEqVqK7HV2VDfMrEucE4N+jQOmGgvF+ZPSoAPlwJkVbrx5UHEhRuBGOy/T
+F9Nvu9skd7M/wGkseCPhBAC3zXvPY8HiaoyXNn/ZghlD8zzJNkB84EeQ0ZvHP8UK
+F3QZ9m4J/TjYWLjUqNc8JIgKgrkvRg1ckaPVOm0Pb9bkdDSo2DMBAInNztxLlR1+
+/dzOicRqcPGqEYw3wMFi/zi3zffjnZjc97zep1DMtylwyBw+RXb5+t+3F2bRAvAh
+PaKEuUNVf3Tctrv6jaCv7kWI6pwt2joTbFpNrgiAwS74Bk3yUvEHUlZKLjwWNypE
+Fu1o4nQn5KOAahLJpiJfyqRC36+jbyGjizEdROQ500Hd7E2Sb1lTk43LRhfJwz/J
+0dP+dhdDHSbdAbMo5ClUqCm1jgY0oAs1Mj3BDXudtaX7OjUTf9ueZSzCKGSlvr44
+kXuhjEWgx5mXhXrzx2h9j5ZQuYORFEECkXnmCaJmXtAQRBGEw5KVC1FNTWGeGomy
+l5sY9iPVjr+S28wmrQ2aeHNnx6L8EbcuvVt+v/njHbNuMM4y7DPH8tRq68p/EpTe
+C8MBKyJdE4YiOCTrAVh6a6EdH9qz8rmjvF7ctmBxsmVfPOE1u5tEEz/J3ccHHVuJ
+lR4x2iHEqZyln/aEQaYQOlkMiQJ+BBABAgBoBQJLDN5nIBxTYW5kZXIgVGVtbWUg
+PHNhbmRlckB0ZW1tZS5uZXQ+IhxTYW5kZXIgVGVtbWUgPHNjdGVtbWVAYXBhY2hl
+Lm9yZz4dHFNhbmRlciBUZW1tZSA8c2FuZGVyQG1lLmNvbT4ACgkQm7hjsPUbuIpS
+SRAAmu3Hpy9c1d3mXKZ63mxb6thSL9ohiUxqyq7BWLcB1evW8ikFAsMuks/j2tF3
+3Oc4r0DL4c6GpaqEF59xH1Q07g+oZqbyoBiNmTAdRNHtdl2xDalcyrpk1686ek0N
+JG0LDLQZ6HYYpMQIU29kqK1FOZXD+LXGl6kb2FKK8Zz+2AddEB1t5pX9uSWa5r7N
+FqBjL39KszdQvxIXmuZV1+U/eNtkQ4WIkQ5pDLdDoBKL7ypIMFeviSB1uLemj7OU
+lqUrg1bphFC0gNYKkHR/UX+SSjPB1QZPrgfJyNzCin0mhbPxqWuB9E4U368+Cje1
+1+p8zwDBd5gRR5OBhEqUF24mYUyulw5WVbDL1CcLKK+PuRybjPrD3Sh+g4YoDmCZ
+ok38q2tzZf1uVyvmEq/bpTPytIGSwMREQQt0boatlPwR6Hk4tR8fWqM/5pt1ar8B
+kJHa62SscKcYIggkw45jvlfxSytuho4XI7uFkyl9EZNrhbel0FpPQpYq2EeiEouV
+i/cQ0+84NK2uESW++33ZBX+M+CEYEKPXf0HPf0hHZrPy9wvFrXuAHO5WGO1z/0DC
+Lvx5S/RNXKruxi/hbdlh6yOUsJmEkImmb4+fLZSFsber/Ffe8/hQUdVkT0aZ1Anh
+qNwbNYZryMkxKYw8In1s6DSJ9059AenRmldNP0W0ee1zmICJAhwEEwEKAAYFAksN
+KVkACgkQEMAcWi9gWedWJhAAuNDevOkI+kasMAIF9cSfmeNRdlwch2B4Z0oC6PBB
+NEHHtLwiyvT2wA7KbYuoQnkZJeB47dyjs9SgT7uy+IhX7Q3rcm0uMRAUWmkKFhyN
+YzxyleCd+KeK5GO6wCrdxJk2BOuQXZoyuTQmBMewSIj3TfnwzOtMN2n9XA/QC/JH
+6b/AnOuSwfgFBMX4bYje73F9VFf2hquJfhPCREzwDmkH8q3EI+D/qPOmKGfQOxXl
+e7jmRjmLJoASjMJjEhwty8/Fw3Djh6NHAntgQF94dKvtv5C5y0endDnrAXX86+Of
+MV5c92mUbHvPL8IXb1ZsCRRwK8TiA75wLF9c7AxzOoutnwHudhc8ztyHLqwBBlmc
+wzfEOooiUl1Rmk7uB3VHSkDJAmHLE/fjoo/la5PG8BqlWmyEoUW72GyhPNJ679AK
++FMTBHi84P/gv5nGATEXdhTIhVrCe+S/FNlcUFz58L4WYQ59dCH0T/WV3vU201jm
+fdlAnBBSU/D7o4+GBDw2FyBZbyk+LH5boPW1GO1WUt9rDt1jfqOrGhHyWrb3X1KD
+QHqQ6sUbs4fDRS7bbcKgbM+gTMZbfPPG642wimO8VTTw9bYRAusiqK3LGwNyl4e1
+ocs8LikhFffaym37Go8Vihr4baJJtfNQZuTfoI1+bdBjjahzhbOtFTUCy1YKxphv
+4xGJAhwEEwEKAAYFAksNKWIACgkQMYF4WlJ8gSRgUQ//dUsnTZLTY0XW+1r8Zo2j
+V8XhMFrrxZ8+r2Xp55aGIz2gA+fNjPbFU49CyAvdvWZJN28fmdI/fjA05ExQnlP8
+y9+I3tDS5wb5otP0lWIRs7n+pq/zCjKvWyygbfZlk+MJkSfGkwn43pslxf5A/owR
+Ul6PqIV381rHCZm9x7z3e717gqnA28NIvc2FgLKNyKc0x/MDcTyvJk2ZDPiBJaYF
+4LNpUO4/PteHWIf7ngYEsWG9nz04R53YbWSzr9c3M1Ak90enpzDnDuG0Kuu/n9+A
+fkvr4gVCs+prMN3FtKJxsnUXCmIoFpEM4MyVvllaqEVec7mgJhYAQIrhLbg8qzKE
+BvbURpLnyUOg8v7+siA/gpD+ev8n0XCJsxS3d6JR2ID8rQWJBJgh2e8Cd7q6bAUs
+FE60sHjbEhKchn9+ELv+5AA5m28apoUk/Yda+tCUcCPyv+qaGM2YCzknuSQCs3OP
+Cw9zzDqtMJrZA9Q2Vtv8IKg9xuhq9yj3F52BGMI36m1eKt6FHiB7onngH5c4oWGu
+KNc+0yLuptYycfq2Sqz8BkXKUjKIZBrCUnmG0ikCAvghv9bNOoss0Fafyqtk2/PQ
+XB5wfOBLGJeD5ylz8R8PNDPfwAoMr/kOGBVNa0ylMfw1ZjEh79KXSeCuE4+36kMi
+9nVM9RawVdM83lw6xITpE3OJAhwEEAEKAAYFAkslSJMACgkQMXxt+Dx3Bc/boxAA
+qmdTex9THGjThyWp4xF+bBhWSA8RQxovweFlsxAlgAS9/Orvq4BX8tddc0C3Eqmf
+5obC9O6KznF6K+YMYGUGPNmnXlaQBc13TWvaCBY9CDreomQpnVT17toRKn7bpyLp
+NmFvgyUq3TDv/jRGWABnh3fxFFQGMMeod7ofpZHBQjoe9IqyfQXB473/5sLwM6/5
+v7taFBiWEjCgZfhFMO5yLeLrv/5dGOpaMqeI4sLuE4Lv0bPrWw7GprE05jVTdgqg
++lYiFaBLPWvsaScDWjR5n7HluobCF8OCLKdLOLCW2Z3G6Ny9UaJQH9GEFTO3aKBz
+N/Udl2FMRvhlHJV9AsYEmF5vlT7wxndv8joG8L1y6d3YoI2FAAAYmMimr/JpN6g5
+3Bqwee8dZC+NgDukdSFcUWLczfZye2wZGnsGwKhsgJ2wWoNR48517BW+04Ee19NV
+Mp/nWbxPufR6AfL7HknrwJtisHzDI4MCB25Q3DCX91P51DVbZO/YELJI3WlVP3Fw
+F0BtKy9jEdOAFEha95DEodOmfmsCDISAdFua4OkEex2uF1bvQ/5jcI4LyDb4UYGv
+AeOP4cq8wyN25VasEN/QY9/aidBAaXJUKpQ3qJjbhYKiKqLOSJWDWt6saYs4CaS9
+dvIqeTU1DT6hKA2JjF5qI+HH8H/KKMEsKeUHjQnvVGWJAhwEEAECAAYFAks9zT4A
+CgkQ7Thz9dMmJyL2FxAAvkSqFOcH6/pb8ySduVNN1eu38uDmRky0tRt7KesHyCAm
+t5li8ggB5GGN3h7khI+qX2I218Tjr7Yddg8OVcFvGLYShaSc1k8TK7o9b0/MTRv7
+9uv4LwV/RG7JsyZi5Uu2w93XR9Q5bUw5rCEWznFfqJoYk8Ei+rK0mcS/zubBWagq
+SGJIloGWgmihG+v1Gc1NMfkCkascNil71hVkrUCavpSUNcRAliVTWDYjaKFdIZvg
+VqBI8hmOT2fJn4oZEGO+pMQREfZ0aeqXluN230oczc8UP1WE4iH8ZvyKGuPii/jU
+832hTkc2a6JTpbzxEPVxRR0g/xeOtMkj3yqzIfz3hXy4COZRTZ+HxJpgB0qgaoBK
+uI3ZQbbhvn8DWZkz6q5Oiug269DEWBrPJGvgg9WySoxsEpiy0oby0CNOflY89avh
+uhbOJTWJhL75qMhrP8knKBYA1+hIzWrk6DvgqdxSC81JRopFam2+n9eQtYtlDBdA
+1Tps1t/k4UDFJlhtWKtAvHcjyEiLZWlakBKunrBjzvzz1Fa2h7ZxYL1nLoWzjJw3
+UYZQot45Bb+2k+KZU2pIkZ5Jf81nkq8c1XzE6e2LGVwnhYWBnfWTsh4ul2pix38D
+/73hcacyglwcwgns7tNXG3PRt6UtQHOsXZmhDXs3Wfoem09Cr6li9VFDyupOI/mJ
+AhwEEAEKAAYFAkx2kzQACgkQ4TYIihgkvcGpHRAAv9/gGet3F5VIKwisVoRVg0q8
+7ZtDdou8iCo9KsfqPD8jzFot8p5sNLwU1R4ueo/Th2/+XpAVyg0H0NFgV94PIh43
+3n5+RCjZyLZh4ae09WM4IvJCe2VTU2zww8jbO/GpKH1jsk8M54CboFEe27rMGdqp
+iqq5KaT+uYz8qVXaV19cCHYHHPryRYatQM3QpCpC0V1+WrpB+Vve9TSzvWQBjmmM
+dZ+VleCfscPYyqo2FRzFsxqzZB0RqBSR/eWOwT60JdizWY9XoGXn4aq5M5P1olUV
+WmbjztG29PsATmUy/11nnipzEIGZHsuZcoXMUP0GggniX6zjswGHmdziRh6XG1rT
+lJORC9lqP4ASIP1NOaGifw/ai//QQrpl+a82f+zDLVQKDKxMLcU+3UItaGfILjBY
+DXQq3HPNdlJag1RZBTrUGZ6n07A/jCmt+KAuF1Hb0YAOfto2fMOVNNKNfRv83EAF
+KgnJxlg/HJteeeFY16daxSOQLy8x9J4hQHPFJJw7E3v6M88Gp4kSzmGGVNOmKhRm
++RrMiMVb2r4n9AOy0p+ypG7OmfyOFhomv1LlI+DL9xYYJDOr1HiwA1/16MizjrHB
+DVvHIJuWZ2df/d6rkliDLJQZ9PePx8olL+x/jO4csZGQyVgGbPp6QcOtpOr90xfJ
+/b3tdJ1ryye5YsfDcQ6JAjMEEAEIAB0WIQRFvr7slQq9Bc8O9cNQoE0MO2UX8gUC
+W0HI/QAKCRBQoE0MO2UX8oicD/9brnyHfogIFYG5xijNS0M39H6Ym03YqXc/Fo72
+zWu5vvjKbvcp81gesvJ+AUO6wm4l/TaFny8kh5nazX9YPNrCJ5+9KQyLmO91wQfg
+NYNAt/HcX5mllyNkAKkRG1+VCQhaWC5D6dFVNhrR8tpNRX4TZc4ReDe4R4v9g7Yc
+JQ/dSCeFL5NzsK+6VTFb8+kcwct8C9F0SAj6+3UVOZpy4tawSW+jgh0NpNxDkfzA
+kw02DcOEK5OtnaMpYLR3+5ldi2tKksIa7KYuxLoROc1pVImmhxJauBsA6iZ3dMyj
+nOhOOKlMbP4Xu8OO6VrdlIvQ/d33UaTFrluZisi9xwC7USRU6bw4gaTbJs5p1PDu
+SyYEbbGTdNpaus+WPx8zaIWwZT5WFEJy1bqbJLCA2FzXgcwIn2+kFGEe3LHOfcuq
+MoN9Bws1DjC2stj8TIwSswa45pNrd+juGy2oSxGwQgfoGOnc4xwKDcVUhTY88ri0
+SKGuRiyXxqosY6dDlD5JtBjjugnbPLbZ+N9r8G84QL1bGLSUBXCbRGM3Oipey6KT
+tIEkOOCP91HIC4gTffQvJMDoZgesAomTJMc0ewKF0pYxbVVBHCpjnBuwxGjkTata
+uUmtQxxbRYn7gXhntnT0UbOWh3oacB9aH2hukiGtTE3pM/nOdKfMM624E3Ib/5Aw
+z9l+qYkBswQSAQoAHRYhBJ3wRze0Cwj7B3lVD2lJ0a89vRVBBQJcUJkhAAoJEGlJ
+0a89vRVBzWYL/RxSuLp7NK7rV3Pq277+klBllPWCAsP0bjwGT92WYIQZxW09hJPR
+te2dFSmmKCVyUebGDMbdYqFwolX1QM3Kp8J6TWCzREbPXYr4eZGcdK3vL3TIJfFW
+bU7ZxHRrdD/QviObsivZfOvW9u6iRr1panCUvglXoTnG0UfTywAQrG6v4+DTZBUb
+SKCajUzoK8F2KZPsofZCSvgvqAyN2UYza0MjceoE8Uerw/SIrC4smBpR/haAxfKJ
+Oiyb3s1mZtcZZEinOVQHKuagoCEvQQS8Slb2U3UsRjydpDR7zcltfmgn/bcqxSC8
+IfE4biehgF/LaoHJWikugkWoGhC3ZwU6wWNFQ0RVwnf+iabznHiOqJSLp/Wcu/lF
+/GQOqwlCKj38rgwjAOirpQEt4QZOSPhhv56XggDeY6mG68X4u6ppc2soeHJuyA1j
+2ttJ6Bc8PZqNtaUR0FUqQTL/+L0DwLcjUlmgpkNYxaj7K6Jz9LyVgAl/+EUKJmBw
+UF9V7Qi+lv1jkokCMwQQAQgAHRYhBMR7x23wGSyylGW7z0ex1q0OaCycBQJfaMHE
+AAoJEEex1q0OaCycQQYP/AwF5O8le1jSWUFaDKnEhK25v7BDk7X3vKA35WCdnakz
+uTTPybuXd2hybbL6bihGqT1yhQgHQl1TvfXXKUacGSsHQ1mdyIYLhwnrSmYbwN8v
+NmUrhEmlcVRl9GB6fwLF7oHKsSY7yfha7AIcxL3Pui/xKWjEvg43nJ3kkqSRqoNH
+Z7fqqb/WfqSnhnG7m7PZ9cXeYR1HTWSVXZR9OrvLf/D6g6Fa91cWwnttYfLBRBdQ
+gvFaMp9lcYbosT+pQU18D1E+WVsOHA5wsJ4OPsSsgGO2r2nB93ilPBNLE8eyRWyF
+IaS7I0MNgGqhXQugyQzNxZ7Z5VlJZxqXTRppLRiWqAkGrl0hdD0qmNtx+5b8sOnc
+AFlx5WJ8k1xefoS37kqZ6hoeRWmI1f0DL5hm+vfMDKXXNYPYiw6pBYw1uAo0eNkP
++PcRPBJrzHJBlAcOmM/Y0hOeNZIb17zFFZ91kzH1e7JOEuufmx4K32i3xTOcCIG1
+biXamXfQsJ70Ca7dMLEudi4MP5rv0IoiQlNFegbUffofvJu65LUEqTzLbkZ7B4pQ
+MF1PD3bs6N4V67o+J5QyBMujH/09qGsYTLQ4QgkeJCP8oM5t0dMENNmz1nZo3btn
+HSJTA04ilIx2CEp6JAVHj1YqgA9hbKrYZSKsoQulQxQ4cMxPNiSMu7NdGoyf0ghY
+uQINBErygmoBEADOoPQARJ1lrbA+C2JJDBF36+fph6URbnYnc72Y/kddWdChXAnC
+KRN5QAdZeIQWEYKnpECjqS/UnH+E46l1wXSg+YdzFvpfWTGGqdmCzcMM9ooV8AtB
+vtUevbzwa4jBWTT1Vjr2BwWVai2J0zmNJnQ3vismZAl1u1qP2DJTPn5pbViK5noh
+8UTfiPimx++TcNvtGxC4ZvumaYWNAdecGBxWjqHw326fg/vmHB6vfixcOb2u60RH
+MvUxkwS4bsUTxJgM77Hr6m+UJKjBKCj5KKfMAzh/7gAR8Jo5S/8fD92Evh1iLvlc
+wjjYH6asPT6WV8wpswuh+CVG3EED+iqAyREB6Dks0P4qjGoUGTrO0OsaNciV/pPE
+8fkxjamSLPJhVAa3caBJefP8u7PCYhB9kOYd7XlATqv4jToBjVWIgKgzPs2I92B9
+VL0TcGWQ+Gzo6WwiBYTik+em7O4GjkItAgeYyX7kh0mAU35I1VX7j6y3HhREyRqJ
+SRynQybyi6m7IHbxUb986k6qDVUGMWsW61gyNrzqZFjcGDteDrgmPt2qgVcqO89R
++PES4hqaUSY1kzafylKxo9c8UAkbUf3L7KtV9rsvvKcCKrNbHwqsTdKeUq4Sj/ll
+UXfFHW92wnfwEJj4NiXOLFUNo8zuoIHMJUbFUNnqs+wR/CAFM8AY/YHNbQARAQAB
+iQIfBBgBCgAJBQJK8oJqAhsMAAoJEDWVOV6z2OG6XOcP+gP3lXw6tC7FjT4B/oOM
+tpkQ2NRw6FgSW75Y1P2d4fZu7QkuI7zLdmNjWZPRcEdloGc0p+GN+NKVBE7SKmiN
+DZwNDGdDiAiRGfsjPbBFybpQkc6IIZHXD4NgDBUj+PfeuvO2D7J+loRPezyTTAQ5
+x5aPyVvtYgjt6TvGEhn93SE0XDL3b9Se64pKYN8UKUjBPM9KHLcIHSgVBHdIxuGq
+5ohnz607NgMM321DTSw7jrVVGDCYn19q6J4v+ss1F6CKBmsXQFhjhe6wzUFzalcb
+8NV+V48yg1BPH0n52rH1aTlKMRDR1mwXCnPlavB5Yyk0GFloGSN9YvsSxg0KFo3u
+fu7LwmBs70WZFvgM9a/GTmi0WpS/d8g9u39f9d4VtXfd5anuRINv0Mv5iReoF5/h
+AtUE4EZ4gmFCCbStMq3EWX5gu6IUzXrsXnogdOe/1soS/dSfWm48aBacKmcXrMHH
+leD/ctrgDTW+RXJ2xvQ/QLH4RM9YJnPJF6e63l1AtQBARfP4bweN1F/5orzbgzHh
+YB+lXzOQKRVp76x7+3EQXF51v9jmN96MyoVfgzTtm4DJ2gWR7IIxrGKftZkjhlRb
+X6y3udIxCKlm6/ZexO7q1uKVA5xxab7nMguYGxIPtFPX56TsXyJvXfSwVWwTgwrF
+eHQMYs8Q+LJK0tUXjXfXSbqs
+=F199
+-----END PGP PUBLIC KEY BLOCK-----
+
pub 79E193516BE7998F
uid Filip Jirs?k <filip@jirsak.org>
@@ -11192,6 +11895,62 @@
=VojG
-----END PGP PUBLIC KEY BLOCK-----
+pub 32AC66C4FBF15ECB
+uid Charles Honton <chas@honton.org>
+
+sub D79E291A1BF549DC
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQINBFZ1ptUBEADVzx4LjDmWHK4gY03VBGRh/A+1CAjwdDtcrHPnoFYCYC0uoe8m
+z/iESYlAHRqVo0nMItZgjqGTPD6GhQvJn/fzXTjIpYIDLZgPMXxImHCSRAFnduI6
+eott+NFO1X0Ix/6RoQkzu8I3Uu5rKZ8G7KEyTgAUZDxIQB7kwc/2/bjPJm+YHN90
+7XvgqTCKjGtCbzqEiC/RdTKER8MmBwireHk4HXU3AzFgHTAnAztwovNiJuuxpCsF
+u5op7z8rIivtd1NS+kyS2v8SZLXyrA4zBCekFTCmP2m4tLZvwgKqHyUyzZdUuDQ0
+BQospNATpP0ek71IXNqwXDbdqjGglOmBVWPm85RMIe0F/VDgQsb4JKIa0XASBZIn
+DLziUcb4Wke4sHXRHZMKaegU7z5UngSM7YTSxG+13rhrVfWoQJKN50J7lKo2UuZl
+3/lG4Q4iDBVb+WBIE8cmBF6CZTSvB31/cpkPWqWC7sBpS6Npiy2f21hu9N0B19+G
+8XhAWLfw91GhxpTVQnYSumKWuSRG9RRhAOlRizG621GEPzngKLw3k86/27ZH9MFj
++zAJF+y5vKiXsKtWwFEZJa/iH2zQTOWcoJPBzRfFQgxo3Ir3qshYWotJ2Z2hIXD6
+ufgvWi5AdHzC/hxpId0pO5pJCswYmMap0jWEt6RaJJrJrZXghCPgNYJ0AQARAQAB
+tCBDaGFybGVzIEhvbnRvbiA8Y2hhc0Bob250b24ub3JnPokCNwQTAQoAIQUCVnWm
+1QIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRAyrGbE+/Fey06dD/9z/+2g
+CXP/grR1LzoVZcc12hOdI1ko9C0lfMuqRvQuWd1mkZZxmA+0yXcXv/iYVyQxxiyd
+GXfrSQGLypW53ozOs/IcrIOceYiNzfsiyBkm7MnIVGrMJ/5wKiVwR4jErJZeb1lY
+ZBaMX3FZqxR89aFYNPAleIm25s93nnulfYRpeHMXRGaRnkQoWmMVME6pf9jSdGEa
+q8KE8486nF+Ks2/cuG4JBqRqILl3nUigVhUk5d3CdoEG9u/nQ7lDYDYZzdrNvblJ
+A1uS1Nr2h+po1JqWD5Y8P7A1AnoBFQQN7AfuXSP/ctxvpKybpajsHyD4WInE6uoj
+lBi+EmjFjNoqIg7UltmLx4IGIchgLPMDxItYVf6cTR9ZvOhZz2ImoUq04mlAJIa7
+X5wUkd3gA5CdhaPVE1PLdMkfDLW0TEDVLEYT/SOxBAos93FNG6NsW0KUYTUyY2pN
+RdfeHlKgt2pohiXg0byeb54BB0/AWV4J+B5O19A6nP0b7GBBfpHHat1nA6rJw3z+
+jMzuVGoNhPAxWAwrwGJzECaFw4VdSSytqhI7hoY8P20SYGiGv361PlwauQaVfoaY
+thezlErtmHbWZR9n3LmVnx3v1o8XwDIp0tgOg1lUQpcXnQh322aJXQGXqdZunMX5
+0AtCyhjb7sUlkYmCQzYde4nuQAFad3m49dTyNbkCDQRWdabVARAAq2hM6uehEL+a
+ql/AtaXZILGX5rd2L+eDPbHdRMvGjf07DnGEvl8CC7HqyOTHhAJvYlw+oz6HKKxm
+dZDutb99HrjiL6LICGO3+CxNH5kqH0ku05tpqVPvVtfHgK0E+lpowEyiiC4Xqhqr
+5MXBBNsTxcxEUJ+ylJTgMT9BkKJ1f15/bvBXgKJGmuQYtL1+OFFteQDF9qM1W9AV
+Dv9L9uMVpm80yIHORDuJS2haijkaO9kvfPds7uy0B59bM+MqsOttuhPdE6EhQa2X
+Wlq4Bho/IwGxu60BGI5HreWT6RbH/x0242ZUcov9gonEIGqwsUjXFwMHy3RfpeW/
+8D/4ihNy7OhXo6tOIatoytz4QlYTOCYI6TUawx4HFJ/ewJubBzoFg3Emf90D4OCS
+WBpmaEk+s+q6/WNrJKAp6QeEJhPKeq9koA86svmNauK2AYOMgTIWqaX28qfQqB40
+6AzFgMeYdBt28G4snId0qgMWWZ3MN88VFNiLqpC4Ocly7WyTE1KYi3jzATTnHfz9
+PDaOpFh0GcstlPZX5FO3AEvj31syQZFSbxjxSyCKE63PtmIiaDnhNki0/2q37pGN
+pKjmB9V0oGdGTpBz8g+JVpwZBdedo4nEhqIuospSXnfnlwxupbSgqJxuab7W9D4H
+t2jTZdvGF1i13wr/Anz4APrXbRMYfr0AEQEAAYkCHwQYAQoACQUCVnWm1QIbDAAK
+CRAyrGbE+/Fey0UpEADBqujOyzHQfKwpncuPB75pARUcznaQKZLQPgqhax02Ti07
+bv0Gum3LV+WbS7eu7aiuAT4GryolMQvVQ7VfiA61y7z/+PLYS39xXwdFPuVG85Um
+mJdvPpQ4WXIL9POJqfTNc/+t/ZaKbg2DJu1lmIV5bNXMqHRLo0orHQRSZj1mAVJL
+TvqPbogh3MfNHMP/dmwyMqxBNnFHYVaGjGwxQvsfakojJwR4TEzzLJQY0iiSkw8W
+w0Uqmsh4p+9esIkkjiWn8VGOw91fitH15ec/Dnbjg5VnkaZQv5UHvzp+Pkb0Xdqz
+wOYfs4pBSEtDHVNEk1OViYedU6XNNryFf4O+MZ+E8jpXwEWcSPp5/5UdY5J2A80I
+c6Pjm0xT5zwJL7jsVMbFKY/iOiHOk0/MU1EA4tq3vV2xqnuiToGICQhqnK+1wi7g
+KRs4HMD/I+wE0TgwZyr/LQ6WxU5XZuhbJCICmtgDFK7dWqQZYj5VzCBYvPBrYfzo
+00b+LfT82QRTr3VN9opKj2SXWdBatzIl8RGK9CckhECSt5js0VtPt5PprrULYpAr
+K1GG/KvwmDjO4Wll3Na788UoG+B8hVu/1w/fDEd5EdQaQAXIh4iHnK1J0uuHQTN+
+ni8QlOqMP6kopPbnskwhaEtEVQRl1oozC9Wq7Zmh23+rdQl5ZkeBWEKVqlu5Ow==
+=/JM3
+-----END PGP PUBLIC KEY BLOCK-----
+
pub 5796E91EE6619C69
sub 153E7A3C2B4E5118
-----BEGIN PGP PUBLIC KEY BLOCK-----
@@ -12219,6 +12978,158 @@
=S4Fa
-----END PGP PUBLIC KEY BLOCK-----
+pub 2B172E3E156466E8
+uid Tamas Cservenak (ASF) (Release key) <cstamas@apache.org>
+
+sub 673B436865B87E35
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQINBGKVyb8BEAC+qG+3tDrZkCJlJwiU72OrX/R+cKQ8Jvp2lzwgJg2Sw/S0xXAz
+KqoxvfkcM/egEWbxUsbuYVVXlAuGwTJeg8QtiuqIVXyoEEmUoWIqjOsCcNDbQ8Of
+PCtUpci02xrIjNEf0jxE5YNAIB8pUn2MN4IAWtfdr+zlZis+vtDkncfW/pTngyDn
+Nd2gFAcNcBpuP6r/jqWb03e0noxhANls5kNyJcN1a9SvmZzOgSN8x8v7CjsDwBGd
+BPqpZ4r6Fsb27uchFVAMaVBEsvc8kXPs8OVg/e10OQYPoNq24JqbaNUlwflRajn4
+57t0d5RC08GlA3nGvvTvFGzprjxaBTNhQ94RmpgMMblKIWxtUMWUmGtHu44MzAr3
+JXlhdgYrKaCKKZh73vNJfte0JyqCEoPJM4/wieTTn8K9/wyLfIiTMcQNajjRu8K/
+OUrU81WHtkq0pVEm1nx71J5nrJU+fxQklkqMFBdnnQ1EfOd7ust7LtSt5Jp/iBZx
+Rm5ekjPoZjMWGS6GhTbpu29YQWYtmYLI59nXLS4E37r5A8HAZK8MxpTs71sUMgiJ
+aYGDSzdj4BJ9JE9Se/K/0sHy9HzEGmMAnac2Sp1oqLwttfSkzwJWr443qx2NMbFm
+8aMXAzOE0aHGLN30i97jhLg8ItBWYi2BfLtWbcDX9jkESkpZvwW07XuM5wARAQAB
+tDhUYW1hcyBDc2VydmVuYWsgKEFTRikgKFJlbGVhc2Uga2V5KSA8Y3N0YW1hc0Bh
+cGFjaGUub3JnPokCUQQTAQgAOxYhBCm+oqZF8tbO1/sS4CsXLj4VZGboBQJilcm/
+AhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJECsXLj4VZGbofeUP/2jp
+yfxu0NwLqcFm7NbkKPYUFahNJbjBpPxqnEkHhYZY/2nIPmOs3SJ858X9r3TRPV59
+/Usx9e4fxPYrd70YgYBMJ4YSNSaRH8PjNs4DCTTzBxFWQd8spTSxxkg4J+OQLFq5
+YL4cw+4dioh3J+CQgJ2SwS4qMCadmV/11mtzWyukhdudqrG+BIj8Se7TqFaMMPOT
+fbOpuG7fnE4ODweOUDKjFkucCsjmmRSgr7b1ElvrXjaTw2UOakvC2SvVSVkBxckh
+gJOh3oUTHhqGZTg5afAc/HOKpQYe2IqG/7iHNfcTdB28vEg6/cvtgl7WBdKc4bak
+93PYQ2+kMqu/icwDw/ATopu8M8vZRAyNWX3ZlK0zlQL4MkL9mhfcB1FDLBTXVdF8
+W5PrRcQS1AS5Zg1FbT4Qz50gsYLuRlVXT57lv0LacRUSqIL0Blk2pdRRX8df9bFm
+DVAJGedaoPh1EtJsbi7HRjGdfvWRn4aS6sPRYQs3vJzpmdWYSZu5bbeInem2CIix
+4+3fD7E3KI9d2quWhMB1ADLXCu9yCgNSJef2JhUHJk6gKnPxaO2MiWpB96QU8HHX
+1dZrR9E2g97C80vZT19zDCGAVPoKgrqtZJXdhssctIoiWkvFR3X8iZQEH69fKO2F
+hUjwFKWea3iOYmfYEnIqx+xUDf7u3zFSs5WQX7LgiF0EEBEKAB0WIQTqI9sTYNkC
+lIHn8u/s3+o8tEk7lAUCYpXfOAAKCRDs3+o8tEk7lM8HAKDxSThuCim++uviwDsX
+S+4B+JPL8ACfQdnQyeTl1hfbqyCTTudSOO9izPPRy+/L7QEQAAEBAAAAAAAAAAAA
+AAAA/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsL
+DBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBD
+AQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy
+MjIyMjIyMjIyMjIyMjIyMjL/wAARCACHAIcDASIAAhEBAxEB/8QAHwAAAQUBAQEB
+AQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQR
+BRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
+ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWW
+l5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo
+6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QA
+tREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMz
+UvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVm
+Z2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6
+wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEA
+PwDKxSEVJimsK1OIhYVEwqZhUbCmUkQMKqzyRxAl3C/U1Hql61smyIZlbpgZxWQm
+lXt0WmmSRyRnGOKwqVow3OqjQnU1SLzXcDciRcVA8sZ/jFPtPDl7MxDRFV9SK0P+
+Ea28SdMdcVl9ZhsdSwVW17GMSv8AeH50wjPSp9R8PzQqXgJOO2a59p54JCrFhg9D
+WikpbGM4Sh8RqsKiYUyC7WcAE/NUzCnaxJTuR8tTaSP3gqO5Hy1PpI/eCqhuJnTx
+j5BS4p0Y+QUpFdJJERRTyKKLgbeKawqSmGsjlRCwqJ6napdPhWe/iRhlc5IqZSUY
+tmtODnJRXU0NA8JR3SrdXoLO5yF9BXXjSrWCPYqKqjtii0lVFCKMt0GKsOrnktz6
+Lx/9evnqlRzk2z6yFJUkopGJqUUVtHuXAHp0rlby4JJAcCuo1mPBCsyoT3Y5rl7s
+2sI+9vPqcUQve5s5K2pmvOWypOfrXK+IrBPMEqfePXFb80g8w4PBrJ1T5kJ616dO
++jPHxFmmjlFbYeODWtbSmWPDfeFZVwQrHjg1NZS4Zea7Fqjy3o7l25HyVNpI+cVF
+dfcqfSB+8FENxs6lB8gpcUqD5BSkV0XEREUU4iigDYzTTS01qxOawxutWtKZI79W
+dsKATmqjdaRVDyIpOAWANRV1g0b4d2qxfmdrpup2k9wYkZm/2+1ad5eQ2UTMDkgd
+WriRKpdoLW6hhdfupn5j71a1O6lTwwsN4ytcyE7XXuO1eDa1j6lO9zm9X1uG81Fi
+8jMAcYBpjJb+RuktZo1PRnB5qhYeG7q5Be1lBm3Akt/CPX8K0bjQb1NLVbq9Mlzk
+5KEnPpW/u9zBOXYx3lUS7UPy5pl5F5kBIzmtvT/DbbDLcsyjHBPc1Bd26Rho9wIH
+GfWuqhNSdkc2Ig1FyZ55eI28j0NNtOGAz0rQ1G38qZu/OSKnSa109NtvbCW4YZZp
+BkL7Cu3m5WeXGm5t62EuR+7HOeKs6QP3gqC5YPCrgYyM4qxo/wDrBTjuS1bQ6pR8
+goIpyj5BQRW4iIiinEUUXA0aDS0hrEwGNTR94fWnNSJjzUz0yM0pbMuO6NbTfDXk
+awmqAs02CFUdACO/rT/HYhtoLcPMiyEfKue/0rqRNFbWJk4Py8Y+leK+Kob3UL3P
+2kykM3fG0ZrxIe/Ozex9PJ+yheKOz8HyrJqXlSMMlegNdtdQ20CEkKT7ivFvDN2N
+IuS7SSPJtxz0Fd2PEMGoW/liUCUDlSetKrBKWhVOonG73GaxqahGRXHpiuOubptx
+Ymrt7I3nsHOW9PWudv7v7wByB0rqw/u7HJiZcyILmVbmfJwM9am0a2SfXAZlzblM
+uey8VlAuz7jwM9a0tNu5IJXV/lEg4BHXHSu+11Y82LSlcW/jWPKJ91eB9Kk0YfvB
+Ud7kqSam0YfvBVQ3Mpau51Sj5BQRTgPkH0oIrYkjIopWFFAF8UhpRSGsTEaRTCKe
+aY1BSNO81drfw5vkPJG1cV51vuNQuZo7W3nuncYKxqTt/Gukv3U2rQyn5M7lHvVy
+yYaf4cjSyGyV8sxU4J/GvIaVOTuj36cvaQV2csPDWtpFvliSANxtkfLfkKhk0e/s
+U855lJHI2k1u/bp4IjLNJu3eo71Qv9VHlbeCWHJ9KtTlJ2SCapxRnz6kzzxOWyyj
+BJqvcbZEeYkKvcdyfYVlPdfvmIPemTXbbSAeK6Y07HDKrdMf5wMyDHyqeBXQzxKf
+s0gHRiv4EVy9nmS5BPOOa62I77Yj0INdkNmcbvcpXo+Sp9GH70VDe/dNWNF/1gqY
+DkdUo+UUEU5R8o+lJitiSMiilIopgXKaTSmm1gZiE0w08imkUDSKOowGa2bA+ZQS
+KwV1jyLYxuSGRsYNdQ1YmraJFeqzxjZL6jvWFWkpu7OmlWlT0Rzl9rzzoYwSB/hW
+PNfyyqQWpbzT7i2nKSKQe3vVbyT3BqoU4R2CdSc3qCFick045binpE393FTrFjoB
+VXJUWTWUYTnvXRWM/lxt05HeufiO1h6Cpr+7MNvtQ/M3Qirg+4SVkXpp1uLfzEzg
+Egg9jV3RB+8FZtvtSEo/HngSDPYn/wCvmtTSF8qba/BHWtZU+VJ9zJSu7HVAfKKQ
+igSptHIppmT1pFARRTGuIx3op3At0lLmkzWRAU1qKXY23Jwo9SaBoiao24AyOpC/
+iasx+Uck5bHJqsGuLnWII9gW3iHmNgcZ5wKTKsVPEGnQxwJLIm+PIDjHK+4rk9Q0
+WW0BlhIkhPIPtXd+Ir+ytLHZdShWkICr1J/+tXPaW5mNxp7t8y8xK3ce1Y1U4+8j
+qouM/cZyatk8jmlY4q9qFvsuzEYij9jiqMsbxnDKR704tMJRa0GF8CnWkLXEhnly
+YYunuaZDbSXcwReFH3mPQCtS8McNskEGNijr6+9dFKN2c1R6BCiXyqJC4WNsEoMk
+A8j+v51binCuEYHzY/kJB6+nFZNrdPbQ3LIzpJgNuXsM4/rT7Rw9zERvYsC7Ox5J
+xW8ZrmaaMJLZnRCW7lXMQyPfiqF1qN3bZ82J1HrjirdtPJGqgMCMenWpvtoYYaPp
+1HUUnyPyNFc559fcnvRWvLa6bdEs9vsb1UYoqeTswuddmjOKrQz+cDKPuZwvv71E
+9xm5kI6LwKwKUS4XC4NRSOq3gRuVddy/1quZNw9utMvWIWzn9JNp+hpjsaDMFtyA
+B87YqC2uZk1e4QpELcKDvJ+fIHYelSTkFoVHQcmsrW7pbS2l2LunlPyYPQYwaiTa
+BnB69qcmqatNOzEoGKoPRRU2malMs8W4sXi5jcDlcdj7VSsdPkvrjaBtQfeb0rrb
+bTxFGRDGMKuCSOtW1dWEm07o6+1tdN8Q2aXJVWbo2PvKa14fBOknTpZZA0nHG7sa
+8+sJLnRbo3kTN5MjfMh6e4r0yy123bR/O3/unHQnkH0rza1KcHaGx7OHr06kff3R
+4l4hnNtqFxYQKIoY3wwHVj71FYP9othGTynX6VY8YXFpc+IJ5bPbhuXK9N3es2xj
+ljZbgpmIH5hnG4dwK9OlJxSZ49X3pM6O60DZDPLFK8xeAOQqYXHB4Oc8Y9KoaVD5
+ZkJOSI8/nU51B4Yb21tnnKzJkb2BAGeNv50WgKpOx68L+Q/+vVRetyWi/bn90M9a
+ajcvnrmiLj8qhjOZWHqaGxosBiq5FFRytsQA0UrgdBBJi0twPSoFf/SJfdjRRUFF
+xlIiX3p9xF51gyD+Ahh9RRRQAqv5uxvUVc0vT49R8R2CyRq6qXO1hkHCk9Pwoool
+sC3OUvYIdN8UX9pEAYTKZYwBjgnpWypUHCgAHpRRQtkLqZ+q3MenWc0rRiQHgIem
+TXFtd6jfgQCVhGTkIGwtFFMQR6LcSE7mRVBxnOa0JrSQmKBOQi7V/wBo9zRRUzbS
+ETWljcW00ds0iuZIi+3+6Oo5/CraWcqwBDjLNk8++aKKKbbQdCRomjz0NVoVPm59
+6KKtjGXrkMFooopiP//ZiQJRBBMBCAA7FiEEKb6ipkXy1s7X+xLgKxcuPhVkZugF
+AmKVyoICGwMFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQKxcuPhVkZui6
+Tw//XP8LM+CHFvHxnHshpOGyadNJuowwhGxOH42bPvcbFljSCmCtc9RvIBQ3SnuX
+fTqroV+qdsnBQ4YqZcYlcm9+SI8GHYbqgwMMWDZj0+TbvjyNYdZ3RtYm+xtcZjZs
+q9lVt0C2Hat+McLdbWdl3vbgFs9FD5jZHZxBuH462QbyeqRe0hQbNGD1KsG/6TT/
+8s79wvJL66jEd1ULVbOnoyJ+8a3vyeYCVbebB+bITNTHyOzNMKste3yd+i296YbZ
+0I81svcoOFgOMQoP8+G/wRfpcQebuAR6MvGSmSJIR38CmOi5hmEc/zwH6rvrhuxd
+0DJFuCQe03ePkuJibnh1vsDnlLuUwO/LEgALaeTdzp+CB3CNmiiQVZMfdXmytaDC
+SxEpjVDbR4mWLS9xH0wuRc06Zotil56vHXKm/SHZk3R937V8ZdCCg9G7uF4Hk3XA
+DnSG914fBrv79CSyoGJC9R8NncXzVQ3bzvtLsKhqokLorGhOBT4IsDsPzxw7XURK
+Ns8E9IZhXlmyUvdE4qHctpJiROQ2nEQzcVPqHcwCDQx62g2cBjBILmNKKwtLu3WS
+dKUMySvdM41DYVKxqFl0zZA5bF83ix93xUp/uXvIJyGyRiIO/iFcUyKmEJ48OGcD
+MxedhhXypjLsZikl1zOQfxJ4Wh/QfUS/mIarhlgPekqaf52JAlEEEwEIADsWIQQp
+vqKmRfLWztf7EuArFy4+FWRm6AUCYpXKUgIbAwULCQgHAgIiAgYVCgkICwIEFgID
+AQIeBwIXgAAKCRArFy4+FWRm6D1VD/44KSWUUW2k513DuIr4oAL6ACs/iFBTz4CL
+2hduGt2fRbQlLy4ijv6NS2DyAkxuRwXG7QQ6GuhVJWIlAsmE2PjMozqrdQrh0mu7
+VMFYXHdaheeDEJyuCcxC/rCheoOcnZ8k2IJPxcyf1wCHv6pfP9oyDwBLgEJSIizM
+ji1htf8oxWghPbXNdX8j/UbVo1fQ1UjrACU49wgUXYJeaWj7FX1GqOfIXyQCQ1Fj
+rbwrTSW8oZ+R6P+CJTQYZLUXGnAhKXCO5PPyIFLUrjNMaMIhIPAKUHW/OUkvmEks
+57tti7txFqRNGkHPBtyJmXq6GcWS2Pv973V/sK155+EFwVIMOIxE5ekr2EUrtLir
+cy0BPF5W7MGWnmITw0M+MIyiPVr9g073xs1/eccm24FsvjD0U7cTgp9iT0uZ7LSk
+YzhRJUyt+X7AJjs6b88xeuh86AUsC6yzzWA7aQXHIcqwjUtKWvyFNs/S0upLe4CG
+29mmI7IONcUc9xljw7S9Soo6XdxUDfKRPb66SBBQ12WOjpc98yKUyw8vf7n5faZ+
+jCku5Mzx0Kxl5uVxKR4qJBZDSTQlFxql3n3aa192UvPv2KQxK6P8NuKTFXKOnfys
+B+Z/hGACyeiIymhsl6Lf31qpKVa6xi9byvIGOkcKu8gDT9h+TzlwOMPlbSPj+7xs
+/BmcVPQ3oLkCDQRilcm/ARAA1PBp+lM/7//FT+Xlg9dmh98dKa4TW/VRl76kuaOY
+P7DseMrB07Q/yiQSjzP76HazuemLuOUhOb8+CWCoZa80bob016qv1pRxLNhcuM2w
+nWnI9cHHGr+hAAQUoeD8RYtG3Ogd0Ep7IKjNZ3ByaQdSVwCfXO9gbxUVDfS950io
+t1Yf6dwF4mDuLQrL5go8WpomJzn7wKQduqF7YCfDQ8doiYkd8VLmGH6fLC6dE+WM
+hE7UoHgVBAg1jaehEPSkdxLki5JSS74eUKLrIYJQMbwqD7g4LYosyaKpQHg/Yu5T
+Nf87lPY1gj3djrG3LsbcZTozrr4Q/U18g5CITi1C04PaB5h1ljIzkxRw7SVoD5Od
+g+B/GblCOWhfVkoWG2MdcP7udq83kblLeQco2X4qcCWC7eb+N7zTd//khEsNosCo
+pYdNEXUPf2Cof+ghy737K7Rs7J5Pj3BC1TCkA5mfXtBTdf4CgXWOd7EIV+Xlom1/
+2EkGGDZqIjVaphH4yJ+mWY9dXNsomffIrPKxcGN+DZi2WnZnLzZ9fzoRB9hxIbb0
+WbhouziP37irLf7xc3B1I+tAZKlp28bWt7gt9v7Oy/FedVtkImzf+6IXOeTDunZv
+o2ATQQOc5KYmnOMSP6WmTKx+YR4DfA1xFoyAkadtmCB0BimD/M/ohQUJC0yAXTTc
+sDkAEQEAAYkCNgQYAQgAIBYhBCm+oqZF8tbO1/sS4CsXLj4VZGboBQJilcm/AhsM
+AAoJECsXLj4VZGboi7gP/0Mz4OoUf93gxKmxtpOhDueU1i0GQQDi3ZZx7usUkzL+
+HLnXKwqfDcqWkDOCSMG9P3D1iWEq1qHcawy/dRKJl5jZi+LMmxNmNINL/Ko+Cx5c
+lSJT4Cx3eZrg16KUfu871PkrsWNF2zDI2vi8dZa/pmajT2DnxmdGoD7tqcVGEfup
+OJ6UUgxjnpR8M/wmZ1CmC3/qRNcg1FH+aSPYQG0pKHmOlC72usTNlsSnVEUggOAE
+AB0/Oj8hyah1p9E13VSDmSFbXWShb3VuhVrAlo1e4VKyEJR3yLqkVBRrY8I9b8CQ
+GuKKaJyCS4nDkt0eo5BRsjVpIVsN6aDY9WDbxYpNACC/Ebc3tHnfsez53Lx1Eyy4
+ajzkMpoirHKQX2fldmw21d1gb55ITRTguZjcYqzGaFdZjW+LdtR+2HNhvQJnUdQy
+F589GfhxxLQygvgD8p+Wl9v/f7pDtEcbSt5oAIk9ZXiEpnHS70dYuqzVH+smRaO9
+vyYVQwCyBwo5gvXH5rkUY5wkBqhOEjsQOCdKx46avOZfzZWLd8U8vBZcgWkVh7ly
+2IKX6lWBk6WvhdRCkSCiaMWuuvEPiPhwfyF05BV9V3dl6sHHltJJ4x5SGK3IjxmS
+6WccwNyS64ekgi0xiUtGFNG2eRSlhJflAqRoc/C4mkLUVs4Bo3jNwCG7FwR39Ii8
+=XAs3
+-----END PGP PUBLIC KEY BLOCK-----
+
pub 26E74B6874AEE127
uid Sam Judd <sam.a.judd@gmail.com>
@@ -13661,6 +14572,65 @@
=GWfv
-----END PGP PUBLIC KEY BLOCK-----
+pub C1ADD37CA0069309
+uid Spdx Gradle Plugin Owners (key generated by Appu Goundan) <gradle-plugin-owners@spdx.org>
+
+sub 3F078B16810B4EA4
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQINBGRmS+sBEADKHnDWmf5NP1/WPGmBLTEDv/mSGZx7jpfjbaEcCFH3hiGbspbK
+3wgGE1OzFf6JRBurs8GS0gD4aXoQFz8saVASPHlKK/LYc7f6vYAAWj6Tlm1j2qwe
+TJ+/Md+Uws56GYqQ0Wm/PyXnxIvQcwwF69LwNlnIBePn0hOvxeiCaRT0hqDGwJGx
+tnPhlXYcqPNUPvBw9hUXR0nQc/jkwdumJjV8UKet9CECIzX/dcxtijpcVTNP+jtv
+7GjbXcB87vQ9b7iY5YexrWZrNS9PmknaW+km3PyaXBJ26zQHj0JFoNDghUNYxtgq
+4rBtIq24bYOSgi5OBiKZj7+30m7THSGQRARsUyOCgL+JMxxcbxB19dO3eN1uvMUy
+cej1OdY9df42A5USVBPEoUlCN6AOXfWWwWsnVp6gfz7V+Fq8bbb3vJ2SWZxkQ/tr
+qpCl11XBhyeBSEHR2WHgTEq+6dxWFUlzCyvhje5AH8Cgr8KLmfpNhzgmtNJL/BPG
+udxdxeEB6KViHfk9PLiK9mpAWIA++YbFd8GUe25bnzq0hjwhIAOfTSxU4wVcjZ1Z
+Irmu0HYqkUEA2QwjySkHn3eFTM1syUGNpgzb1ooSZYG+XumAER9wW/CitWJjFfFQ
+oeGXMrNqKV3BcGTjFyCw2b1SqJxr3DHYdGTbDO6/kDQ/B+oZRPxRbkBrcwARAQAB
+tFlTcGR4IEdyYWRsZSBQbHVnaW4gT3duZXJzIChrZXkgZ2VuZXJhdGVkIGJ5IEFw
+cHUgR291bmRhbikgPGdyYWRsZS1wbHVnaW4tb3duZXJzQHNwZHgub3JnPokCTgQT
+AQoAOBYhBH/l6Y3zpcDcNGY6t8Gt03ygBpMJBQJkZkvrAhsDBQsJCAcCBhUKCQgL
+AgQWAgMBAh4BAheAAAoJEMGt03ygBpMJ4+0QAIlxXDc92pF4FBlAYsPBbGDpy5VB
+ym9lrk6lXALM56MrJPctJRvDV/L3Pzm3W4dxUYKMuF7q5xpcg42/nI/PkCfBwRYu
+fJ8IJPoqVt8f8mtLQ9ozG7nUcy+vKpvN7zL6DKtgyY8bFfulUr2dzDzzuvBIjm4A
+GZqeABBnjBVXvDXNNKUAmXcu96euoVaR2q2NZE4gFE0Dydr7D7BmODPl506/P6vx
+VdMkBnCnaBC8nJHu+SFojjqQRu1xzc2diHy8bk58xreTvUA7D4JKFJpJLGdPisz1
+4qkyEhVQgkF6kNqiMbuwK6Oi7U2iB59S4s8gpRDKvcz7p9XDNYKXB+2DJ53dRnn3
+JO5Un1P30+We7GwxaD1uTZOvIkscyDQOaNFnSXxzDCyOso/a6I0J4rG/LAeaZ0fr
+8p5KUtgKm8k1ubsdzGHNwMF4uXnHVuUwfNPxDY4aF4rIrVsCU9R84dlNgdvoSzf5
+6v+h/sMNlMUG7hqs2X/z0FDErlmyfTTU8D6VWJeoIZHQugtcc5eZ6cyggb2IanEz
+FBheWMtJwLhcHSAlw1q03nUlRS12CbvD+dnKtyJsq8qkLrU21PJkJ/bLCURzoXiB
+Uv+BCT/Yk5A4wXAYJAciL4yz9/c7ojvdIG1V0m0XdY/pzX21aUBkn+xB8tuscT7D
+vCWhk2Kk9Bx7kzqCuQINBGRmS+sBEAC7mvPiRj++uEs5o1smHjKCoKNXM6JMKjK2
+LHCUD1WsLh1ZLOVVRRsOataBoiYEE6tqaQI/goKFHx/82BbY7a5wdxQsu+Y4gJ4M
+GHBU8ogHt9bN7zsM/dphCq8wEH5jg2FvY6nvAFdunagh/79terLXcNgvCdBE0lJF
+ZOBEOZo0psmnYHNMRoTniihOj3vcFRG/XID6laIfLMqz4xKLBQeYKeS4WkG/UL17
+NdnVNiRCefADfK6kgqunc6jKJZ6Cnh8cQzzyhJHE0z2SQBZx2/shVB0CsdheyyTa
+8V4hbFvddNCD1qPJjbwcyH5y4mNTKATspNR6JkN8Lvl2Djjf0Whg4pC1iDz6h7pd
+0xItD/hSBxjiflOozaACxWptgBEPpx0T+VY7AOit7NEFmbYhGMm1OmWunXcXDqeI
+02SPhtaDdq2QwV1zoGgoFTS4Cp95xoNcNTX1jgVUh0NdstHxsnlfdCP3olzXARU4
+pfE2fUToSfB/p2t2cVWDerdv3HxdDxYSCaSxA4rtAGfkhZAwM9n4o1HomWBSGKN3
+blpmpI21uCBrd9R7fTDt6UVSQf0e2s6Pt+qyOiAsZYZRxhvPqaTEWnR82O7elbNg
+Dcljlz7v1MfukiQdxazjY+zaj4do4y4ounmfxXAaNmt1Hgi+xKFD6y+/cGXJ1EIm
+OtKdWs8TtQARAQABiQI2BBgBCgAgFiEEf+XpjfOlwNw0Zjq3wa3TfKAGkwkFAmRm
+S+sCGwwACgkQwa3TfKAGkwlkRA//Rz1xjeaijjDpNaCwMtRPfHkM+ifd9DzyBeO3
+41FXn0h70DkOjC125SggL0b8yCFY2RgI+99UefMZsXfAIIRFHNjMWYEvR6TlNqPx
+wFs3H9S2b5Bxu+q9ImT7/Fcf4y0hZCle56TGMcIM4vJ1tKtFYN0ygYWJIs7fiMUz
+inQwfdewHiuDQpj5SpcnqH9kmXZZ7tZRcfSVpIAp9C3GzcKXdVC0dZN3ArUCZ9Wm
+7hV/brXGeYriBOJx1TOs/lpm4ePDUYKl5O/uccja1r69SlNQlcfAITSOwxv6Z+6X
+tR3YrhnuqaelHdIz4Mw8c9RDQKAjmDAuMPMQ+Qiq+fYPlKeI1eAGjv+eKGeo94la
+OCDxkUVcicWILxZC89l1Yt6gq3XU/W6D5KVUB9Up3uOUOHQcSjFVlZy5mKxwzTEd
+EBIeIvBd9z1C+QTuSb8znFEOLhdEE2MzEbC+XSPPX1YV7XYXiOeyBIXu/gCPT8F9
+wttHP4URjS1V3jEp6CFTDlF+NqAeUDK/QNXOXmcxohWvU5TGSYR7o3rYmyauHijR
+G1h/fr7P5M2vor620yY4TmrzXq8dRpjS+isSh7OWQ8iNKjzMFMyF3pjMFRYHQxRH
+HXpLegGow0UM1sS8SA4490hA6WG43DEvKP0cVVHInrFrovNfYvBf2r7nsclqKY4W
+LnWsAzM=
+=8kGO
+-----END PGP PUBLIC KEY BLOCK-----
+
pub EEF9ECC7D5D90518
uid Daniel Santiago Rivera <danysantiago@google.com>
@@ -14145,236 +15115,40 @@
=MZeq
-----END PGP PUBLIC KEY BLOCK-----
-pub 5A68A2249128E2C6
-uid Tink Developers (Signing key for Maven artifacts) <tink-dev@google.com>
+pub 69B8E32E23138662
+uid Gary O'Neall (GPG Key created on Aug 26 2016) <gary@sourceauditor.com>
-sub 4E5C59DBFF7DACF9
+sub 4083687620E57086
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG v1.68
-mQINBGPcwwABEADTw/gqmHh4LTSDsBP0KMoXFtFQnv7xmVPPrPjt0NxGn3w2WIou
-7UaLUTViKkgm92h72gyM7N9JfNBLcYrqVf9ed75MPdGQgzIhkVg3SLWZGFoIQUJ4
-VznKuqJmd0dSRtApXL9ZoVXf1mLnbLkOvfLfw2hVIsMJcW9/G4It7pPY82IiwTLn
-XG/pw6+wLa5FGCM4mldPnyBDR935nSkgnZzQJyDESXZKS1uiU1rMcGWkVLJ1UYfg
-fT5c6jAk+75vhyQEvHReoa1T8fgBPD0jAlE7T80460x8dramshhAAIOZLnlAuiBN
-A7KPY7cUDxDyFNLdhj7lGjPP1UTv5mdcZc0H6tgaapOB8QzqnkAJN7GrPHjAWnu7
-ujdiT+lmng+waiBfoQN7HQyJXng8Skj1tVYjuAUNgUuA6p1hL30k9Ny9wO2BBg23
-OXYn8yLptZCUg4T31w2ko2PReSxMeEI6S2jWTALP9HH1Q1sinQnlJ8SfPAssG8wn
-qjaV4PtS8bO+Gy2NosG389dzibrmVJAHqymTLlaviWgeqAXEwZhbVcSOv+B3JgAX
-h1dI2zDJUMGV7jNbKa+UNGb+di8T3J5JEXCNM/Zvm3KNudfZFbcNS1pEzNRzm4gh
-kmNHQEtknSm6NHaWIP5eMIxsKGUA6qTR8XE9qrvpwV35rwbxmPHSowHzzwARAQAB
-tEdUaW5rIERldmVsb3BlcnMgKFNpZ25pbmcga2V5IGZvciBNYXZlbiBhcnRpZmFj
-dHMpIDx0aW5rLWRldkBnb29nbGUuY29tPokCTgQTAQoAOBYhBHOXbJw5wUebhOJk
-GlpooiSRKOLGBQJj3MMAAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEFpo
-oiSRKOLGX3YP/iAVKH2H5ZKxO78FTLS8Jf1bl48Z31kTnvZg/sMFA51D9p+kBxns
-dNe/4UAt7R7hchlJ6tah9+L5bBf3eU0r4vNwE7+d6WiYoKgGVaegRHfOJEqSlnXo
-a6b3J2ML2vgnRpWTFJPdtZXKekodf76We6YshbHfuix5B0Zfztn2UC54cuhCsi83
-FhEMW9WvMe4Men9u4MsiQU+wCYUtsRV6bZpLWbrYFJyB75/IwWiLZv4AiVIqUpB6
-yw/lTDsPTyrncEfE2+DYwyHduieY+gIR6SGkJh+7VF3ESj6UR1i7+sdcvWbLgJXe
-JoqQBROxnApKh/3LIDUGuONfiryEaC5Xy/l1YkEUsgp5RA5YrotFkTEZCvud6M9m
-iBrFOz0xAHwu84OfcSJsmzARh8lItd4wImykXnhyiTInVUrq9OeDN94RSTFQ7+Mh
-RT+CBnh6Z8y3jL9ekCpGZrxB0K4T4FBxQ0QNLnPZK2OfTEvmC2haP2sofbrYbo31
-TlafpzPfLXyp5sBGevT/vUd3YbXS69L3lDRKoOnJy3PK3UUpeSxTP0sN53mnembu
-8R6eHzuisrb1vl9wsIJ0EFn5F331xQagKYzDn0Vp63KltD3xOnB+itcsZETYamuL
-MHk3TXrNg47Iu6fbLEw9M2HHYDBm70AI1PpXtT4mtQ+TU18JtPM4ZpvHuQINBGPc
-wwABEADh/vvuWr2Pl5xD/gF1vKIdy+sNTTadx7EoAsdnrYShtP3jvUPL9VDvbpyH
-K9B6wFEulUM037L7BOl9khg9oO4G/NXlU3wiIJk4dI4tBrj1IAFD7z3qQ2Sgpy/b
-TsBRZZCwOiW28IxqQsx5DE4i5YYOEjjyqZiza4/I3TchKN0sEOwb77MEUrYS1CUe
-lpl/zFlYZNGXT/oDjJI2bVs1pvCMtb2iQW7m6JvDEY0xZ7zoRm2rJA567oV3WAO6
-u2T2tpAzfu1SYJRRPbUt45pdzWSZUzCQwcB0ZTAuQbK4nIsjPGv6oAPm3PgpEpW2
-PBHPux+UHN03k/vEpb5XLLTBuWIdgtXRzD2vSkEO7A6CBkYTY4TY5UodLgV+szYl
-G+N00m0h2SOf/9FEijRIA2XMfNYZ6E8x3I0ADXmOEE1MfdBGSEtk/Tzb/NX8Bb8/
-zk1tKRI00vEz1bjOTsiRZQ6Aod+hUcCPasTUAKIgTpe30zd1v1krF4leVRXHWJbU
-mpsr7CoJRIrKBghkP7K0vLUQzes0djxl/J9C8Ru7bjM6Ndjmy5+oSCMMPJyJ/Wpd
-+fEWZxgIukAnjLtuZTUVeMESzP1CkUeNv+aGadPNGw97VRAFEfk6508ihg+TVEiy
-FORV/njYUB+4zm/+aczd6KKT24t6DIVdm1FkSds8SpcDT8Ei0wARAQABiQI2BBgB
-CgAgFiEEc5dsnDnBR5uE4mQaWmiiJJEo4sYFAmPcwwACGwwACgkQWmiiJJEo4sbA
-dRAAlzA7kLCzFnCSYr2TgCfQEoI8yslnPL0flq7ghw5yBK4OdUbYoUBYBroZMJLw
-hPvyaEdp3t63Sl/9GsYNfub+TAOJA64WuRtOT1QbOh6+U5T7X5yvPM3FAGUuYOlk
-1ABuTAtbOWW+iPOpE7sZaai0j9zH2vPyviBqZ6GtvsuVT7ynRbrYuWe9127ZkJet
-6zPzGXoyTE+FaGOdv/wd+9u1Qjk/lYowNoQ7xXWbnF4jD3o6lM56uOgvPUFoSnzb
-sd1fCXcfQ4wj+O3yEoMDVa1K9eIrSz7TrL5K4VzfOxaHxPh2orE8dFgjXy0Vm/KC
-XTOc9DcJXCjqJVh9RoDxTaNkjWfkN+1bq9NUaPauRduMwlkbk904ygXxMJ485hm5
-uSaCKM8eYBp4y/CdwOcnonBEg+lS3rVIcfDUByRrim5pOsIlSe3f2OX3txMYQvXJ
-ivYOA4phKSpntp4TDzGkZfLbCIpaFowR3px/c2LKuQmTmr+Vl8v5W4kBgQGEDdxY
-a7jhYx9HbLimtQG2XcCC+javwdubT/ItHrfcAB6B+dV0iRA5b4QDGtU0CsD9tY3N
-oaTSCeYc7Xae5YCXr3viH8vWPap984XZWLJZXM2s2Vm1XdeBTQxWCGVER9dnzGGE
-DsHNOZoy3UpsL+GQ+AORGsEAjOVJQnCjqUh7gtB8cwiPvps=
-=TnZo
------END PGP PUBLIC KEY BLOCK-----
-
-pub 5A68A2249128E2C6
-uid Tink Developers (Signing key for Maven artifacts) <tink-dev@google.com>
-
-sub 4E5C59DBFF7DACF9
------BEGIN PGP PUBLIC KEY BLOCK-----
-Version: BCPG v1.68
-
-mQINBGPcwwABEADTw/gqmHh4LTSDsBP0KMoXFtFQnv7xmVPPrPjt0NxGn3w2WIou
-7UaLUTViKkgm92h72gyM7N9JfNBLcYrqVf9ed75MPdGQgzIhkVg3SLWZGFoIQUJ4
-VznKuqJmd0dSRtApXL9ZoVXf1mLnbLkOvfLfw2hVIsMJcW9/G4It7pPY82IiwTLn
-XG/pw6+wLa5FGCM4mldPnyBDR935nSkgnZzQJyDESXZKS1uiU1rMcGWkVLJ1UYfg
-fT5c6jAk+75vhyQEvHReoa1T8fgBPD0jAlE7T80460x8dramshhAAIOZLnlAuiBN
-A7KPY7cUDxDyFNLdhj7lGjPP1UTv5mdcZc0H6tgaapOB8QzqnkAJN7GrPHjAWnu7
-ujdiT+lmng+waiBfoQN7HQyJXng8Skj1tVYjuAUNgUuA6p1hL30k9Ny9wO2BBg23
-OXYn8yLptZCUg4T31w2ko2PReSxMeEI6S2jWTALP9HH1Q1sinQnlJ8SfPAssG8wn
-qjaV4PtS8bO+Gy2NosG389dzibrmVJAHqymTLlaviWgeqAXEwZhbVcSOv+B3JgAX
-h1dI2zDJUMGV7jNbKa+UNGb+di8T3J5JEXCNM/Zvm3KNudfZFbcNS1pEzNRzm4gh
-kmNHQEtknSm6NHaWIP5eMIxsKGUA6qTR8XE9qrvpwV35rwbxmPHSowHzzwARAQAB
-tEdUaW5rIERldmVsb3BlcnMgKFNpZ25pbmcga2V5IGZvciBNYXZlbiBhcnRpZmFj
-dHMpIDx0aW5rLWRldkBnb29nbGUuY29tPokCTgQTAQoAOBYhBHOXbJw5wUebhOJk
-GlpooiSRKOLGBQJj3MMAAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEFpo
-oiSRKOLGX3YP/iAVKH2H5ZKxO78FTLS8Jf1bl48Z31kTnvZg/sMFA51D9p+kBxns
-dNe/4UAt7R7hchlJ6tah9+L5bBf3eU0r4vNwE7+d6WiYoKgGVaegRHfOJEqSlnXo
-a6b3J2ML2vgnRpWTFJPdtZXKekodf76We6YshbHfuix5B0Zfztn2UC54cuhCsi83
-FhEMW9WvMe4Men9u4MsiQU+wCYUtsRV6bZpLWbrYFJyB75/IwWiLZv4AiVIqUpB6
-yw/lTDsPTyrncEfE2+DYwyHduieY+gIR6SGkJh+7VF3ESj6UR1i7+sdcvWbLgJXe
-JoqQBROxnApKh/3LIDUGuONfiryEaC5Xy/l1YkEUsgp5RA5YrotFkTEZCvud6M9m
-iBrFOz0xAHwu84OfcSJsmzARh8lItd4wImykXnhyiTInVUrq9OeDN94RSTFQ7+Mh
-RT+CBnh6Z8y3jL9ekCpGZrxB0K4T4FBxQ0QNLnPZK2OfTEvmC2haP2sofbrYbo31
-TlafpzPfLXyp5sBGevT/vUd3YbXS69L3lDRKoOnJy3PK3UUpeSxTP0sN53mnembu
-8R6eHzuisrb1vl9wsIJ0EFn5F331xQagKYzDn0Vp63KltD3xOnB+itcsZETYamuL
-MHk3TXrNg47Iu6fbLEw9M2HHYDBm70AI1PpXtT4mtQ+TU18JtPM4ZpvHuQINBGPc
-wwABEADh/vvuWr2Pl5xD/gF1vKIdy+sNTTadx7EoAsdnrYShtP3jvUPL9VDvbpyH
-K9B6wFEulUM037L7BOl9khg9oO4G/NXlU3wiIJk4dI4tBrj1IAFD7z3qQ2Sgpy/b
-TsBRZZCwOiW28IxqQsx5DE4i5YYOEjjyqZiza4/I3TchKN0sEOwb77MEUrYS1CUe
-lpl/zFlYZNGXT/oDjJI2bVs1pvCMtb2iQW7m6JvDEY0xZ7zoRm2rJA567oV3WAO6
-u2T2tpAzfu1SYJRRPbUt45pdzWSZUzCQwcB0ZTAuQbK4nIsjPGv6oAPm3PgpEpW2
-PBHPux+UHN03k/vEpb5XLLTBuWIdgtXRzD2vSkEO7A6CBkYTY4TY5UodLgV+szYl
-G+N00m0h2SOf/9FEijRIA2XMfNYZ6E8x3I0ADXmOEE1MfdBGSEtk/Tzb/NX8Bb8/
-zk1tKRI00vEz1bjOTsiRZQ6Aod+hUcCPasTUAKIgTpe30zd1v1krF4leVRXHWJbU
-mpsr7CoJRIrKBghkP7K0vLUQzes0djxl/J9C8Ru7bjM6Ndjmy5+oSCMMPJyJ/Wpd
-+fEWZxgIukAnjLtuZTUVeMESzP1CkUeNv+aGadPNGw97VRAFEfk6508ihg+TVEiy
-FORV/njYUB+4zm/+aczd6KKT24t6DIVdm1FkSds8SpcDT8Ei0wARAQABiQI2BBgB
-CgAgFiEEc5dsnDnBR5uE4mQaWmiiJJEo4sYFAmPcwwACGwwACgkQWmiiJJEo4sbA
-dRAAlzA7kLCzFnCSYr2TgCfQEoI8yslnPL0flq7ghw5yBK4OdUbYoUBYBroZMJLw
-hPvyaEdp3t63Sl/9GsYNfub+TAOJA64WuRtOT1QbOh6+U5T7X5yvPM3FAGUuYOlk
-1ABuTAtbOWW+iPOpE7sZaai0j9zH2vPyviBqZ6GtvsuVT7ynRbrYuWe9127ZkJet
-6zPzGXoyTE+FaGOdv/wd+9u1Qjk/lYowNoQ7xXWbnF4jD3o6lM56uOgvPUFoSnzb
-sd1fCXcfQ4wj+O3yEoMDVa1K9eIrSz7TrL5K4VzfOxaHxPh2orE8dFgjXy0Vm/KC
-XTOc9DcJXCjqJVh9RoDxTaNkjWfkN+1bq9NUaPauRduMwlkbk904ygXxMJ485hm5
-uSaCKM8eYBp4y/CdwOcnonBEg+lS3rVIcfDUByRrim5pOsIlSe3f2OX3txMYQvXJ
-ivYOA4phKSpntp4TDzGkZfLbCIpaFowR3px/c2LKuQmTmr+Vl8v5W4kBgQGEDdxY
-a7jhYx9HbLimtQG2XcCC+javwdubT/ItHrfcAB6B+dV0iRA5b4QDGtU0CsD9tY3N
-oaTSCeYc7Xae5YCXr3viH8vWPap984XZWLJZXM2s2Vm1XdeBTQxWCGVER9dnzGGE
-DsHNOZoy3UpsL+GQ+AORGsEAjOVJQnCjqUh7gtB8cwiPvps=
-=TnZo
------END PGP PUBLIC KEY BLOCK-----
-
-pub 5A68A2249128E2C6
-uid Tink Developers (Signing key for Maven artifacts) <tink-dev@google.com>
-
-sub 4E5C59DBFF7DACF9
------BEGIN PGP PUBLIC KEY BLOCK-----
-Version: BCPG v1.68
-
-mQINBGPcwwABEADTw/gqmHh4LTSDsBP0KMoXFtFQnv7xmVPPrPjt0NxGn3w2WIou
-7UaLUTViKkgm92h72gyM7N9JfNBLcYrqVf9ed75MPdGQgzIhkVg3SLWZGFoIQUJ4
-VznKuqJmd0dSRtApXL9ZoVXf1mLnbLkOvfLfw2hVIsMJcW9/G4It7pPY82IiwTLn
-XG/pw6+wLa5FGCM4mldPnyBDR935nSkgnZzQJyDESXZKS1uiU1rMcGWkVLJ1UYfg
-fT5c6jAk+75vhyQEvHReoa1T8fgBPD0jAlE7T80460x8dramshhAAIOZLnlAuiBN
-A7KPY7cUDxDyFNLdhj7lGjPP1UTv5mdcZc0H6tgaapOB8QzqnkAJN7GrPHjAWnu7
-ujdiT+lmng+waiBfoQN7HQyJXng8Skj1tVYjuAUNgUuA6p1hL30k9Ny9wO2BBg23
-OXYn8yLptZCUg4T31w2ko2PReSxMeEI6S2jWTALP9HH1Q1sinQnlJ8SfPAssG8wn
-qjaV4PtS8bO+Gy2NosG389dzibrmVJAHqymTLlaviWgeqAXEwZhbVcSOv+B3JgAX
-h1dI2zDJUMGV7jNbKa+UNGb+di8T3J5JEXCNM/Zvm3KNudfZFbcNS1pEzNRzm4gh
-kmNHQEtknSm6NHaWIP5eMIxsKGUA6qTR8XE9qrvpwV35rwbxmPHSowHzzwARAQAB
-tEdUaW5rIERldmVsb3BlcnMgKFNpZ25pbmcga2V5IGZvciBNYXZlbiBhcnRpZmFj
-dHMpIDx0aW5rLWRldkBnb29nbGUuY29tPokCTgQTAQoAOBYhBHOXbJw5wUebhOJk
-GlpooiSRKOLGBQJj3MMAAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEFpo
-oiSRKOLGX3YP/iAVKH2H5ZKxO78FTLS8Jf1bl48Z31kTnvZg/sMFA51D9p+kBxns
-dNe/4UAt7R7hchlJ6tah9+L5bBf3eU0r4vNwE7+d6WiYoKgGVaegRHfOJEqSlnXo
-a6b3J2ML2vgnRpWTFJPdtZXKekodf76We6YshbHfuix5B0Zfztn2UC54cuhCsi83
-FhEMW9WvMe4Men9u4MsiQU+wCYUtsRV6bZpLWbrYFJyB75/IwWiLZv4AiVIqUpB6
-yw/lTDsPTyrncEfE2+DYwyHduieY+gIR6SGkJh+7VF3ESj6UR1i7+sdcvWbLgJXe
-JoqQBROxnApKh/3LIDUGuONfiryEaC5Xy/l1YkEUsgp5RA5YrotFkTEZCvud6M9m
-iBrFOz0xAHwu84OfcSJsmzARh8lItd4wImykXnhyiTInVUrq9OeDN94RSTFQ7+Mh
-RT+CBnh6Z8y3jL9ekCpGZrxB0K4T4FBxQ0QNLnPZK2OfTEvmC2haP2sofbrYbo31
-TlafpzPfLXyp5sBGevT/vUd3YbXS69L3lDRKoOnJy3PK3UUpeSxTP0sN53mnembu
-8R6eHzuisrb1vl9wsIJ0EFn5F331xQagKYzDn0Vp63KltD3xOnB+itcsZETYamuL
-MHk3TXrNg47Iu6fbLEw9M2HHYDBm70AI1PpXtT4mtQ+TU18JtPM4ZpvHuQINBGPc
-wwABEADh/vvuWr2Pl5xD/gF1vKIdy+sNTTadx7EoAsdnrYShtP3jvUPL9VDvbpyH
-K9B6wFEulUM037L7BOl9khg9oO4G/NXlU3wiIJk4dI4tBrj1IAFD7z3qQ2Sgpy/b
-TsBRZZCwOiW28IxqQsx5DE4i5YYOEjjyqZiza4/I3TchKN0sEOwb77MEUrYS1CUe
-lpl/zFlYZNGXT/oDjJI2bVs1pvCMtb2iQW7m6JvDEY0xZ7zoRm2rJA567oV3WAO6
-u2T2tpAzfu1SYJRRPbUt45pdzWSZUzCQwcB0ZTAuQbK4nIsjPGv6oAPm3PgpEpW2
-PBHPux+UHN03k/vEpb5XLLTBuWIdgtXRzD2vSkEO7A6CBkYTY4TY5UodLgV+szYl
-G+N00m0h2SOf/9FEijRIA2XMfNYZ6E8x3I0ADXmOEE1MfdBGSEtk/Tzb/NX8Bb8/
-zk1tKRI00vEz1bjOTsiRZQ6Aod+hUcCPasTUAKIgTpe30zd1v1krF4leVRXHWJbU
-mpsr7CoJRIrKBghkP7K0vLUQzes0djxl/J9C8Ru7bjM6Ndjmy5+oSCMMPJyJ/Wpd
-+fEWZxgIukAnjLtuZTUVeMESzP1CkUeNv+aGadPNGw97VRAFEfk6508ihg+TVEiy
-FORV/njYUB+4zm/+aczd6KKT24t6DIVdm1FkSds8SpcDT8Ei0wARAQABiQI2BBgB
-CgAgFiEEc5dsnDnBR5uE4mQaWmiiJJEo4sYFAmPcwwACGwwACgkQWmiiJJEo4sbA
-dRAAlzA7kLCzFnCSYr2TgCfQEoI8yslnPL0flq7ghw5yBK4OdUbYoUBYBroZMJLw
-hPvyaEdp3t63Sl/9GsYNfub+TAOJA64WuRtOT1QbOh6+U5T7X5yvPM3FAGUuYOlk
-1ABuTAtbOWW+iPOpE7sZaai0j9zH2vPyviBqZ6GtvsuVT7ynRbrYuWe9127ZkJet
-6zPzGXoyTE+FaGOdv/wd+9u1Qjk/lYowNoQ7xXWbnF4jD3o6lM56uOgvPUFoSnzb
-sd1fCXcfQ4wj+O3yEoMDVa1K9eIrSz7TrL5K4VzfOxaHxPh2orE8dFgjXy0Vm/KC
-XTOc9DcJXCjqJVh9RoDxTaNkjWfkN+1bq9NUaPauRduMwlkbk904ygXxMJ485hm5
-uSaCKM8eYBp4y/CdwOcnonBEg+lS3rVIcfDUByRrim5pOsIlSe3f2OX3txMYQvXJ
-ivYOA4phKSpntp4TDzGkZfLbCIpaFowR3px/c2LKuQmTmr+Vl8v5W4kBgQGEDdxY
-a7jhYx9HbLimtQG2XcCC+javwdubT/ItHrfcAB6B+dV0iRA5b4QDGtU0CsD9tY3N
-oaTSCeYc7Xae5YCXr3viH8vWPap984XZWLJZXM2s2Vm1XdeBTQxWCGVER9dnzGGE
-DsHNOZoy3UpsL+GQ+AORGsEAjOVJQnCjqUh7gtB8cwiPvps=
-=TnZo
------END PGP PUBLIC KEY BLOCK-----
-
-pub 5A68A2249128E2C6
-uid Tink Developers (Signing key for Maven artifacts) <tink-dev@google.com>
-
-sub 4E5C59DBFF7DACF9
------BEGIN PGP PUBLIC KEY BLOCK-----
-Version: BCPG v1.68
-
-mQINBGPcwwABEADTw/gqmHh4LTSDsBP0KMoXFtFQnv7xmVPPrPjt0NxGn3w2WIou
-7UaLUTViKkgm92h72gyM7N9JfNBLcYrqVf9ed75MPdGQgzIhkVg3SLWZGFoIQUJ4
-VznKuqJmd0dSRtApXL9ZoVXf1mLnbLkOvfLfw2hVIsMJcW9/G4It7pPY82IiwTLn
-XG/pw6+wLa5FGCM4mldPnyBDR935nSkgnZzQJyDESXZKS1uiU1rMcGWkVLJ1UYfg
-fT5c6jAk+75vhyQEvHReoa1T8fgBPD0jAlE7T80460x8dramshhAAIOZLnlAuiBN
-A7KPY7cUDxDyFNLdhj7lGjPP1UTv5mdcZc0H6tgaapOB8QzqnkAJN7GrPHjAWnu7
-ujdiT+lmng+waiBfoQN7HQyJXng8Skj1tVYjuAUNgUuA6p1hL30k9Ny9wO2BBg23
-OXYn8yLptZCUg4T31w2ko2PReSxMeEI6S2jWTALP9HH1Q1sinQnlJ8SfPAssG8wn
-qjaV4PtS8bO+Gy2NosG389dzibrmVJAHqymTLlaviWgeqAXEwZhbVcSOv+B3JgAX
-h1dI2zDJUMGV7jNbKa+UNGb+di8T3J5JEXCNM/Zvm3KNudfZFbcNS1pEzNRzm4gh
-kmNHQEtknSm6NHaWIP5eMIxsKGUA6qTR8XE9qrvpwV35rwbxmPHSowHzzwARAQAB
-tEdUaW5rIERldmVsb3BlcnMgKFNpZ25pbmcga2V5IGZvciBNYXZlbiBhcnRpZmFj
-dHMpIDx0aW5rLWRldkBnb29nbGUuY29tPokCTgQTAQoAOBYhBHOXbJw5wUebhOJk
-GlpooiSRKOLGBQJj3MMAAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEFpo
-oiSRKOLGX3YP/iAVKH2H5ZKxO78FTLS8Jf1bl48Z31kTnvZg/sMFA51D9p+kBxns
-dNe/4UAt7R7hchlJ6tah9+L5bBf3eU0r4vNwE7+d6WiYoKgGVaegRHfOJEqSlnXo
-a6b3J2ML2vgnRpWTFJPdtZXKekodf76We6YshbHfuix5B0Zfztn2UC54cuhCsi83
-FhEMW9WvMe4Men9u4MsiQU+wCYUtsRV6bZpLWbrYFJyB75/IwWiLZv4AiVIqUpB6
-yw/lTDsPTyrncEfE2+DYwyHduieY+gIR6SGkJh+7VF3ESj6UR1i7+sdcvWbLgJXe
-JoqQBROxnApKh/3LIDUGuONfiryEaC5Xy/l1YkEUsgp5RA5YrotFkTEZCvud6M9m
-iBrFOz0xAHwu84OfcSJsmzARh8lItd4wImykXnhyiTInVUrq9OeDN94RSTFQ7+Mh
-RT+CBnh6Z8y3jL9ekCpGZrxB0K4T4FBxQ0QNLnPZK2OfTEvmC2haP2sofbrYbo31
-TlafpzPfLXyp5sBGevT/vUd3YbXS69L3lDRKoOnJy3PK3UUpeSxTP0sN53mnembu
-8R6eHzuisrb1vl9wsIJ0EFn5F331xQagKYzDn0Vp63KltD3xOnB+itcsZETYamuL
-MHk3TXrNg47Iu6fbLEw9M2HHYDBm70AI1PpXtT4mtQ+TU18JtPM4ZpvHuQINBGPc
-wwABEADh/vvuWr2Pl5xD/gF1vKIdy+sNTTadx7EoAsdnrYShtP3jvUPL9VDvbpyH
-K9B6wFEulUM037L7BOl9khg9oO4G/NXlU3wiIJk4dI4tBrj1IAFD7z3qQ2Sgpy/b
-TsBRZZCwOiW28IxqQsx5DE4i5YYOEjjyqZiza4/I3TchKN0sEOwb77MEUrYS1CUe
-lpl/zFlYZNGXT/oDjJI2bVs1pvCMtb2iQW7m6JvDEY0xZ7zoRm2rJA567oV3WAO6
-u2T2tpAzfu1SYJRRPbUt45pdzWSZUzCQwcB0ZTAuQbK4nIsjPGv6oAPm3PgpEpW2
-PBHPux+UHN03k/vEpb5XLLTBuWIdgtXRzD2vSkEO7A6CBkYTY4TY5UodLgV+szYl
-G+N00m0h2SOf/9FEijRIA2XMfNYZ6E8x3I0ADXmOEE1MfdBGSEtk/Tzb/NX8Bb8/
-zk1tKRI00vEz1bjOTsiRZQ6Aod+hUcCPasTUAKIgTpe30zd1v1krF4leVRXHWJbU
-mpsr7CoJRIrKBghkP7K0vLUQzes0djxl/J9C8Ru7bjM6Ndjmy5+oSCMMPJyJ/Wpd
-+fEWZxgIukAnjLtuZTUVeMESzP1CkUeNv+aGadPNGw97VRAFEfk6508ihg+TVEiy
-FORV/njYUB+4zm/+aczd6KKT24t6DIVdm1FkSds8SpcDT8Ei0wARAQABiQI2BBgB
-CgAgFiEEc5dsnDnBR5uE4mQaWmiiJJEo4sYFAmPcwwACGwwACgkQWmiiJJEo4sbA
-dRAAlzA7kLCzFnCSYr2TgCfQEoI8yslnPL0flq7ghw5yBK4OdUbYoUBYBroZMJLw
-hPvyaEdp3t63Sl/9GsYNfub+TAOJA64WuRtOT1QbOh6+U5T7X5yvPM3FAGUuYOlk
-1ABuTAtbOWW+iPOpE7sZaai0j9zH2vPyviBqZ6GtvsuVT7ynRbrYuWe9127ZkJet
-6zPzGXoyTE+FaGOdv/wd+9u1Qjk/lYowNoQ7xXWbnF4jD3o6lM56uOgvPUFoSnzb
-sd1fCXcfQ4wj+O3yEoMDVa1K9eIrSz7TrL5K4VzfOxaHxPh2orE8dFgjXy0Vm/KC
-XTOc9DcJXCjqJVh9RoDxTaNkjWfkN+1bq9NUaPauRduMwlkbk904ygXxMJ485hm5
-uSaCKM8eYBp4y/CdwOcnonBEg+lS3rVIcfDUByRrim5pOsIlSe3f2OX3txMYQvXJ
-ivYOA4phKSpntp4TDzGkZfLbCIpaFowR3px/c2LKuQmTmr+Vl8v5W4kBgQGEDdxY
-a7jhYx9HbLimtQG2XcCC+javwdubT/ItHrfcAB6B+dV0iRA5b4QDGtU0CsD9tY3N
-oaTSCeYc7Xae5YCXr3viH8vWPap984XZWLJZXM2s2Vm1XdeBTQxWCGVER9dnzGGE
-DsHNOZoy3UpsL+GQ+AORGsEAjOVJQnCjqUh7gtB8cwiPvps=
-=TnZo
+mQENBFfAYzkBCADRFsmQXLC6UbFNjCKrwy+AwiMNUchJdsPkbFrvueWKq0nPB6Rh
+D2YGNdCdLlkeybHHaSjYi/Xdxv7Vgfp4d32tzoqQJe8Q8oYYW7KbTkfzwH7TNLcw
+lDqgqONCzOzqYUBy3E3wPlBE8MCI2NyGmVKR4/kjii12Ok8nUmAel7IpUwQoV4cx
+CiK7N9pInC4q1hOmeK6EddUEJnPRhFtMD/aiH2S2H1m5a+raBLtP+47h6XCphas/
+iyALtqtIyMOQgO/qrtyxLC1f4If176Ylhd8d/Yk90OYN4N1mWCXBRBY9yQyOMyys
+ISyEA2GjxmLxgMLoMCfUOczcoLEqgkSXGvGvABEBAAG0RkdhcnkgTydOZWFsbCAo
+R1BHIEtleSBjcmVhdGVkIG9uIEF1ZyAyNiAyMDE2KSA8Z2FyeUBzb3VyY2VhdWRp
+dG9yLmNvbT6JATkEEwEIACMFAlfAYzkCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIe
+AQIXgAAKCRBpuOMuIxOGYkwrCAC6JjooHvdxUuAEGtJIj2PRqHv0CDzoJOp3ZMxC
+X9mxqepCQYU+UyQS9gcjOwk9MKNE1loJ334Sv2xXfbewRHbuEZhyy9Qay22JAdOl
+QNoW67eKC6gO5iC8dcH2njn5tW2KGtlRItu7MjIEO72YzKgPFU1KvDQP0DxdRj5H
+IU61Vk+tiZAzZjZ0PCI9S19F3fpt3eJ0wgM1nCKiZfInkBwXzFP8SIMbr8K/qu08
+X+xFzNrz7tOMkxPhQmlxcUx3Cp72B6+Kzqyq5c/rR0oCo70uXB6tmAE3TAClnIjo
+tgOL9uTPYNozwilQCEzGpO7i+W4UI+irlJ4DkIrzq67q5X0puQENBFfAYzkBCADQ
+wzS0Qw4IfrBpO2O8oVLmuGn7vcrJwecMK353HJgLq5nPLOyeq91ry2Id14zklv/F
+/8xeUod8Nb9uZBVQTKLynfoCcPwDvJLkKoEpMasT1B1npoz1npQQraNWBaaqa6Ci
+98J12lE+leV9zdu+cRN6SZwETtSmO9NmL+4zZuRpfpni6grEhia9z3lQYslCxovl
+j1VE10S93BqNovY6fchP4RXplNBQdBwRHdR96k1+vKjuLYyDloRW8VsTSvBIdprM
+2xijCbujsq4QVi8rvvEEMFKRt6kipbMCDkK5WqMTCdPQCMjBrFv1fb4s7W0/lf9T
+OZ/LKx7ZZE5EMncW/2eBABEBAAGJAR8EGAEIAAkFAlfAYzkCGwwACgkQabjjLiMT
+hmJEjAgAiom48h2A8uSRGf6rR9AMKnMXQumwk4W3eoXMhygLvozxqJ5YMI6euNs8
+gF5ehK4OwPOIyDEkZbkp0MgldD3zdlhjAN/rxmMBSItUQfgPwwgC5f89vpZJNwUW
+l018OicikDUo60ecswWzwXCUfIzV3OqKc9IB+NQZYrjMnOu4zLewPTawpUfrW5Fw
+9EBn20ktBUXOo+d0qyqi4hzjKs2tjQbGyTphU8adrNtG0hpjOXsLG7cHWY968Ew+
+pc051SPs7QqRgrL5bLw1FsUP7kvoGGSzf6J2UtU9O0qY4erXSl9219qGmGSzb8jd
+b0ZlGu3RAziliAj6KR2YKGp0fCBndA==
+=lNGi
-----END PGP PUBLIC KEY BLOCK-----
pub 5E1F79A7C298661E
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 9a07f43..c95558d 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -31,10 +31,6 @@
<trust group="^androidx($|([.].*))" regex="true" reason="not signed yet"/>
<trust group="^com[.]android($|([.].*))" regex="true" reason="b/215430394"/>
</trusted-artifacts>
- <ignored-keys>
- <ignored-key id="3d12ca2ac19f3181" reason="Key couldn't be downloaded from any key server"/>
- <ignored-key id="5a68a2249128e2c6" reason="Key couldn't be downloaded from any key server"/>
- </ignored-keys>
<trusted-keys>
<trusted-key id="00089ee8c3afa95a854d0f1df800dd0933ecf7f7" group="com.google.guava"/>
<trusted-key id="019082bc00e0324e2aef4cf00d3b328562a119a7" group="org.openjdk.jmh"/>
@@ -99,7 +95,17 @@
<trusted-key id="24d04176586361fda94ee0315f7786df73e61f56" group="com.google.devtools.ksp"/>
<trusted-key id="26063b04869f7d235ccc057447586a1b75ef0de5" group="com.squareup.wire"/>
<trusted-key id="263923711ef4fe3f3f0c28af11509ed50ec155e6" group="org.reactivestreams"/>
- <trusted-key id="28118c070cb22a0175a2e8d43d12ca2ac19f3181" group="com.fasterxml.jackson.core" name="jackson-databind" version="2.12.7.1"/>
+ <trusted-key id="28118c070cb22a0175a2e8d43d12ca2ac19f3181">
+ <trusting group="com.fasterxml"/>
+ <trusting group="com.fasterxml.jackson"/>
+ <trusting group="com.fasterxml.jackson.core"/>
+ <trusting group="com.fasterxml.jackson.dataformat"/>
+ <trusting group="com.fasterxml.woodstox"/>
+ </trusted-key>
+ <trusted-key id="29bea2a645f2d6ced7fb12e02b172e3e156466e8">
+ <trusting group="org.apache.maven"/>
+ <trusting group="org.apache.maven.resolver"/>
+ </trusted-key>
<trusted-key id="2a4f55d9cda5877731fbe7466eff5ef5523052d4" group="com.github.tschuchortdev"/>
<trusted-key id="2bab4466b44f54f8f99bbbdd5ed22f661bbf0acc" group="com.almworks.sqlite4java"/>
<trusted-key id="2bcbdd0f23ea1cafcc11d4860374cf2e8dd1bdfd">
@@ -125,7 +131,10 @@
<trusting group="com.google.auto.service"/>
</trusted-key>
<trusted-key id="32b92f2ff75fdf37dc811c3c2f566d4221d3ec52" group="com.ryanharter.auto.value"/>
- <trusted-key id="33fd4bfd33554634053d73c0c2148900bcd3c2af" group="org.jetbrains.trove4j" name="trove4j"/>
+ <trusted-key id="33fd4bfd33554634053d73c0c2148900bcd3c2af">
+ <trusting group="org.jetbrains" name="annotations"/>
+ <trusting group="org.jetbrains.trove4j" name="trove4j"/>
+ </trusted-key>
<trusted-key id="34441e504a937f43eb0daef96a65176a0fb1cd0b" group="org.codehaus.groovy"/>
<trusted-key id="3872ed7d5904493d23d78fa2c4c8cb73b1435348" group="com.android.tools.build"/>
<trusted-key id="3d11126ea77e4e07fbabb38614a84c976d265b25" group="com.google.protobuf"/>
@@ -172,6 +181,7 @@
<trusted-key id="4f8fec6785f611d9a712ea2734918b7d3969d2f5" group="com.google.dagger"/>
<trusted-key id="517b94f8d0a46317a28d8ab30da8a5ec02d11ead" group="net.sf.jopt-simple"/>
<trusted-key id="51b52dc5dd452f92be342cc2858fc4c4f43856a3" group="xerces"/>
+ <trusted-key id="53c935821aa6a755bd337db53595395eb3d8e1ba" group="org.apache.logging.log4j"/>
<trusted-key id="54f6e594923ebd04f2b88606125a9ec9faa91ae1" group="io.antmedia" name="rtmp-client"/>
<trusted-key id="55e770230e69cc6de143fb5b62c82e50836eb3ee" group="com.github.gundy"/>
<trusted-key id="56b505dc8a29c69138a430b9429c8816dea04cdb" group="org.xerial"/>
@@ -203,11 +213,13 @@
<trusting group="^com[.]google($|([.].*))" regex="true"/>
</trusted-key>
<trusted-key id="696b6199a2a9d8c29ce78cc0d041cad2e452550f" group="com.google.protobuf"/>
+ <trusted-key id="6a814b1f869c2bbeab7cb7271a2a1c94bde89688" group="org.codehaus.plexus"/>
<trusted-key id="6bdaca2c0493cca133b372d09c4f7e9d98b1cc53" group="org.apache"/>
<trusted-key id="6dd3b8c64ef75253beb2c53ad908a43fb7ec07ac">
<trusting group="com.sun.activation"/>
<trusting group="jakarta.activation"/>
</trusted-key>
+ <trusted-key id="6ead752b3e2b38e8e2236d7ba9321edaa5cb3202" group="ch.randelshofer" name="fastdoubleparser" version="0.8.0"/>
<trusted-key id="6f538074ccebf35f28af9b066a0975f8b1127b83">
<trusting group="org.jetbrains.kotlin"/>
<trusting group="org.jetbrains.kotlin.jvm"/>
@@ -245,13 +257,20 @@
<trusted-key id="7e22d50a7ebd9d2cd269b2d4056aca74d46000bf" group="io.netty"/>
<trusted-key id="7f36e793ae3252e5d9e9b98fee9e7dc9d92fc896" group="com.google.errorprone"/>
<trusted-key id="7faa0f2206de228f0db01ad741321490758aad6f" group="org.codehaus.groovy"/>
+ <trusted-key id="7fe5e98df3a5c0dc34663ab7c1add37ca0069309" group="org.spdx" name="spdx-gradle-plugin" version="0.1.0"/>
<trusted-key id="808d78b17a5a2d7c3668e31fbffc9b54721244ad" group="org.apache.commons"/>
<trusted-key id="80f6d6b0d90c6747753344cab5a9e81b565e89e0" group="org.tomlj"/>
<trusted-key id="8254180bfc943b816e0b5e2e5e2f2b3d474efe6b" group="it.unimi.dsi"/>
+ <trusted-key id="82c9ec0e52c47a936a849e0113d979595e6d01e1" group="org.apache.maven.shared" name="maven-shared-utils" version="3.3.4"/>
<trusted-key id="82f833963889d7ed06f1e4dc6525fd70cc303655" group="org.codehaus.mojo"/>
<trusted-key id="835a685c8c6f49c54980e5caf406f31bc1468eba" group="org.jcodec"/>
<trusted-key id="842afb86375d805422835bfd82b5574242c20d6f" group="org.antlr"/>
+ <trusted-key id="84789d24df77a32433ce1f079eb80e92eb2135b1">
+ <trusting group="org.apache"/>
+ <trusting group="org.apache.maven" name="maven-parent"/>
+ </trusted-key>
<trusted-key id="8569c95cadc508b09fe90f3002216ed811210daa" group="io.github.detekt.sarif4k"/>
+ <trusted-key id="86616cd3c4f0803e73374a434dbf5995d492505d" group="org.json" name="json" version="20230227"/>
<trusted-key id="8756c4f765c9ac3cb6b85d62379ce192d401ab61">
<trusting group="com.github.ajalt"/>
<trusting group="com.github.javaparser"/>
@@ -294,7 +313,6 @@
<trusted-key id="9ffed7a118d45a44e4a1e47130e6f80434a72a7f">
<trusting group="org.apache.maven"/>
<trusting group="org.apache.maven.wagon"/>
- <trusting group="^org[.]apache[.]maven($|([.].*))" regex="true"/>
</trusted-key>
<trusted-key id="a0e7010544c02bd4c072b1803e3d777c909a447c" group="io.opencensus"/>
<trusted-key id="a33a0b49a4c1ab590b0a4ddc1364c5e2df3e99c5" group="org.reactivestreams"/>
@@ -318,6 +336,7 @@
<trusted-key id="ae9e53fc28ff2ab1012273d0bf1518e0160788a2" group="org.apache" name="apache"/>
<trusted-key id="afa2b1823fc021bfd08c211fd5f4c07a434ab3da" group="com.squareup"/>
<trusted-key id="afcc4c7594d09e2182c60e0f7a01b0f236e5430f" group="com.google.code.gson"/>
+ <trusted-key id="b02137d875d833d9b23392ecae5a7fb608a0221c" group="org.codehaus.plexus" name="plexus-classworlds" version="2.6.0"/>
<trusted-key id="b02335aa54ccf21e52bbf9abd9c565aa72ba2fdd">
<trusting group="com.google.protobuf"/>
<trusting group="io.grpc"/>
@@ -364,12 +383,14 @@
<trusting group="org.apache.ant"/>
<trusting group="org.apache.commons"/>
</trusted-key>
+ <trusted-key id="cf17e92c9ffa55316b5db83901d734ee5ee9c3f8" group="org.eclipse.sisu"/>
<trusted-key id="d196a5e3e70732eeb2e5007f1861c322c56014b2" group="commons-lang"/>
<trusted-key id="d433f9c895710db8ab087fa6b7c3b43d18eaa8b7" group="org.codehaus.mojo"/>
<trusted-key id="d477d51812e692011db11e66a6ea2e2bf22e0543" group="io.github.java-diff-utils"/>
<trusted-key id="d4c89ea4aaf455fd88b22087efe8086f9e93774e" group="junit"/>
<trusted-key id="d4fb0b7b5e8c18c993a8a386eb9d04a9a679fe18" group="com.uber.nullaway"/>
<trusted-key id="d54a395b5cf3f86eb45f6e426b1b008864323b92" group="org.antlr"/>
+ <trusted-key id="d5f46bc0b86af5dc56df58f05e975cb00c643dbf" group="com.google.inject"/>
<trusted-key id="d6f1bc78607808ec8e9f69437a8860944fad5f62">
<trusting group="org.apache.commons"/>
<trusting group="org.apache.commons" name="commons-parent"/>
@@ -406,6 +427,7 @@
<trusted-key id="eaa526b91dd83ba3e1b9636fa730529ca355a63e" group="org.ccil.cowan.tagsoup"/>
<trusted-key id="ec86f41279f2ec8ffd2f54906ccc36cc6c69fc17" group="com.google"/>
<trusted-key id="ee0ca873074092f806f59b65d364abaa39a47320" group="com.google.errorprone"/>
+ <trusted-key id="f06e94a01b835825e6ab4da369b8e32e23138662" group="org.spdx"/>
<trusted-key id="f1a51e051f527e0c8e24d54d4b1e11d5a4b91e89" group="com.google.protobuf"/>
<trusted-key id="f254b35617dc255d9344bcfa873a8e86b4372146">
<trusting group="org.apache"/>
@@ -413,10 +435,12 @@
<trusting group="org.codehaus.plexus"/>
</trusted-key>
<trusted-key id="f3184bcd55f4d016e30d4c9bf42e87f9665015c9" group="org.jsoup"/>
+ <trusted-key id="f3d15b8ff9902805de4be6b18dc6f3d0abdbd017" group="org.codehaus.plexus" name="plexus-sec-dispatcher" version="2.0"/>
<trusted-key id="f42b96b8648b5c4a1c43a62fbb2914c1fa0811c3" group="net.bytebuddy"/>
<trusted-key id="fa1703b1d287caea3a60f931e0130a3ed5a2079e" group="org.webjars"/>
<trusted-key id="fa77dcfef2ee6eb2debedd2c012579464d01c06a">
<trusting group="org.apache"/>
+ <trusting group="org.apache.maven"/>
<trusting group="org.codehaus.plexus"/>
</trusted-key>
<trusted-key id="fa7929f83ad44c4590f6cc6815c71c0a4e0b8edd" group="net.java.dev.jna"/>
@@ -449,6 +473,14 @@
<sha256 value="a4fefa2fd40d16fcdf1b0095cfaf3c1b2857a79290972b436c797fbb20df9b63" origin="Hand-built using sha256sum kotlin-native-prebuilt-macos-x86_64-1.8.21.tar.gz"/>
</artifact>
</component>
+ <component group="aopalliance" name="aopalliance" version="1.0">
+ <artifact name="aopalliance-1.0.jar">
+ <sha256 value="0addec670fedcd3f113c5c8091d783280d23f75e3acb841b61a9cdb079376a08" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ </artifact>
+ <artifact name="aopalliance-1.0.pom">
+ <sha256 value="26e82330157d6b844b67a8064945e206581e772977183e3e31fec6058aa9a59b" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ </artifact>
+ </component>
<component group="com.fasterxml.jackson.core" name="jackson-databind" version="2.12.7.1">
<artifact name="jackson-databind-2.12.7.1.jar">
<sha256 value="3f504cac405ce066d5665ff69541484d5322f35ac7a7ec6104cf86a01008e02d" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
@@ -735,6 +767,16 @@
<pgp value="808d78b17a5a2d7c3668e31fbffc9b54721244ad"/>
</artifact>
</component>
+ <component group="org.apache.commons" name="commons-parent" version="41">
+ <artifact name="commons-parent-41.pom">
+ <pgp value="f2cef92da169104244917a6b32ac66c4fbf15ecb"/>
+ </artifact>
+ </component>
+ <component group="org.apache.maven.shared" name="maven-shared-components" version="34">
+ <artifact name="maven-shared-components-34.pom">
+ <pgp value="fa77dcfef2ee6eb2debedd2c012579464d01c06a"/>
+ </artifact>
+ </component>
<component group="org.ccil.cowan.tagsoup" name="tagsoup" version="1.2">
<artifact name="tagsoup-1.2.jar">
<sha256 value="10d12b82c9a58a7842765a1152a56fbbd11eac9122a621f5a86a087503297266" origin="Generated by Gradle"/>
@@ -761,68 +803,68 @@
<pgp value="720746177725a89207a7075bfd5dea07fcb690a8"/>
</artifact>
</component>
- <component group="org.jetbrains.dokka" name="all-modules-page-plugin" version="1.8.10-dev-203">
- <artifact name="all-modules-page-plugin-1.8.10-dev-203.jar">
- <sha256 value="d750c52b0f2ad66ff5bdee04ecc6ba50b9eb7e02720abec455aff33635112524" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <component group="org.jetbrains.dokka" name="all-modules-page-plugin" version="1.8.20-dev-214">
+ <artifact name="all-modules-page-plugin-1.8.20-dev-214.jar">
+ <sha256 value="62ff36ab5e9507084e82a9fb2c31d10c4bded261772d23b3a2f8441904355705" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
- <artifact name="all-modules-page-plugin-1.8.10-dev-203.module">
- <sha256 value="317e08d873f54310e1fcbfe5a4509367c2d3c26a65cf6f01937b700ed5db8b4e" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <artifact name="all-modules-page-plugin-1.8.20-dev-214.module">
+ <sha256 value="51a43de6f287e7292d8bbb26b5930fd03f5e5d25fd2a3e8f6f86c7a1c8762824" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
- <component group="org.jetbrains.dokka" name="android-documentation-plugin" version="1.8.10-dev-203">
- <artifact name="android-documentation-plugin-1.8.10-dev-203.jar">
- <sha256 value="388125760e133d6cf80d8277990532a8037ba29c9beb57f8daf4f268f0e9a6ed" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <component group="org.jetbrains.dokka" name="android-documentation-plugin" version="1.8.20-dev-214">
+ <artifact name="android-documentation-plugin-1.8.20-dev-214.jar">
+ <sha256 value="d2e79150a6c6846b633777500bdb50986bbdf6eed3ed002d8b28b04068b5c435" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
- <artifact name="android-documentation-plugin-1.8.10-dev-203.module">
- <sha256 value="5653f9361ed738ddff84ff5a4a2aef26e5983113ec7cac6a7e9d14d51b7f0905" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <artifact name="android-documentation-plugin-1.8.20-dev-214.module">
+ <sha256 value="adbb064752b113973c3fe4c8a0bb8f393329fa1ee06201f282b8a9c1dbe7860e" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
- <component group="org.jetbrains.dokka" name="dokka-analysis" version="1.8.10-dev-203">
- <artifact name="dokka-analysis-1.8.10-dev-203.jar">
- <sha256 value="f92acffcf55a8ecd1ca1d86224fe9c0477c2efc2f2a80a3541250620dab31c3f" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <component group="org.jetbrains.dokka" name="dokka-analysis" version="1.8.20-dev-214">
+ <artifact name="dokka-analysis-1.8.20-dev-214.jar">
+ <sha256 value="e3b653cf8f327ac5f524d8a35c77aa18fd687be3458bc08d2db884b188ca3764" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
- <artifact name="dokka-analysis-1.8.10-dev-203.module">
- <sha256 value="0ca9f55d947ec7c03a1169a67f8ec328c135efb359621a80a633aca53d5ba278" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <artifact name="dokka-analysis-1.8.20-dev-214.module">
+ <sha256 value="1729c26f02f434cfd00b0e6b94ad5596d3294485fe75d22258fa0d44fdcc5654" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
- <component group="org.jetbrains.dokka" name="dokka-base" version="1.8.10-dev-203">
- <artifact name="dokka-base-1.8.10-dev-203.jar">
- <sha256 value="87a7737029f32a602bd5e04146e5919b46be2eadbacf5ad7bd151f78d6caf1ff" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <component group="org.jetbrains.dokka" name="dokka-base" version="1.8.20-dev-214">
+ <artifact name="dokka-base-1.8.20-dev-214.jar">
+ <sha256 value="9f87f1bb70339e68bef51eb31504272250d7510cd3c7d3c58149f8c8e2d3a845" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
- <artifact name="dokka-base-1.8.10-dev-203.module">
- <sha256 value="842b421bd24ac2a154dd6b10f358eb31ed5d498340b75898c68e88ff72f14714" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <artifact name="dokka-base-1.8.20-dev-214.module">
+ <sha256 value="b6d52b99443496c59ada568513a3206a353d02a32537c61335f5351aa486deb3" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
- <component group="org.jetbrains.dokka" name="dokka-cli" version="1.8.10-dev-203">
- <artifact name="dokka-cli-1.8.10-dev-203.jar">
- <sha256 value="aac1f51acff796df791343aab7e52c7d1828c14811c63aeb17d8b4f2815f1433" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <component group="org.jetbrains.dokka" name="dokka-cli" version="1.8.20-dev-214">
+ <artifact name="dokka-cli-1.8.20-dev-214.jar">
+ <sha256 value="239389758f6fbb6b7feaa84f776404c65b2eca3e189ba9681adb024162b5d685" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
- <artifact name="dokka-cli-1.8.10-dev-203.pom">
- <sha256 value="18e6494b8198025538bc36f4ed81cbcb61c72c6d2d9fdb0162d0981404f65bac" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <artifact name="dokka-cli-1.8.20-dev-214.pom">
+ <sha256 value="dcc64c910ecf7fe3f32c6890bee82f95d7a3376370bc944575d01fdfba5b73e1" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
- <component group="org.jetbrains.dokka" name="kotlin-analysis-compiler" version="1.8.10-dev-203">
- <artifact name="kotlin-analysis-compiler-1.8.10-dev-203.jar">
- <sha256 value="a220e6566c17fdf57e66bc76678876dcb5a1605a00107561588209df84700e2e" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <component group="org.jetbrains.dokka" name="kotlin-analysis-compiler" version="1.8.20-dev-214">
+ <artifact name="kotlin-analysis-compiler-1.8.20-dev-214.jar">
+ <sha256 value="fab55a53e5fbd5211a9965403ad96b3df449badf57700ceddb1cfaad27d448bb" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
- <artifact name="kotlin-analysis-compiler-1.8.10-dev-203.pom">
- <sha256 value="11479e6eea4f5d6758e5993e3240ceeb9ac2f19de043cdacba2a10c39d1ce6b4" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <artifact name="kotlin-analysis-compiler-1.8.20-dev-214.pom">
+ <sha256 value="c1e87b3b1b57a8754bc73fea6bb1adaf38b3d2ca92451a9a67ea56c9fa5f0c9e" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
- <component group="org.jetbrains.dokka" name="kotlin-analysis-intellij" version="1.8.10-dev-203">
- <artifact name="kotlin-analysis-intellij-1.8.10-dev-203.jar">
- <sha256 value="7e8fa87cfe4aa342844e571cd6d71274e4ef0694f90c64527b534603cd2a8545" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <component group="org.jetbrains.dokka" name="kotlin-analysis-intellij" version="1.8.20-dev-214">
+ <artifact name="kotlin-analysis-intellij-1.8.20-dev-214.jar">
+ <sha256 value="26c90e9ee433b5fa90c5f73024f822ec4bc5842321b45e253748da22024ec28c" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
- <artifact name="kotlin-analysis-intellij-1.8.10-dev-203.pom">
- <sha256 value="16bb57be30478e0a2f9ec0923aa4ca362c55c511282c01ad7d92d7dc1f8823c3" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <artifact name="kotlin-analysis-intellij-1.8.20-dev-214.pom">
+ <sha256 value="fd0c843137358b974e9cb17dfff93d499cfa23d73fa323027d87dd164e82e064" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
- <component group="org.jetbrains.dokka" name="templating-plugin" version="1.8.10-dev-203">
- <artifact name="templating-plugin-1.8.10-dev-203.jar">
- <sha256 value="30b12682ffe08a886f8a78ee1df307c36a23dec5764c580665924d7fac9ba2d9" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <component group="org.jetbrains.dokka" name="templating-plugin" version="1.8.20-dev-214">
+ <artifact name="templating-plugin-1.8.20-dev-214.jar">
+ <sha256 value="0202febabbe3d81433b796c8994182b98ae854707ba0d1299564d1a4bb1d3dcd" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
- <artifact name="templating-plugin-1.8.10-dev-203.module">
- <sha256 value="0eadb5d9052cf9cd3e2da9681c8de8367a272b524b4915c3b11eb87e789655b6" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <artifact name="templating-plugin-1.8.20-dev-214.module">
+ <sha256 value="48eae7955b0ca94581efdc44fbae410549bdeb1cf81d5e226c4e8615a9304000" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="kotlin-reflect" version="1.3.71">
@@ -830,12 +872,12 @@
<sha256 value="4df94aaeee8d900be431386e31ef44e82a66e57c3ae30866aec2875aff01fe70" origin="Generated by Gradle"/>
</artifact>
</component>
- <component group="org.jetbrains.kotlinx" name="kotlinx-benchmark-plugin" version="0.4.7">
- <artifact name="kotlinx-benchmark-plugin-0.4.7.jar">
- <sha256 value="f090dad33b57e3dba4ea25a42350e19d6863213342937a5982c88a74166d08db" origin="generated by gradle" reason="Artifact is not signed"/>
+ <component group="org.jetbrains.kotlinx" name="kotlinx-benchmark-plugin" version="0.4.8">
+ <artifact name="kotlinx-benchmark-plugin-0.4.8.jar">
+ <sha256 value="dcae0aabbae9374f6326e2dd26493dafaac0a7790d2d982a61fa3c779eea660c" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
- <artifact name="kotlinx-benchmark-plugin-0.4.7.module">
- <sha256 value="7a937502d3a6c6cca8e08ff7c9b6947d410c13abd17f43a9dca79446ee2e1ca3" origin="generated by gradle" reason="Artifact is not signed"/>
+ <artifact name="kotlinx-benchmark-plugin-0.4.8.module">
+ <sha256 value="e5a19c0db8f1aa06ab506db78918720508e57696e9bf3018f05e7c8db6ffb34e" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core-metadata" version="1.4.1">
@@ -856,9 +898,9 @@
<sha256 value="c6c38e1fb8d99d1d41728b0f055e490d5e463c1252f13e7bb6f7015c22c95ab6" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
- <component group="org.jetbrains.kotlinx.benchmark" name="org.jetbrains.kotlinx.benchmark.gradle.plugin" version="0.4.7">
- <artifact name="org.jetbrains.kotlinx.benchmark.gradle.plugin-0.4.7.pom">
- <sha256 value="59fec57251015a7c2577b1527a8e213d08278aa0e1b121e3e146dec3f2eb1680" origin="Generated by Gradle" reason="Artifact is not signed"/>
+ <component group="org.jetbrains.kotlinx.benchmark" name="org.jetbrains.kotlinx.benchmark.gradle.plugin" version="0.4.8">
+ <artifact name="org.jetbrains.kotlinx.benchmark.gradle.plugin-0.4.8.pom">
+ <sha256 value="094140c425967f8ca98a2bdaf4bf293315b057e141c1dec85b1898d78b601536" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="org.jetbrains.skiko" name="skiko" version="0.7.7">
diff --git a/gradlew b/gradlew
index fc93b47..d4e9c09 100755
--- a/gradlew
+++ b/gradlew
@@ -26,7 +26,6 @@
if [ -n "$DIST_DIR" ]; then
mkdir -p "$DIST_DIR"
DIST_DIR="$(cd $DIST_DIR && pwd -P)"
- export LINT_PRINT_STACKTRACE=true
#Set the initial heap size to match the max heap size,
#by replacing a string like "-Xmx1g" with one like "-Xms1g -Xmx1g"
diff --git a/gridlayout/gridlayout/api/1.1.0-beta02.txt b/gridlayout/gridlayout/api/1.1.0-beta02.txt
new file mode 100644
index 0000000..475b482
--- /dev/null
+++ b/gridlayout/gridlayout/api/1.1.0-beta02.txt
@@ -0,0 +1,71 @@
+// Signature format: 4.0
+package androidx.gridlayout.widget {
+
+ public class GridLayout extends android.view.ViewGroup {
+ ctor public GridLayout(android.content.Context!);
+ ctor public GridLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public GridLayout(android.content.Context!, android.util.AttributeSet!, int);
+ method protected androidx.gridlayout.widget.GridLayout.LayoutParams! generateDefaultLayoutParams();
+ method public androidx.gridlayout.widget.GridLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+ method protected androidx.gridlayout.widget.GridLayout.LayoutParams! generateLayoutParams(android.view.ViewGroup.LayoutParams!);
+ method public int getAlignmentMode();
+ method public int getColumnCount();
+ method public int getOrientation();
+ method public android.util.Printer! getPrinter();
+ method public int getRowCount();
+ method public boolean getUseDefaultMargins();
+ method public boolean isColumnOrderPreserved();
+ method public boolean isRowOrderPreserved();
+ method public void setAlignmentMode(int);
+ method public void setColumnCount(int);
+ method public void setColumnOrderPreserved(boolean);
+ method public void setOrientation(int);
+ method public void setPrinter(android.util.Printer!);
+ method public void setRowCount(int);
+ method public void setRowOrderPreserved(boolean);
+ method public void setUseDefaultMargins(boolean);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, androidx.gridlayout.widget.GridLayout.Alignment!);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, androidx.gridlayout.widget.GridLayout.Alignment!, float);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, float);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, int);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, int, androidx.gridlayout.widget.GridLayout.Alignment!);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, int, androidx.gridlayout.widget.GridLayout.Alignment!, float);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, int, float);
+ field public static final int ALIGN_BOUNDS = 0; // 0x0
+ field public static final int ALIGN_MARGINS = 1; // 0x1
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! BASELINE;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! BOTTOM;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! CENTER;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! END;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! FILL;
+ field public static final int HORIZONTAL = 0; // 0x0
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! LEFT;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! RIGHT;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! START;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! TOP;
+ field public static final int UNDEFINED = -2147483648; // 0x80000000
+ field public static final int VERTICAL = 1; // 0x1
+ }
+
+ public abstract static class GridLayout.Alignment {
+ }
+
+ public static class GridLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public GridLayout.LayoutParams();
+ ctor public GridLayout.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+ ctor public GridLayout.LayoutParams(android.view.ViewGroup.LayoutParams!);
+ ctor public GridLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams!);
+ ctor public GridLayout.LayoutParams(androidx.gridlayout.widget.GridLayout.LayoutParams!);
+ ctor public GridLayout.LayoutParams(androidx.gridlayout.widget.GridLayout.Spec!, androidx.gridlayout.widget.GridLayout.Spec!);
+ method public void setGravity(int);
+ field public androidx.gridlayout.widget.GridLayout.Spec! columnSpec;
+ field public androidx.gridlayout.widget.GridLayout.Spec! rowSpec;
+ }
+
+ public static class GridLayout.Spec {
+ method public androidx.gridlayout.widget.GridLayout.Alignment! getAbsoluteAlignment(boolean);
+ }
+
+}
+
diff --git a/gridlayout/gridlayout/api/res-1.1.0-beta02.txt b/gridlayout/gridlayout/api/res-1.1.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gridlayout/gridlayout/api/res-1.1.0-beta02.txt
diff --git a/gridlayout/gridlayout/api/restricted_1.1.0-beta02.txt b/gridlayout/gridlayout/api/restricted_1.1.0-beta02.txt
new file mode 100644
index 0000000..475b482
--- /dev/null
+++ b/gridlayout/gridlayout/api/restricted_1.1.0-beta02.txt
@@ -0,0 +1,71 @@
+// Signature format: 4.0
+package androidx.gridlayout.widget {
+
+ public class GridLayout extends android.view.ViewGroup {
+ ctor public GridLayout(android.content.Context!);
+ ctor public GridLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public GridLayout(android.content.Context!, android.util.AttributeSet!, int);
+ method protected androidx.gridlayout.widget.GridLayout.LayoutParams! generateDefaultLayoutParams();
+ method public androidx.gridlayout.widget.GridLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+ method protected androidx.gridlayout.widget.GridLayout.LayoutParams! generateLayoutParams(android.view.ViewGroup.LayoutParams!);
+ method public int getAlignmentMode();
+ method public int getColumnCount();
+ method public int getOrientation();
+ method public android.util.Printer! getPrinter();
+ method public int getRowCount();
+ method public boolean getUseDefaultMargins();
+ method public boolean isColumnOrderPreserved();
+ method public boolean isRowOrderPreserved();
+ method public void setAlignmentMode(int);
+ method public void setColumnCount(int);
+ method public void setColumnOrderPreserved(boolean);
+ method public void setOrientation(int);
+ method public void setPrinter(android.util.Printer!);
+ method public void setRowCount(int);
+ method public void setRowOrderPreserved(boolean);
+ method public void setUseDefaultMargins(boolean);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, androidx.gridlayout.widget.GridLayout.Alignment!);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, androidx.gridlayout.widget.GridLayout.Alignment!, float);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, float);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, int);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, int, androidx.gridlayout.widget.GridLayout.Alignment!);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, int, androidx.gridlayout.widget.GridLayout.Alignment!, float);
+ method public static androidx.gridlayout.widget.GridLayout.Spec! spec(int, int, float);
+ field public static final int ALIGN_BOUNDS = 0; // 0x0
+ field public static final int ALIGN_MARGINS = 1; // 0x1
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! BASELINE;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! BOTTOM;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! CENTER;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! END;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! FILL;
+ field public static final int HORIZONTAL = 0; // 0x0
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! LEFT;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! RIGHT;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! START;
+ field public static final androidx.gridlayout.widget.GridLayout.Alignment! TOP;
+ field public static final int UNDEFINED = -2147483648; // 0x80000000
+ field public static final int VERTICAL = 1; // 0x1
+ }
+
+ public abstract static class GridLayout.Alignment {
+ }
+
+ public static class GridLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public GridLayout.LayoutParams();
+ ctor public GridLayout.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+ ctor public GridLayout.LayoutParams(android.view.ViewGroup.LayoutParams!);
+ ctor public GridLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams!);
+ ctor public GridLayout.LayoutParams(androidx.gridlayout.widget.GridLayout.LayoutParams!);
+ ctor public GridLayout.LayoutParams(androidx.gridlayout.widget.GridLayout.Spec!, androidx.gridlayout.widget.GridLayout.Spec!);
+ method public void setGravity(int);
+ field public androidx.gridlayout.widget.GridLayout.Spec! columnSpec;
+ field public androidx.gridlayout.widget.GridLayout.Spec! rowSpec;
+ }
+
+ public static class GridLayout.Spec {
+ method public androidx.gridlayout.widget.GridLayout.Alignment! getAbsoluteAlignment(boolean);
+ }
+
+}
+
diff --git a/health/connect/connect-client/lint-baseline.xml b/health/connect/connect-client/lint-baseline.xml
index c5e5522..c3fe024 100644
--- a/health/connect/connect-client/lint-baseline.xml
+++ b/health/connect/connect-client/lint-baseline.xml
@@ -1,149 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class ApiVersionException extends ExecutionException {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/ApiVersionException.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class BaseQueueOperation implements QueueOperation {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/internal/BaseQueueOperation.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public abstract class Client<S extends IInterface> {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class ClientConfiguration {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/ClientConfiguration.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public final class ConnectionConfiguration {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionConfiguration.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public final class ConnectionManager implements Handler.Callback, ServiceConnection.Callback {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionManager.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class DefaultExecutionTracker implements ExecutionTracker {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/internal/DefaultExecutionTracker.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface ExecutionTracker {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/internal/ExecutionTracker.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public final class HealthDataServiceConstants {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/service/HealthDataServiceConstants.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public final class ListenerKey {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/internal/ListenerKey.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface QueueOperation {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/internal/QueueOperation.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface RemoteFutureOperation<S, R> {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/RemoteFutureOperation.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface RemoteOperation<S, R> {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/RemoteOperation.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public final class SdkConfig {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/SdkConfig.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class ServiceConnection implements android.content.ServiceConnection {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnection.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface ServiceOperation<R> {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/platform/client/impl/ipc/ServiceOperation.java"/>
- </issue>
+<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">
<issue
id="BanSynchronizedMethods"
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/package-info.java
index b6649f7..a030e03 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
package androidx.health.data.client.impl;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/BloodGlucose.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/BloodGlucose.kt
index aa41934..3b5756e 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/BloodGlucose.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/BloodGlucose.kt
@@ -18,11 +18,11 @@
/**
* Represents a unit of blood glucose level (glycaemia). Supported units:
- *
* - mmol/L - see [BloodGlucose.millimolesPerLiter]
* - mg/dL - see [BloodGlucose.milligramsPerDeciliter]
- **/
-class BloodGlucose private constructor(
+ */
+class BloodGlucose
+private constructor(
private val value: Double,
private val type: Type,
) : Comparable<BloodGlucose> {
@@ -43,39 +43,30 @@
/** Returns zero [BloodGlucose] of the same [Type]. */
internal fun zero(): BloodGlucose = ZEROS.getValue(type)
- override fun compareTo(other: BloodGlucose): Int = if (type == other.type) {
- value.compareTo(other.value)
- } else {
- inMillimolesPerLiter.compareTo(other.inMillimolesPerLiter)
- }
+ override fun compareTo(other: BloodGlucose): Int =
+ if (type == other.type) {
+ value.compareTo(other.value)
+ } else {
+ inMillimolesPerLiter.compareTo(other.inMillimolesPerLiter)
+ }
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is BloodGlucose) return false
- if (value != other.value) return false
- if (type != other.type) return false
+ if (type == other.type) {
+ return value == other.value
+ }
- return true
+ return inMillimolesPerLiter == other.inMillimolesPerLiter
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
- override fun hashCode(): Int {
- var result = value.hashCode()
- result = 31 * result + type.hashCode()
- return result
- }
+ override fun hashCode(): Int = inMillimolesPerLiter.hashCode()
override fun toString(): String = "$value ${type.title}"
companion object {
- private val ZEROS =
- Type.values().associateWith { BloodGlucose(value = 0.0, type = it) }
+ private val ZEROS = Type.values().associateWith { BloodGlucose(value = 0.0, type = it) }
/** Creates [BloodGlucose] with the specified value in mmol/L. */
@JvmStatic
@@ -91,7 +82,8 @@
private enum class Type {
MILLIMOLES_PER_LITER {
override val millimolesPerLiterPerUnit: Double = 1.0
- override val title: String get() = "mmol/L"
+ override val title: String
+ get() = "mmol/L"
},
MILLIGRAMS_PER_DECILITER {
override val millimolesPerLiterPerUnit: Double = 1 / 18.0
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Energy.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Energy.kt
index 942982a..606b7c2 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Energy.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Energy.kt
@@ -18,13 +18,13 @@
/**
* Represents a unit of energy. Supported units:
- *
* - calories - see [Energy.calories], [Double.calories]
* - kilocalories - see [Energy.kilocalories], [Double.kilocalories]
* - joules - see [Energy.joules], [Double.joules]
* - kilojoules - see [Energy.kilojoules], [Double.kilojoules]
*/
-class Energy private constructor(
+class Energy
+private constructor(
private val value: Double,
private val type: Type,
) : Comparable<Energy> {
@@ -62,27 +62,18 @@
inCalories.compareTo(other.inCalories)
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Energy) return false
- if (value != other.value) return false
- if (type != other.type) return false
+ if (type == other.type) {
+ return value == other.value
+ }
- return true
+ return inCalories == other.inCalories
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
- override fun hashCode(): Int {
- var result = value.hashCode()
- result = 31 * result + type.hashCode()
- return result
- }
+ override fun hashCode(): Int = inCalories.hashCode()
override fun toString(): String = "$value ${type.title}"
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Length.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Length.kt
index 30f3daf..f320e98 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Length.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Length.kt
@@ -61,27 +61,18 @@
inMeters.compareTo(other.inMeters)
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Length) return false
- if (value != other.value) return false
- if (type != other.type) return false
+ if (type == other.type) {
+ return value == other.value
+ }
- return true
+ return inMeters == other.inMeters
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
- override fun hashCode(): Int {
- var result = value.hashCode()
- result = 31 * result + type.hashCode()
- return result
- }
+ override fun hashCode(): Int = inMeters.hashCode()
override fun toString(): String = "$value ${type.name.lowercase()}"
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Mass.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Mass.kt
index babdd20..408d8f0 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Mass.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Mass.kt
@@ -18,7 +18,6 @@
/**
* Represents a unit of mass. Supported units:
- *
* - grams - see [Mass.grams], [Double.grams]
* - kilograms - see [Mass.kilograms], [Double.kilograms]
* - milligrams - see [Mass.milligrams], [Double.milligrams]
@@ -26,7 +25,8 @@
* - ounces - see [Mass.ounces], [Double.ounces]
* - pounds - see [Mass.pounds], [Double.pounds]
*/
-class Mass private constructor(
+class Mass
+private constructor(
private val value: Double,
private val type: Type,
) : Comparable<Mass> {
@@ -74,27 +74,18 @@
inGrams.compareTo(other.inGrams)
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Mass) return false
- if (value != other.value) return false
- if (type != other.type) return false
+ if (type == other.type) {
+ return value == other.value
+ }
- return true
+ return inGrams == other.inGrams
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
- override fun hashCode(): Int {
- var result = value.hashCode()
- result = 31 * result + type.hashCode()
- return result
- }
+ override fun hashCode(): Int = inGrams.hashCode()
override fun toString(): String = "$value ${type.name.lowercase()}"
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Percentage.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Percentage.kt
index c7a13d1..34ac2c3 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Percentage.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Percentage.kt
@@ -21,24 +21,14 @@
override fun compareTo(other: Percentage): Int = value.compareTo(other.value)
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Percentage) return false
- if (value != other.value) return false
-
- return true
+ return value == other.value
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
- override fun hashCode(): Int {
- return value.hashCode()
- }
+ override fun hashCode(): Int = value.hashCode()
override fun toString(): String = "$value%"
}
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Power.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Power.kt
index 41dfd33..6caae89 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Power.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Power.kt
@@ -18,11 +18,11 @@
/**
* Represents a unit of power. Supported units:
- *
* - watts - see [Power.watts], [Double.watts]
* - kilocalories/day - see [Power.kilocaloriesPerDay], [Double.kilocaloriesPerDay]
- **/
-class Power private constructor(
+ */
+class Power
+private constructor(
private val value: Double,
private val type: Type,
) : Comparable<Power> {
@@ -50,27 +50,18 @@
inWatts.compareTo(other.inWatts)
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Power) return false
- if (value != other.value) return false
- if (type != other.type) return false
+ if (type == other.type) {
+ return value == other.value
+ }
- return true
+ return inWatts == other.inWatts
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
- override fun hashCode(): Int {
- var result = value.hashCode()
- result = 31 * result + type.hashCode()
- return result
- }
+ override fun hashCode(): Int = inWatts.hashCode()
override fun toString(): String = "$value ${type.title}"
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Pressure.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Pressure.kt
index c0091f5..4ab9611 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Pressure.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Pressure.kt
@@ -18,11 +18,11 @@
/**
* Represents a unit of pressure. Supported units:
- *
* - millimeters of Mercury (mmHg) - see [Pressure.millimetersOfMercury],
- * [Double.millimetersOfMercury].
+ * [Double.millimetersOfMercury].
*/
-class Pressure private constructor(
+class Pressure
+private constructor(
private val value: Double,
) : Comparable<Pressure> {
@@ -36,24 +36,14 @@
override fun compareTo(other: Pressure): Int = value.compareTo(other.value)
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Pressure) return false
- if (value != other.value) return false
-
- return true
+ return value == other.value
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
- override fun hashCode(): Int {
- return value.hashCode()
- }
+ override fun hashCode(): Int = value.hashCode()
override fun toString(): String = "$value mmHg"
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Temperature.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Temperature.kt
index 5a1d80e..77e1f1f 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Temperature.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Temperature.kt
@@ -16,12 +16,13 @@
package androidx.health.connect.client.units
-/** Represents a unit of temperature. Supported units:
- *
+/**
+ * Represents a unit of temperature. Supported units:
* - Celsius - see [Temperature.celsius], [Double.celsius]
* - Fahrenheit - see [Temperature.fahrenheit], [Double.fahrenheit]
- **/
-class Temperature private constructor(
+ */
+class Temperature
+private constructor(
private val value: Double,
private val type: Type,
) : Comparable<Temperature> {
@@ -51,27 +52,18 @@
inCelsius.compareTo(other.inCelsius)
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Temperature) return false
- if (value != other.value) return false
- if (type != other.type) return false
+ if (type == other.type) {
+ return value == other.value
+ }
- return true
+ return inCelsius == other.inCelsius
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
- override fun hashCode(): Int {
- var result = value.hashCode()
- result = 31 * result + type.hashCode()
- return result
- }
+ override fun hashCode(): Int = inCelsius.hashCode()
override fun toString(): String = "$value ${type.title}"
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Velocity.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Velocity.kt
index 9a15e36..ae7da91 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Velocity.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Velocity.kt
@@ -18,12 +18,12 @@
/**
* Represents a unit of speed. Supported units:
- *
* - metersPerSecond - see [Velocity.metersPerSecond], [Double.metersPerSecond]
* - kilometersPerHour - see [Velocity.kilometersPerHour], [Double.kilometersPerHour]
* - milesPerHour - see [Velocity.milesPerHour], [Double.milesPerHour]
*/
-class Velocity private constructor(
+class Velocity
+private constructor(
private val value: Double,
private val type: Type,
) : Comparable<Velocity> {
@@ -56,27 +56,18 @@
inMetersPerSecond.compareTo(other.inMetersPerSecond)
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Velocity) return false
- if (value != other.value) return false
- if (type != other.type) return false
+ if (type == other.type) {
+ return value == other.value
+ }
- return true
+ return inMetersPerSecond == other.inMetersPerSecond
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
- override fun hashCode(): Int {
- var result = value.hashCode()
- result = 31 * result + type.hashCode()
- return result
- }
+ override fun hashCode(): Int = inMetersPerSecond.hashCode()
override fun toString(): String = "$value ${type.title}"
@@ -92,8 +83,7 @@
fun kilometersPerHour(value: Double): Velocity = Velocity(value, Type.KILOMETERS_PER_HOUR)
/** Creates [Velocity] with the specified value in miles per hour. */
- @JvmStatic
- fun milesPerHour(value: Double): Velocity = Velocity(value, Type.MILES_PER_HOUR)
+ @JvmStatic fun milesPerHour(value: Double): Velocity = Velocity(value, Type.MILES_PER_HOUR)
}
private enum class Type {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Volume.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Volume.kt
index 723be33..4ec0a30 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Volume.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/units/Volume.kt
@@ -18,12 +18,12 @@
/**
* Represents a unit of volume. Supported units:
- *
* - liters - see [Volume.liters], [Double.liters]
* - milliliters - see [Volume.milliliters], [Double.milliliters]
* - US fluid ounces - see [Volume.fluidOuncesUs], [Double.fluidOuncesUs]
*/
-class Volume private constructor(
+class Volume
+private constructor(
private val value: Double,
private val type: Type,
) : Comparable<Volume> {
@@ -56,27 +56,18 @@
inLiters.compareTo(other.inLiters)
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Volume) return false
- if (value != other.value) return false
- if (type != other.type) return false
+ if (type == other.type) {
+ return value == other.value
+ }
- return true
+ return inLiters == other.inLiters
}
- /*
- * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
- */
- override fun hashCode(): Int {
- var result = value.hashCode()
- result = 31 * result + type.hashCode()
- return result
- }
+ override fun hashCode(): Int = inLiters.hashCode()
override fun toString(): String = "$value ${type.title}"
@@ -84,16 +75,13 @@
private val ZEROS = Type.values().associateWith { Volume(value = 0.0, type = it) }
/** Creates [Volume] with the specified value in liters. */
- @JvmStatic
- fun liters(value: Double): Volume = Volume(value, Type.LITERS)
+ @JvmStatic fun liters(value: Double): Volume = Volume(value, Type.LITERS)
/** Creates [Volume] with the specified value in milliliters. */
- @JvmStatic
- fun milliliters(value: Double): Volume = Volume(value, Type.MILLILITERS)
+ @JvmStatic fun milliliters(value: Double): Volume = Volume(value, Type.MILLILITERS)
/** Creates [Volume] with the specified value in US fluid ounces. */
- @JvmStatic
- fun fluidOuncesUs(value: Double): Volume = Volume(value, Type.FLUID_OUNCES_US)
+ @JvmStatic fun fluidOuncesUs(value: Double): Volume = Volume(value, Type.FLUID_OUNCES_US)
}
private enum class Type {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java
index 11d19e7..674c27b 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java
@@ -20,7 +20,6 @@
/**
* SDK Configurations
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public final class SdkConfig {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/data/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/data/package-info.java
index 4f31964..039a98f 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/data/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/data/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
package androidx.health.platform.client.impl.data;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/error/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/error/package-info.java
index fe07ca8..851a0f7 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/error/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/error/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
package androidx.health.platform.client.impl.error;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ApiVersionException.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ApiVersionException.java
index 6b518f2..a4501f7 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ApiVersionException.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ApiVersionException.java
@@ -24,7 +24,6 @@
/**
* Exception that is thrown when API version requirements are not met.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public class ApiVersionException extends ExecutionException {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/Client.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/Client.java
index 58e2fa1..1d57eda 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/Client.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/Client.java
@@ -43,7 +43,6 @@
* interface. For user instruction see: go/wear-dd-wcs-sdk
*
* @param <S> type of the service interface
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public abstract class Client<S extends IInterface> {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ClientConfiguration.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ClientConfiguration.java
index 144a439..ddcaff0 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ClientConfiguration.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ClientConfiguration.java
@@ -23,7 +23,6 @@
* An interface that provides basic information about the IPC service. This is required for building
* the service in {@link Client}.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public class ClientConfiguration {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteFutureOperation.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteFutureOperation.java
index ff7e489..05a4b7b 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteFutureOperation.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteFutureOperation.java
@@ -29,7 +29,6 @@
*
* @param <S> type of the remote service
* @param <R> type of the result value
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public interface RemoteFutureOperation<S, R> {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteOperation.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteOperation.java
index cb7fc06..4b2ab5e 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteOperation.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteOperation.java
@@ -26,7 +26,6 @@
*
* @param <S> type of the remote service
* @param <R> type of the returned value
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public interface RemoteOperation<S, R> {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ServiceOperation.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ServiceOperation.java
index 6c2383c..87e5f29 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ServiceOperation.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ServiceOperation.java
@@ -30,7 +30,6 @@
* result value.
*
* @param <R> Type of the returned value.
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public interface ServiceOperation<R> {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/BaseQueueOperation.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/BaseQueueOperation.java
index 99f60db..1479766 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/BaseQueueOperation.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/BaseQueueOperation.java
@@ -29,7 +29,6 @@
* Abstract implementation of QueueOperation that accepts {@link ConnectionConfiguration} describing
* the service where it will be executed.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public class BaseQueueOperation implements QueueOperation {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionConfiguration.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionConfiguration.java
index 754fc0a..6172dac 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionConfiguration.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionConfiguration.java
@@ -24,7 +24,6 @@
/**
* Internal representation of configuration of IPC service connection.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public final class ConnectionConfiguration {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionManager.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionManager.java
index 25cb64c..d3f5c27 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionManager.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionManager.java
@@ -34,7 +34,6 @@
/**
* Manages connections to a service in a different process.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public final class ConnectionManager implements Handler.Callback, ServiceConnection.Callback {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/DefaultExecutionTracker.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/DefaultExecutionTracker.java
index 52d1237..9c56f9a 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/DefaultExecutionTracker.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/DefaultExecutionTracker.java
@@ -28,7 +28,6 @@
/**
* Default implementation of {@link ExecutionTracker}.
*
- * @hide
*/
@SuppressWarnings("ExecutorTaskName")
@RestrictTo(Scope.LIBRARY)
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ExecutionTracker.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ExecutionTracker.java
index 07101ea..e9e991c 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ExecutionTracker.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ExecutionTracker.java
@@ -24,7 +24,6 @@
/**
* Tracker for tracking operations that are currently in progress.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public interface ExecutionTracker {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ListenerKey.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ListenerKey.java
index 3da03c11..32fbada 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ListenerKey.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ListenerKey.java
@@ -23,7 +23,6 @@
/**
* Unique key to hold listener reference.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public final class ListenerKey {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/QueueOperation.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/QueueOperation.java
index e3c92db..421a883 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/QueueOperation.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/QueueOperation.java
@@ -26,7 +26,6 @@
* A wrapper for SDK operation that will be executed on a connected binder. It is intended for
* scheduling in execution queue.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public interface QueueOperation {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnection.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnection.java
index 3372711..b57c87c 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnection.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnection.java
@@ -47,7 +47,6 @@
*
* <p>Note: this class is not thread safe and should be called always from the same thread.
*
- * @hide
*/
@NotThreadSafe
@RestrictTo(Scope.LIBRARY)
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/package-info.java
index 1c1e847..2a3bb4d 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/ipc/package-info.java
@@ -16,7 +16,6 @@
/**
* A temporary fork of wear-ipc code source. Migrate to reuse the library once it is published.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
package androidx.health.platform.client.impl.ipc;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/package-info.java
index 567c26e..a1f0e51 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
package androidx.health.platform.client.impl;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/permission/foregroundstate/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/permission/foregroundstate/package-info.java
index 5c17428..88dc642 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/permission/foregroundstate/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/permission/foregroundstate/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
package androidx.health.platform.client.impl.permission.foregroundstate;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/permission/token/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/permission/token/package-info.java
index 7dc9361..5577f9b 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/permission/token/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/permission/token/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
package androidx.health.platform.client.impl.permission.token;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/sdkservice/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/sdkservice/package-info.java
index 849ce71..3b8c157 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/sdkservice/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/impl/sdkservice/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
package androidx.health.platform.client.impl.sdkservice;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/package-info.java
index f5920e8..1cca33e 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
package androidx.health.platform.client;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/permission/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/permission/package-info.java
index ea35fd9..cb3d1d2 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/permission/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/permission/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
package androidx.health.platform.client.permission;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/proto/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/proto/package-info.java
index c50c645..5159f67 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/proto/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/proto/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
package androidx.health.platform.client.proto;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/request/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/request/package-info.java
index dd924bb..d830330 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/request/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/request/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
package androidx.health.platform.client.request;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/response/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/response/package-info.java
index 3d3d506..e56d58b 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/response/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/response/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY)
package androidx.health.platform.client.response;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/service/HealthDataServiceConstants.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/service/HealthDataServiceConstants.java
index 0f531f9..45b3d8c 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/service/HealthDataServiceConstants.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/service/HealthDataServiceConstants.java
@@ -21,7 +21,6 @@
/**
* Class to hold common constants for AHP.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public final class HealthDataServiceConstants {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/utils/package-info.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/utils/package-info.java
index 61c752d..985645d 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/utils/package-info.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/utils/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
package androidx.health.platform.client.utils;
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/BloodGlucoseTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/BloodGlucoseTest.kt
index d6d4892..8a7b4ed 100644
--- a/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/BloodGlucoseTest.kt
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/BloodGlucoseTest.kt
@@ -25,11 +25,9 @@
@RunWith(AndroidJUnit4::class)
class BloodGlucoseTest {
- @Rule
- @JvmField
- val expect = Expect.create()
+ @Rule @JvmField val expect = Expect.create()
- private val tests: List<Triple<Double, Double, String>> =
+ private val conversions: List<Triple<Double, Double, String>> =
listOf(
Triple(
BloodGlucose.millimolesPerLiter(5.0).inMilligramsPerDeciliter,
@@ -54,9 +52,47 @@
)
@Test
- fun testAll() {
- for (test in tests) {
- expect.withMessage(test.third).that(test.first).isWithin(0.00001).of(test.second)
+ fun conversion() {
+ for (conversion in conversions) {
+ expect
+ .withMessage(conversion.third)
+ .that(conversion.first)
+ .isWithin(0.00001)
+ .of(conversion.second)
}
}
-}
\ No newline at end of file
+
+ @Test
+ fun equals_sameValues_areEqual() {
+ expect
+ .that(BloodGlucose.millimolesPerLiter(5.0))
+ .isEqualTo(BloodGlucose.millimolesPerLiter(5.0))
+ expect
+ .that(BloodGlucose.millimolesPerLiter(5.0))
+ .isEqualTo(BloodGlucose.milligramsPerDeciliter(5.0 * 18.0))
+ }
+
+ @Test
+ fun equals_differentValues_areNotEqual() {
+ expect
+ .that(BloodGlucose.millimolesPerLiter(5.01))
+ .isNotEqualTo(BloodGlucose.millimolesPerLiter(5.0))
+ expect
+ .that(BloodGlucose.millimolesPerLiter(5.01))
+ .isNotEqualTo(BloodGlucose.milligramsPerDeciliter(5.0 * 18.0))
+ }
+
+ @Test
+ fun hashCode_sameValues_areEqual() {
+ expect
+ .that(BloodGlucose.millimolesPerLiter(5.0).hashCode())
+ .isEqualTo(BloodGlucose.milligramsPerDeciliter(5.0 * 18.0).hashCode())
+ }
+
+ @Test
+ fun hashCode_differentValues_areNotEqual() {
+ expect
+ .that(BloodGlucose.millimolesPerLiter(5.01).hashCode())
+ .isNotEqualTo(BloodGlucose.milligramsPerDeciliter(5.0 * 18.0).hashCode())
+ }
+}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/EnergyTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/EnergyTest.kt
new file mode 100644
index 0000000..b7449012
--- /dev/null
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/EnergyTest.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.health.connect.client.units
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Expect
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class EnergyTest {
+
+ @Rule @JvmField val expect = Expect.create()
+
+ @Test
+ fun equals_sameValues_areEqual() {
+ expect.that(Energy.kilocalories(235.0)).isEqualTo(Energy.kilocalories(235.0))
+ expect.that(Energy.kilocalories(235.0)).isEqualTo(Energy.calories(235_000.0))
+ }
+
+ @Test
+ fun equals_differentValues_areNotEqual() {
+ expect.that(Energy.kilocalories(235.001)).isNotEqualTo(Energy.kilocalories(235.0))
+ expect.that(Energy.kilocalories(235.001)).isNotEqualTo(Energy.calories(235_000.0))
+ }
+
+ @Test
+ fun hashCode_sameValues_areEqual() {
+ expect
+ .that(Energy.kilocalories(235.0).hashCode())
+ .isEqualTo(Energy.calories(235_000.0).hashCode())
+ }
+
+ @Test
+ fun hashCode_differentValues_areNotEqual() {
+ expect
+ .that(Energy.kilocalories(235.001).hashCode())
+ .isNotEqualTo(Energy.calories(235_000.0).hashCode())
+ }
+}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/LengthTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/LengthTest.kt
new file mode 100644
index 0000000..8a8977b
--- /dev/null
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/LengthTest.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.connect.client.units
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Expect
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class LengthTest {
+
+ @Rule @JvmField val expect = Expect.create()
+
+ @Test
+ fun equals_sameValues_areEqual() {
+ expect.that(Length.kilometers(0.7)).isEqualTo(Length.kilometers(0.7))
+ expect.that(Length.kilometers(0.7)).isEqualTo(Length.meters(700.0))
+ }
+
+ @Test
+ fun equals_differentValues_areNotEqual() {
+ expect.that(Length.kilometers(0.70001)).isNotEqualTo(Length.kilometers(0.7))
+ expect.that(Length.kilometers(0.70001)).isNotEqualTo(Length.meters(700.0))
+ }
+
+ @Test
+ fun hashCode_sameValues_areEqual() {
+ expect.that(Length.kilometers(0.7).hashCode()).isEqualTo(Length.meters(700.0).hashCode())
+ }
+
+ @Test
+ fun hashCode_differentValues_areNotEqual() {
+ expect
+ .that(Length.kilometers(0.70001).hashCode())
+ .isNotEqualTo(Length.meters(700.0).hashCode())
+ }
+}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/MassTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/MassTest.kt
new file mode 100644
index 0000000..2e99d5b
--- /dev/null
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/MassTest.kt
@@ -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.health.connect.client.units
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Expect
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class MassTest {
+
+ @Rule @JvmField val expect = Expect.create()
+
+ @Test
+ fun equals_sameValues_areEqual() {
+ expect.that(Mass.kilograms(107.0)).isEqualTo(Mass.kilograms(107.0))
+ expect.that(Mass.kilograms(107.0)).isEqualTo(Mass.grams(107_000.0))
+ }
+
+ @Test
+ fun equals_differentValues_areNotEqual() {
+ expect.that(Mass.kilograms(107.1)).isNotEqualTo(Mass.kilograms(107.0))
+ expect.that(Mass.kilograms(107.1)).isNotEqualTo(Mass.grams(107_000.0))
+ }
+
+ @Test
+ fun hashCode_sameValues_areEqual() {
+ expect.that(Mass.kilograms(107.0).hashCode()).isEqualTo(Mass.grams(107_000.0).hashCode())
+ }
+
+ @Test
+ fun hashCode_differentValues_areNotEqual() {
+ expect.that(Mass.kilograms(107.1).hashCode()).isNotEqualTo(Mass.grams(107_000.0).hashCode())
+ }
+}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/PercentageTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/PercentageTest.kt
new file mode 100644
index 0000000..1977766
--- /dev/null
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/PercentageTest.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.connect.client.units
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Expect
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class PercentageTest {
+
+ @Rule @JvmField val expect = Expect.create()
+
+ @Test
+ fun equals_sameValues_areEqual() {
+ expect.that(Percentage(99.0)).isEqualTo(Percentage(99.0))
+ }
+
+ @Test
+ fun equals_differentValues_areNotEqual() {
+ expect.that(Percentage(99.9)).isNotEqualTo(Percentage(100.0))
+ }
+
+ @Test
+ fun hashCode_sameValues_areEqual() {
+ expect.that(Percentage(99.0).hashCode()).isEqualTo(Percentage(99.0).hashCode())
+ }
+
+ @Test
+ fun hashCode_differentValues_areNotEqual() {
+ expect.that(Percentage(99.9).hashCode()).isNotEqualTo(Percentage(100.0).hashCode())
+ }
+}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/PowerTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/PowerTest.kt
new file mode 100644
index 0000000..cb4c7bb
--- /dev/null
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/PowerTest.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.health.connect.client.units
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Expect
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class PowerTest {
+
+ @Rule @JvmField val expect = Expect.create()
+
+ @Test
+ fun equals_sameValues_areEqual() {
+ expect.that(Power.kilocaloriesPerDay(500.0)).isEqualTo(Power.kilocaloriesPerDay(500.0))
+ expect.that(Power.kilocaloriesPerDay(500.0)).isEqualTo(Power.watts(24.21296295))
+ }
+
+ @Test
+ fun equals_differentValues_areNotEqual() {
+ expect.that(Power.kilocaloriesPerDay(500.1)).isNotEqualTo(Power.kilocaloriesPerDay(500.0))
+ expect.that(Power.kilocaloriesPerDay(500.1)).isNotEqualTo(Power.watts(24.21296295))
+ }
+
+ @Test
+ fun hashCode_sameValues_areEqual() {
+ expect
+ .that(Power.kilocaloriesPerDay(500.0).hashCode())
+ .isEqualTo(Power.watts(24.21296295).hashCode())
+ }
+
+ @Test
+ fun hashCode_differentValues_areNotEqual() {
+ expect
+ .that(Power.kilocaloriesPerDay(500.1).hashCode())
+ .isNotEqualTo(Power.watts(24.21296295).hashCode())
+ }
+}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/PressureTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/PressureTest.kt
new file mode 100644
index 0000000..34ef710
--- /dev/null
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/PressureTest.kt
@@ -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.health.connect.client.units
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Expect
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class PressureTest {
+
+ @Rule @JvmField val expect = Expect.create()
+
+ @Test
+ fun equals_sameValues_areEqual() {
+ expect
+ .that(Pressure.millimetersOfMercury(10.0))
+ .isEqualTo(Pressure.millimetersOfMercury(10.0))
+ }
+
+ @Test
+ fun equals_differentValues_areNotEqual() {
+ expect
+ .that(Pressure.millimetersOfMercury(10.1))
+ .isNotEqualTo(Pressure.millimetersOfMercury(10.0))
+ }
+
+ @Test
+ fun hashCode_sameValues_areEqual() {
+ expect
+ .that(Pressure.millimetersOfMercury(10.0).hashCode())
+ .isEqualTo(Pressure.millimetersOfMercury(10.0).hashCode())
+ }
+
+ @Test
+ fun hashCode_differentValues_areNotEqual() {
+ expect
+ .that(Pressure.millimetersOfMercury(10.1).hashCode())
+ .isNotEqualTo(Pressure.millimetersOfMercury(10.0).hashCode())
+ }
+}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/TemperatureTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/TemperatureTest.kt
new file mode 100644
index 0000000..e383c3d
--- /dev/null
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/TemperatureTest.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.health.connect.client.units
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Expect
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TemperatureTest {
+
+ @Rule @JvmField val expect = Expect.create()
+
+ @Test
+ fun equals_sameValues_areEqual() {
+ expect.that(Temperature.celsius(37.6)).isEqualTo(Temperature.celsius(37.6))
+ expect.that(Temperature.celsius(37.6)).isEqualTo(Temperature.fahrenheit(99.68))
+ }
+
+ @Test
+ fun equals_differentValues_areNotEqual() {
+ expect.that(Temperature.celsius(37.61)).isNotEqualTo(Temperature.celsius(37.6))
+ expect.that(Temperature.celsius(37.61)).isNotEqualTo(Temperature.fahrenheit(99.68))
+ }
+
+ @Test
+ fun hashCode_sameValues_areEqual() {
+ expect
+ .that(Temperature.celsius(37.6).hashCode())
+ .isEqualTo(Temperature.fahrenheit(99.68).hashCode())
+ }
+
+ @Test
+ fun hashCode_differentValues_areNotEqual() {
+ expect
+ .that(Temperature.celsius(37.61).hashCode())
+ .isNotEqualTo(Temperature.fahrenheit(99.68).hashCode())
+ }
+}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/VelocityTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/VelocityTest.kt
new file mode 100644
index 0000000..70187d0
--- /dev/null
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/VelocityTest.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.connect.client.units
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Expect
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class VelocityTest {
+
+ @Rule @JvmField val expect = Expect.create()
+
+ @Test
+ fun equals_sameValues_areEqual() {
+ expect.that(Velocity.kilometersPerHour(12.0)).isEqualTo(Velocity.kilometersPerHour(12.0))
+ expect
+ .that(Velocity.kilometersPerHour(12.0))
+ .isEqualTo(Velocity.milesPerHour(7.456448341689335))
+ }
+
+ @Test
+ fun equals_differentValues_areNotEqual() {
+ expect
+ .that(Velocity.kilometersPerHour(12.001))
+ .isNotEqualTo(Velocity.kilometersPerHour(12.0))
+ expect
+ .that(Velocity.kilometersPerHour(12.001))
+ .isNotEqualTo(Velocity.milesPerHour(7.456448341689335))
+ }
+
+ @Test
+ fun hashCode_sameValues_areEqual() {
+ expect
+ .that(Velocity.kilometersPerHour(12.0).hashCode())
+ .isEqualTo(Velocity.milesPerHour(7.456448341689335).hashCode())
+ }
+
+ @Test
+ fun hashCode_differentValues_areNotEqual() {
+ expect
+ .that(Velocity.kilometersPerHour(12.001).hashCode())
+ .isNotEqualTo(Velocity.milesPerHour(7.456448341689335).hashCode())
+ }
+}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/VolumeTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/VolumeTest.kt
new file mode 100644
index 0000000..839550b
--- /dev/null
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/units/VolumeTest.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.health.connect.client.units
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Expect
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class VolumeTest {
+
+ @Rule @JvmField val expect = Expect.create()
+
+ @Test
+ fun equals_sameValues_areEqual() {
+ expect.that(Volume.liters(24.0)).isEqualTo(Volume.liters(24.0))
+ expect.that(Volume.liters(24.0)).isEqualTo(Volume.milliliters(24_000.0))
+ }
+
+ @Test
+ fun equals_differentValues_areNotEqual() {
+ expect.that(Volume.liters(24.01)).isNotEqualTo(Volume.liters(24.0))
+ expect.that(Volume.liters(24.01)).isNotEqualTo(Volume.milliliters(24_000.0))
+ }
+
+ @Test
+ fun hashCode_sameValues_areEqual() {
+ expect
+ .that(Volume.liters(24.0).hashCode())
+ .isEqualTo(Volume.milliliters(24_000.0).hashCode())
+ }
+
+ @Test
+ fun hashCode_differentValues_areNotEqual() {
+ expect
+ .that(Volume.liters(24.01).hashCode())
+ .isNotEqualTo(Volume.milliliters(24_000.0).hashCode())
+ }
+}
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IExerciseApiService.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IExerciseApiService.aidl
index 66128f6..abb715f 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IExerciseApiService.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IExerciseApiService.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IExerciseApiService {
int getApiVersion() = 0;
void prepareExercise(in androidx.health.services.client.impl.request.PrepareExerciseRequest prepareExerciseRequest, androidx.health.services.client.impl.internal.IStatusCallback statusCallback) = 14;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IExerciseUpdateListener.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IExerciseUpdateListener.aidl
index 243d16d..f4312d6 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IExerciseUpdateListener.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IExerciseUpdateListener.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IExerciseUpdateListener {
oneway void onExerciseUpdateListenerEvent(in androidx.health.services.client.impl.event.ExerciseUpdateListenerEvent event) = 0;
}
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IHealthServicesApiService.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IHealthServicesApiService.aidl
index 3d44c7d..d914e6d 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IHealthServicesApiService.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IHealthServicesApiService.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IHealthServicesApiService {
int getApiVersion() = 0;
const int API_VERSION = 1;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IMeasureApiService.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IMeasureApiService.aidl
index f1bcc3a..db43d52 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IMeasureApiService.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IMeasureApiService.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IMeasureApiService {
int getApiVersion() = 0;
void registerCallback(in androidx.health.services.client.impl.request.MeasureRegistrationRequest request, in androidx.health.services.client.impl.IMeasureCallback callback, in androidx.health.services.client.impl.internal.IStatusCallback statusCallback) = 1;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IMeasureCallback.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IMeasureCallback.aidl
index d962152..55c5a88 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IMeasureCallback.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IMeasureCallback.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IMeasureCallback {
oneway void onMeasureCallbackEvent(in androidx.health.services.client.impl.event.MeasureCallbackEvent event) = 0;
}
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveListenerCallback.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveListenerCallback.aidl
index 7e151cf..5545a2b 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveListenerCallback.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveListenerCallback.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IPassiveListenerCallback {
oneway void onPassiveListenerEvent(in androidx.health.services.client.impl.event.PassiveListenerEvent event) = 0;
}
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveListenerService.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveListenerService.aidl
index e6ce850..74fdaa6 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveListenerService.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveListenerService.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IPassiveListenerService {
int getApiVersion() = 0;
void onPassiveListenerEvent(in androidx.health.services.client.impl.event.PassiveListenerEvent event) = 1;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl
index 8c61dd6..3a751d6 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IPassiveMonitoringApiService {
int getApiVersion() = 0;
androidx.health.services.client.impl.response.PassiveMonitoringCapabilitiesResponse getCapabilities(in androidx.health.services.client.impl.request.CapabilitiesRequest request) = 5;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl
index 4b3d8b3..64839c0 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IPassiveMonitoringCallback {
oneway void onPassiveCallbackEvent(in androidx.health.services.client.impl.event.PassiveCallbackEvent event) = 0;
}
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IVersionApiService.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IVersionApiService.aidl
index f5734c5..7974cf5 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IVersionApiService.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/IVersionApiService.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IVersionApiService {
int getVersionApiServiceVersion() = 0;
int getSdkVersion() = 1;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/ExerciseUpdateListenerEvent.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/ExerciseUpdateListenerEvent.aidl
index 852949d..d7a0bf9 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/ExerciseUpdateListenerEvent.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/ExerciseUpdateListenerEvent.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.event;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable ExerciseUpdateListenerEvent;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/MeasureCallbackEvent.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/MeasureCallbackEvent.aidl
index c3db654..75688c2 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/MeasureCallbackEvent.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/MeasureCallbackEvent.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.event;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable MeasureCallbackEvent;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/PassiveCallbackEvent.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/PassiveCallbackEvent.aidl
index 2b5a944..bff4838 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/PassiveCallbackEvent.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/PassiveCallbackEvent.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.event;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable PassiveCallbackEvent;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/PassiveListenerEvent.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/PassiveListenerEvent.aidl
index 3fa39e0..acf3c16 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/PassiveListenerEvent.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/event/PassiveListenerEvent.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.event;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable PassiveListenerEvent;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl
index 88882b3..1ae1792 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.internal;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IExerciseInfoCallback {
oneway void onExerciseInfo(in androidx.health.services.client.impl.response.ExerciseInfoResponse response) = 0;
oneway void onFailure(String message) = 1;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/internal/IStatusCallback.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/internal/IStatusCallback.aidl
index 15876b4..b90907f 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/internal/IStatusCallback.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/internal/IStatusCallback.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.internal;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IStatusCallback {
oneway void onSuccess() = 0;
oneway void onFailure(String msg) = 1;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.aidl
index 51d65c8..f356897 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable AutoPauseAndResumeConfigRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/BatchingModeConfigRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/BatchingModeConfigRequest.aidl
index ab6507f..81b503d 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/BatchingModeConfigRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/BatchingModeConfigRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable BatchingModeConfigRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/CapabilitiesRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/CapabilitiesRequest.aidl
index d75b270..f5e853e 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/CapabilitiesRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/CapabilitiesRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable CapabilitiesRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/ExerciseGoalRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/ExerciseGoalRequest.aidl
index e5dfc7f..c2c2601 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/ExerciseGoalRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/ExerciseGoalRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable ExerciseGoalRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/FlushRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/FlushRequest.aidl
index ab90c6b..78e7737 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/FlushRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/FlushRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable FlushRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/MeasureRegistrationRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/MeasureRegistrationRequest.aidl
index 42df873..c0261a3 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/MeasureRegistrationRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/MeasureRegistrationRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable MeasureRegistrationRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.aidl
index 0ceb393..bcf254b 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable MeasureUnregistrationRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PassiveListenerCallbackRegistrationRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PassiveListenerCallbackRegistrationRequest.aidl
index 07e2fd2..fa7d167 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PassiveListenerCallbackRegistrationRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PassiveListenerCallbackRegistrationRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable PassiveListenerCallbackRegistrationRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PassiveListenerServiceRegistrationRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PassiveListenerServiceRegistrationRequest.aidl
index 5fb29e5..0b724c1 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PassiveListenerServiceRegistrationRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PassiveListenerServiceRegistrationRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable PassiveListenerServiceRegistrationRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PrepareExerciseRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PrepareExerciseRequest.aidl
index 06c842c..d321013 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PrepareExerciseRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/PrepareExerciseRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable PrepareExerciseRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/StartExerciseRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/StartExerciseRequest.aidl
index bd6a3e4..b3fc86c 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/StartExerciseRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/StartExerciseRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable StartExerciseRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/UpdateExerciseTypeConfigRequest.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/UpdateExerciseTypeConfigRequest.aidl
index 60757b9..533c643 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/UpdateExerciseTypeConfigRequest.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/request/UpdateExerciseTypeConfigRequest.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.request;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable UpdateExerciseTypeConfigRequest;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/AvailabilityResponse.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/AvailabilityResponse.aidl
index 39febd5..f5d1732 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/AvailabilityResponse.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/AvailabilityResponse.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.response;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable AvailabilityResponse;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/DataPointsResponse.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/DataPointsResponse.aidl
index e0725c3..309fe38 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/DataPointsResponse.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/DataPointsResponse.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.response;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable DataPointsResponse;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseCapabilitiesResponse.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseCapabilitiesResponse.aidl
index 26ca2f2..00b2435 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseCapabilitiesResponse.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseCapabilitiesResponse.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.response;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable ExerciseCapabilitiesResponse;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseInfoResponse.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseInfoResponse.aidl
index 0d8ec81..ced8867 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseInfoResponse.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseInfoResponse.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.response;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable ExerciseInfoResponse;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.aidl
index 9805bcb..906783f 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.response;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable ExerciseLapSummaryResponse;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseUpdateResponse.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseUpdateResponse.aidl
index b882166..d2df1a9 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseUpdateResponse.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/ExerciseUpdateResponse.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.response;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable ExerciseUpdateResponse;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.aidl
index 6756fe2..0f2b7db 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.response;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable MeasureCapabilitiesResponse;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.aidl
index 3050d82..e6de1805 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.response;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable PassiveMonitoringCapabilitiesResponse;
diff --git a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/PassiveMonitoringUpdateResponse.aidl b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/PassiveMonitoringUpdateResponse.aidl
index 07ba228..60ab02f 100644
--- a/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/PassiveMonitoringUpdateResponse.aidl
+++ b/health/health-services-client/api/aidlRelease/current/androidx/health/services/client/impl/response/PassiveMonitoringUpdateResponse.aidl
@@ -32,6 +32,5 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.health.services.client.impl.response;
-/* @hide */
-@JavaOnlyStableParcelable
+@JavaOnlyStableParcelable @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
parcelable PassiveMonitoringUpdateResponse;
diff --git a/health/health-services-client/lint-baseline.xml b/health/health-services-client/lint-baseline.xml
index 2ecb3d1..c9edad9 100644
--- a/health/health-services-client/lint-baseline.xml
+++ b/health/health-services-client/lint-baseline.xml
@@ -1,122 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class ApiVersionException extends ExecutionException {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/ApiVersionException.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class BaseQueueOperation implements QueueOperation {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public abstract class Client<S extends IInterface> {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class ClientConfiguration {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public final class ConnectionConfiguration {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public final class ConnectionManager implements Handler.Callback, ServiceConnection.Callback {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class DefaultExecutionTracker implements ExecutionTracker {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/internal/DefaultExecutionTracker.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface ExecutionTracker {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/internal/ExecutionTracker.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public final class ListenerKey {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/internal/ListenerKey.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface QueueOperation {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface RemoteFutureOperation<S, R> {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/RemoteFutureOperation.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface RemoteOperation<S, R> {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/RemoteOperation.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class ServiceConnection implements android.content.ServiceConnection {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java"/>
- </issue>
+<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">
<issue
id="BanParcelableUsage"
@@ -155,114 +38,6 @@
</issue>
<issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="interface IExerciseApiService {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/IExerciseApiService.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="oneway interface IExerciseInfoCallback {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="oneway interface IExerciseUpdateListener {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/IExerciseUpdateListener.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="interface IHealthServicesApiService {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/IHealthServicesApiService.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="interface IMeasureApiService {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/IMeasureApiService.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="oneway interface IMeasureCallback {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/IMeasureCallback.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="oneway interface IPassiveListenerCallback {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/IPassiveListenerCallback.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="interface IPassiveListenerService {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/IPassiveListenerService.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="interface IPassiveMonitoringApiService {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="oneway interface IPassiveMonitoringCallback {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="oneway interface IStatusCallback {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/internal/IStatusCallback.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="interface IVersionApiService {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/health/services/client/impl/IVersionApiService.aidl"/>
- </issue>
-
- <issue
id="SyntheticAccessor"
message="Access to `private` field `mCurrentVersion` of class `Client` requires synthetic accessor"
errorLine1=" mCurrentVersion ="
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ApiVersionException.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ApiVersionException.java
index 134ffa3..402ad4e 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ApiVersionException.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ApiVersionException.java
@@ -24,7 +24,6 @@
/**
* Exception that is thrown when API version requirements are not met.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public class ApiVersionException extends ExecutionException {
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/Client.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/Client.java
index 232ef3e5..efbadfb 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/Client.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/Client.java
@@ -43,7 +43,6 @@
* interface. For user instruction see: go/wear-dd-wcs-sdk
*
* @param <S> type of the service interface
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public abstract class Client<S extends IInterface> {
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java
index cf824d1..6351d49 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java
@@ -23,7 +23,6 @@
* An interface that provides basic information about the IPC service. This is required for building
* the service in {@link Client}.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public class ClientConfiguration {
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/RemoteFutureOperation.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/RemoteFutureOperation.java
index c3bcb57..dcebc8f 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/RemoteFutureOperation.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/RemoteFutureOperation.java
@@ -29,7 +29,6 @@
*
* @param <S> type of the remote service
* @param <R> type of the result value
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public interface RemoteFutureOperation<S, R> {
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/RemoteOperation.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/RemoteOperation.java
index 4fefd8a..af31b5f 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/RemoteOperation.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/RemoteOperation.java
@@ -26,7 +26,6 @@
*
* @param <S> type of the remote service
* @param <R> type of the returned value
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public interface RemoteOperation<S, R> {
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java
index 079d509..e66eea2 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java
@@ -28,7 +28,6 @@
* Abstract implementation of QueueOperation that accepts {@link ConnectionConfiguration} describing
* the service where it will be executed.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public class BaseQueueOperation implements QueueOperation {
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java
index 59965b3..359957d34 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java
@@ -24,7 +24,6 @@
/**
* Internal representation of configuration of IPC service connection.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public final class ConnectionConfiguration {
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java
index 739a531..7958a0a 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java
@@ -31,7 +31,6 @@
/**
* Manages connections to a service in a different process.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public final class ConnectionManager implements Handler.Callback, ServiceConnection.Callback {
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/DefaultExecutionTracker.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/DefaultExecutionTracker.java
index 99b0441..ca2066b 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/DefaultExecutionTracker.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/DefaultExecutionTracker.java
@@ -29,7 +29,6 @@
/**
* Default implementation of {@link ExecutionTracker}.
*
- * @hide
*/
@SuppressWarnings("ExecutorTaskName")
@RestrictTo(Scope.LIBRARY)
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ExecutionTracker.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ExecutionTracker.java
index eb9e81d..73b6575 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ExecutionTracker.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ExecutionTracker.java
@@ -24,7 +24,6 @@
/**
* Tracker for tracking operations that are currently in progress.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public interface ExecutionTracker {
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ListenerKey.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ListenerKey.java
index f2960e3..c750fe9 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ListenerKey.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ListenerKey.java
@@ -23,7 +23,6 @@
/**
* Unique key to hold listener reference.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public final class ListenerKey {
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java
index 6021bdf..c642be1 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java
@@ -26,7 +26,6 @@
* A wrapper for SDK operation that will be executed on a connected binder. It is intended for
* scheduling in execution queue.
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public interface QueueOperation {
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java
index 880b852..e69936c 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java
@@ -47,7 +47,6 @@
*
* <p>Note: this class is not thread safe and should be called always from the same thread.
*
- * @hide
*/
@NotThreadSafe
@RestrictTo(Scope.LIBRARY)
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/proto/package-info.java b/health/health-services-client/src/main/java/androidx/health/services/client/proto/package-info.java
index a8ec8f6..6d0b839 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/proto/package-info.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/proto/package-info.java
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-/** @hide */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RestrictTo(RestrictTo.Scope.LIBRARY)
package androidx.health.services.client.proto;
import androidx.annotation.RestrictTo;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IExerciseApiService.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IExerciseApiService.aidl
index b52a78c..5c35b76 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IExerciseApiService.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IExerciseApiService.aidl
@@ -35,8 +35,8 @@
* The next method added to the interface should use ID: 18
* (this id needs to be incremented for each added method)
*
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IExerciseApiService {
/**
* API version of the AIDL interface. Should be incremented every time a new
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IExerciseUpdateListener.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IExerciseUpdateListener.aidl
index eaa41b4..c1097e9 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IExerciseUpdateListener.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IExerciseUpdateListener.aidl
@@ -24,8 +24,8 @@
/**
* Interface to get exercise updates.
*
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
oneway interface IExerciseUpdateListener {
/** Called when there is an exercise update event. */
void onExerciseUpdateListenerEvent(in ExerciseUpdateListenerEvent event) = 0;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IHealthServicesApiService.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IHealthServicesApiService.aidl
index 7ba7cf4..1cb6afb 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IHealthServicesApiService.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IHealthServicesApiService.aidl
@@ -19,8 +19,8 @@
/**
* Interface to make ipc calls for health services api.
*
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IHealthServicesApiService {
/**
* API version of the AIDL interface. Should be incremented every time a new
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IMeasureApiService.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IMeasureApiService.aidl
index 4e805ad..edc8fc2 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IMeasureApiService.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IMeasureApiService.aidl
@@ -26,8 +26,8 @@
/**
* Interface to make ipc calls for health services api.
*
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IMeasureApiService {
/**
* API version of the AIDL interface. Should be incremented every time a new
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IMeasureCallback.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IMeasureCallback.aidl
index fd2fc2c..687b075 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IMeasureCallback.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IMeasureCallback.aidl
@@ -20,9 +20,8 @@
/**
* Interface to get callback for measure api.
- *
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
oneway interface IMeasureCallback {
void onMeasureCallbackEvent(in MeasureCallbackEvent event) = 0;
}
\ No newline at end of file
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveListenerCallback.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveListenerCallback.aidl
index 1d2c503..c3a87f4 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveListenerCallback.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveListenerCallback.aidl
@@ -21,8 +21,8 @@
/**
* Interface to get passive monitoring updates.
*
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
oneway interface IPassiveListenerCallback {
void onPassiveListenerEvent(in PassiveListenerEvent event) = 0;
}
\ No newline at end of file
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveListenerService.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveListenerService.aidl
index e50fb7d..e22bdd01 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveListenerService.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveListenerService.aidl
@@ -18,9 +18,7 @@
import androidx.health.services.client.impl.event.PassiveListenerEvent;
-/**
- * @hide
- */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IPassiveListenerService {
/**
* API version of the AIDL interface. Should be incremented every time a new
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl
index 5354b73..0320c5b 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl
@@ -24,7 +24,7 @@
import androidx.health.services.client.impl.request.PassiveListenerServiceRegistrationRequest;
import androidx.health.services.client.impl.response.PassiveMonitoringCapabilitiesResponse;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IPassiveMonitoringApiService {
/**
* API version of the AIDL interface. Should be incremented every time a new
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl
index 0d7163b..9ed7d88 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl
@@ -21,8 +21,8 @@
/**
* Interface to get passive monitoring updates.
*
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
oneway interface IPassiveMonitoringCallback {
void onPassiveCallbackEvent(in PassiveCallbackEvent event) = 0;
}
\ No newline at end of file
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IVersionApiService.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IVersionApiService.aidl
index c296db8..19f7389 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IVersionApiService.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/IVersionApiService.aidl
@@ -25,9 +25,8 @@
/**
* Interface to make ipc calls to query version information.
- *
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IVersionApiService {
/**
* API version of _this_ AIDL interface. Should be incremented every time a
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/ExerciseUpdateListenerEvent.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/ExerciseUpdateListenerEvent.aidl
index 86040a6..a3bf86b 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/ExerciseUpdateListenerEvent.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/ExerciseUpdateListenerEvent.aidl
@@ -16,6 +16,6 @@
package androidx.health.services.client.impl.event;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable ExerciseUpdateListenerEvent;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/MeasureCallbackEvent.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/MeasureCallbackEvent.aidl
index 14534fa..2d236e5 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/MeasureCallbackEvent.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/MeasureCallbackEvent.aidl
@@ -16,6 +16,6 @@
package androidx.health.services.client.impl.event;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable MeasureCallbackEvent;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/PassiveCallbackEvent.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/PassiveCallbackEvent.aidl
index d5f7328..3336890 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/PassiveCallbackEvent.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/PassiveCallbackEvent.aidl
@@ -16,6 +16,6 @@
package androidx.health.services.client.impl.event;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable PassiveCallbackEvent;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/PassiveListenerEvent.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/PassiveListenerEvent.aidl
index 90e0aec..e6a2783 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/PassiveListenerEvent.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/event/PassiveListenerEvent.aidl
@@ -16,6 +16,6 @@
package androidx.health.services.client.impl.event;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable PassiveListenerEvent;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl
index cfc56ca..dbcb95b 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl
@@ -22,8 +22,8 @@
* Callback for an operation that returns an ExerciseInfo on successful
* completion.
*
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
oneway interface IExerciseInfoCallback {
/**
* Method invoked when the operation is a success and exercise info is
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/internal/IStatusCallback.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/internal/IStatusCallback.aidl
index 2a58b96..7faaf26 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/internal/IStatusCallback.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/internal/IStatusCallback.aidl
@@ -19,8 +19,8 @@
/**
* Generic callback for an operation that returns a status on completion.
*
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
oneway interface IStatusCallback {
/**
* Method invoked when the operation is a success.
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.aidl
index 9baff46..7b77467 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable AutoPauseAndResumeConfigRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/BatchingModeConfigRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/BatchingModeConfigRequest.aidl
index 550320b..9c590f5 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/BatchingModeConfigRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/BatchingModeConfigRequest.aidl
@@ -16,6 +16,6 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable BatchingModeConfigRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/CapabilitiesRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/CapabilitiesRequest.aidl
index 3c8a0ad..60908bc 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/CapabilitiesRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/CapabilitiesRequest.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable CapabilitiesRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/ExerciseGoalRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/ExerciseGoalRequest.aidl
index 07fbbea..7233e8a 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/ExerciseGoalRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/ExerciseGoalRequest.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable ExerciseGoalRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/FlushRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/FlushRequest.aidl
index ca3216e..78f0d56 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/FlushRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/FlushRequest.aidl
@@ -16,6 +16,6 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable FlushRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/MeasureRegistrationRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/MeasureRegistrationRequest.aidl
index 534abff..0835252 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/MeasureRegistrationRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/MeasureRegistrationRequest.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable MeasureRegistrationRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.aidl
index 30161c4..bf97197 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable MeasureUnregistrationRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PassiveListenerCallbackRegistrationRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PassiveListenerCallbackRegistrationRequest.aidl
index 688960c..05eefc1 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PassiveListenerCallbackRegistrationRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PassiveListenerCallbackRegistrationRequest.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable PassiveListenerCallbackRegistrationRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PassiveListenerServiceRegistrationRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PassiveListenerServiceRegistrationRequest.aidl
index 5f9dbf7..47caa61 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PassiveListenerServiceRegistrationRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PassiveListenerServiceRegistrationRequest.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable PassiveListenerServiceRegistrationRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PrepareExerciseRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PrepareExerciseRequest.aidl
index c8ee450..15a3b9d 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PrepareExerciseRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/PrepareExerciseRequest.aidl
@@ -16,6 +16,6 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable PrepareExerciseRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/StartExerciseRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/StartExerciseRequest.aidl
index 5fc6a17..93019ef 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/StartExerciseRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/StartExerciseRequest.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable StartExerciseRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/UpdateExerciseTypeConfigRequest.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/UpdateExerciseTypeConfigRequest.aidl
index 27c16bd..506ea17 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/UpdateExerciseTypeConfigRequest.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/request/UpdateExerciseTypeConfigRequest.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.request;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable UpdateExerciseTypeConfigRequest;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/AvailabilityResponse.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/AvailabilityResponse.aidl
index c53ddb1..2a0b3b7 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/AvailabilityResponse.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/AvailabilityResponse.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.response;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable AvailabilityResponse;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/DataPointsResponse.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/DataPointsResponse.aidl
index 4de02f3..705f3bd 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/DataPointsResponse.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/DataPointsResponse.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.response;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable DataPointsResponse;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseCapabilitiesResponse.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseCapabilitiesResponse.aidl
index f74cd6a..9712cde 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseCapabilitiesResponse.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseCapabilitiesResponse.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.response;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable ExerciseCapabilitiesResponse;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseInfoResponse.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseInfoResponse.aidl
index eb4c41e..68a7a8e 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseInfoResponse.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseInfoResponse.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.response;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable ExerciseInfoResponse;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.aidl
index 6a0a380..718fb39 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.response;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable ExerciseLapSummaryResponse;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseUpdateResponse.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseUpdateResponse.aidl
index 335c904..13c1faa 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseUpdateResponse.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/ExerciseUpdateResponse.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.response;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable ExerciseUpdateResponse;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.aidl
index 7974ce3..24783cd 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.response;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable MeasureCapabilitiesResponse;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.aidl
index cdfcf9d..4b3d81f 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.response;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable PassiveMonitoringCapabilitiesResponse;
diff --git a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/PassiveMonitoringUpdateResponse.aidl b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/PassiveMonitoringUpdateResponse.aidl
index 19dc01d0..d801a72 100644
--- a/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/PassiveMonitoringUpdateResponse.aidl
+++ b/health/health-services-client/src/main/stableAidl/androidx/health/services/client/impl/response/PassiveMonitoringUpdateResponse.aidl
@@ -16,5 +16,5 @@
package androidx.health.services.client.impl.response;
-/** @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
@JavaOnlyStableParcelable parcelable PassiveMonitoringUpdateResponse;
diff --git a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/MultiPointerPredictor.java b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/MultiPointerPredictor.java
index 3f02764..f091db8 100644
--- a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/MultiPointerPredictor.java
+++ b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/MultiPointerPredictor.java
@@ -123,9 +123,6 @@
pointerIds[i] = mPredictorMap.keyAt(i);
SinglePointerPredictor predictor = mPredictorMap.valueAt(i);
singlePointerEvents[i] = predictor.predict(predictionTargetMs);
- // If predictor consumer expect more sample, generate sample where position and
- // pressure are constant
- singlePointerEvents[i] = predictor.appendPredictedEvent(singlePointerEvents[i]);
}
// Compute minimal history size for every predicted single pointer MotionEvent
diff --git a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/SinglePointerPredictor.java b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/SinglePointerPredictor.java
index 74dfc7c..093ecd9 100644
--- a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/SinglePointerPredictor.java
+++ b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/SinglePointerPredictor.java
@@ -67,6 +67,7 @@
private final DVector2 mLastPosition = new DVector2();
private long mPrevEventTime;
+ private long mDownEventTime;
private List<Float> mReportRates = new LinkedList<>();
private int mExpectedPredictionSampleSize = -1;
private float mReportRateMs = 0;
@@ -97,11 +98,13 @@
public SinglePointerPredictor() {
mKalman.reset();
mPrevEventTime = 0;
+ mDownEventTime = 0;
}
void initStrokePrediction(int pointerId, int toolType) {
mKalman.reset();
mPrevEventTime = 0;
+ mDownEventTime = 0;
mPointerId = pointerId;
mToolType = toolType;
}
@@ -173,6 +176,9 @@
event));
return false;
}
+
+ mDownEventTime = event.getDownTime();
+
for (BatchedMotionEvent ev : BatchedMotionEvent.iterate(event)) {
MotionEvent.PointerCoords pointerCoords = ev.coords[pointerIndex];
update(pointerCoords.x, pointerCoords.y, pointerCoords.pressure,
@@ -226,6 +232,7 @@
predictionTargetInSamples = mExpectedPredictionSampleSize;
}
+ long nextPredictedEventTime = mPrevEventTime + Math.round(mReportRateMs);
int i = 0;
for (; i < predictionTargetInSamples; i++) {
mAcceleration.a1 += mJank.a1 * JANK_INFLUENCE;
@@ -252,8 +259,8 @@
if (predictedEvent == null) {
predictedEvent =
MotionEvent.obtain(
- 0 /* downTime */,
- 0 /* eventTime */,
+ mDownEventTime /* downTime */,
+ nextPredictedEventTime /* eventTime */,
MotionEvent.ACTION_MOVE /* action */,
1 /* pointerCount */,
pointerProperties /* pointer properties */,
@@ -267,8 +274,9 @@
0 /* source */,
0 /* flags */);
} else {
- predictedEvent.addBatch(0, coords, 0);
+ predictedEvent.addBatch(nextPredictedEventTime, coords, 0);
}
+ nextPredictedEventTime += Math.round(mReportRateMs);
}
return predictedEvent;
diff --git a/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/InspectionPlugin.kt b/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/InspectionPlugin.kt
index 48c5da5..973a7db 100644
--- a/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/InspectionPlugin.kt
+++ b/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/InspectionPlugin.kt
@@ -63,7 +63,7 @@
// to allow including these dependencies in an SBOM
it.description = "Re-publishes dependencies of the inspector"
it.isCanBeConsumed = true
- it.isCanBeResolved = false
+ it.isCanBeResolved = true
it.extendsFrom(project.configurations.getByName("implementation"))
it.setupReleaseAttribute()
}
diff --git a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxConsoleCallback.aidl b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxConsoleCallback.aidl
index 96b70225..cc3f521 100644
--- a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxConsoleCallback.aidl
+++ b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxConsoleCallback.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package org.chromium.android_webview.js_sandbox.common;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IJsSandboxConsoleCallback {
void consoleMessage(int contextGroupId, int level, String message, String source, int line, int column, String trace) = 0;
void consoleClear(int contextGroupId) = 1;
diff --git a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolate.aidl b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolate.aidl
index 899c4e4..bfb5ec8 100644
--- a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolate.aidl
+++ b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolate.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package org.chromium.android_webview.js_sandbox.common;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IJsSandboxIsolate {
void evaluateJavascript(String code, in org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolateCallback callback) = 0;
void close() = 1;
diff --git a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl
index 17cfb14..b6a0b77 100644
--- a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl
+++ b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package org.chromium.android_webview.js_sandbox.common;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IJsSandboxIsolateCallback {
oneway void reportResult(String result) = 0;
oneway void reportError(int errorType, String error) = 1;
diff --git a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateSyncCallback.aidl b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateSyncCallback.aidl
index e9fc623..2235d47 100644
--- a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateSyncCallback.aidl
+++ b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateSyncCallback.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package org.chromium.android_webview.js_sandbox.common;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IJsSandboxIsolateSyncCallback {
void reportResultWithFd(in android.content.res.AssetFileDescriptor afd) = 2;
void reportErrorWithFd(int errorType, in android.content.res.AssetFileDescriptor afd) = 3;
diff --git a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
index aa395c0..cd3aae0 100644
--- a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
+++ b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package org.chromium.android_webview.js_sandbox.common;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IJsSandboxService {
org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolate createIsolate() = 0;
List<String> getSupportedFeatures() = 1;
diff --git a/javascriptengine/javascriptengine/lint-baseline.xml b/javascriptengine/javascriptengine/lint-baseline.xml
index c449e3c..34bf9d9 100644
--- a/javascriptengine/javascriptengine/lint-baseline.xml
+++ b/javascriptengine/javascriptengine/lint-baseline.xml
@@ -1,14 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-beta01" type="baseline" client="gradle" dependencies="false" name="AGP (8.1.0-beta01)" variant="all" version="8.1.0-beta01">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @interface Level {}"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/javascriptengine/JavaScriptConsoleCallback.java"/>
- </issue>
+<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">
<issue
id="BanThreadSleep"
diff --git a/javascriptengine/javascriptengine/src/androidTest/java/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java b/javascriptengine/javascriptengine/src/androidTest/java/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java
index 112cbb3..f28f89f 100644
--- a/javascriptengine/javascriptengine/src/androidTest/java/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java
+++ b/javascriptengine/javascriptengine/src/androidTest/java/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java
@@ -35,7 +35,6 @@
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -211,7 +210,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testInfiniteLoop() throws Throwable {
final String code = "while(true){}";
Context context = ApplicationProvider.getApplicationContext();
@@ -240,7 +238,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testMultipleInfiniteLoops() throws Throwable {
final String code = "while(true){}";
final int num_of_evaluations = 10;
@@ -275,7 +272,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testSimpleArrayBuffer() throws Throwable {
final String provideString = "Hello World";
final byte[] bytes = provideString.getBytes(StandardCharsets.US_ASCII);
@@ -307,7 +303,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testArrayBufferWasmCompilation() throws Throwable {
final String success = "success";
// The bytes of a minimal WebAssembly module, courtesy of v8/test/cctest/test-api-wasm.cc
@@ -341,7 +336,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testPromiseReturn() throws Throwable {
final String code = "Promise.resolve(\"PASS\")";
final String expected = "PASS";
@@ -362,7 +356,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testPromiseReturnLaterResolve() throws Throwable {
final String code1 = "var promiseResolve, promiseReject;"
+ "new Promise(function(resolve, reject){"
@@ -390,7 +383,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testNestedConsumeNamedDataAsArrayBuffer() throws Throwable {
final String success = "success";
// The bytes of a minimal WebAssembly module, courtesy of v8/test/cctest/test-api-wasm.cc
@@ -433,7 +425,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testPromiseEvaluationThrow() throws Throwable {
final String code = ""
+ "android.consumeNamedDataAsArrayBuffer(\"id-1\").catch((error) => {"
@@ -553,7 +544,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testHeapSizeAdjustment() throws Throwable {
final String code = "\"PASS\"";
final String expected = "PASS";
@@ -593,7 +583,6 @@
@Test
@LargeTest
- @Ignore("b/268212217")
public void testHeapSizeEnforced() throws Throwable {
// WebView versions < 110.0.5438.0 do not contain OOM crashes to a single isolate and
// instead crash the whole sandbox process. This change is not tracked in a feature flag.
@@ -689,7 +678,6 @@
@Test
@LargeTest
- @Ignore("b/268212217")
public void testIsolateCreationAfterCrash() throws Throwable {
// WebView versions < 110.0.5438.0 do not contain OOM crashes to a single isolate and
// instead crash the whole sandbox process. This change is not tracked in a feature flag.
@@ -769,7 +757,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testAsyncPromiseCallbacks() throws Throwable {
// Unlike testPromiseReturn and testPromiseEvaluationThrow, this test is guaranteed to
// exercise promises in an asynchronous way, rather than in ways which cause a promise to
@@ -838,7 +825,6 @@
@Test
@LargeTest
- @Ignore("b/268212217")
public void testLargeScriptJsEvaluation() throws Throwable {
String longString = Strings.repeat("a", 2000000);
final String code = ""
@@ -863,7 +849,6 @@
@Test
@LargeTest
- @Ignore("b/268212217")
public void testLargeScriptByteArrayJsEvaluation() throws Throwable {
final String longString = Strings.repeat("a", 2000000);
final String codeString = ""
@@ -889,7 +874,6 @@
@Test
@LargeTest
- @Ignore("b/268212217")
public void testLargeReturn() throws Throwable {
final String code = "'a'.repeat(2000000);";
final String expected = Strings.repeat("a", 2000000);
@@ -911,7 +895,6 @@
@Test
@LargeTest
- @Ignore("b/268212217")
public void testLargeError() throws Throwable {
final String longString = Strings.repeat("a", 2000000);
final String code = "throw \"" + longString + "\");";
@@ -937,7 +920,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testResultSizeEnforced() throws Throwable {
final int maxSize = 100;
Context context = ApplicationProvider.getApplicationContext();
@@ -988,7 +970,6 @@
@Test
@LargeTest
- @Ignore("b/268212217")
public void testConsoleLogging() throws Throwable {
final class LoggingJavaScriptConsoleCallback implements JavaScriptConsoleCallback {
private final Object mLock = new Object();
@@ -1141,7 +1122,6 @@
@Test
@MediumTest
- @Ignore("b/268212217")
public void testConsoleCallbackCanCallService() throws Throwable {
// This checks that there is nothing intrinsically wrong with calling service APIs from a
// console client. Note that, in theory, Binder will reuse the same threads if code recurses
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptConsoleCallback.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptConsoleCallback.java
index 0faad5f..6b162c7 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptConsoleCallback.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptConsoleCallback.java
@@ -19,6 +19,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
import org.chromium.android_webview.js_sandbox.common.IJsSandboxConsoleCallback;
@@ -35,8 +36,8 @@
final class ConsoleMessage {
/**
* Console message (error) level
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({LEVEL_LOG, LEVEL_DEBUG, LEVEL_INFO, LEVEL_ERROR, LEVEL_WARNING})
@Retention(RetentionPolicy.SOURCE)
public @interface Level {}
diff --git a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxConsoleCallback.aidl b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxConsoleCallback.aidl
index d18086c..d5c1562 100644
--- a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxConsoleCallback.aidl
+++ b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxConsoleCallback.aidl
@@ -18,8 +18,8 @@
/**
* Used to relay console messages to the embedding app.
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IJsSandboxConsoleCallback {
// These must be individual bits so that they can be trivially filtered using a bitmask.
const int CONSOLE_MESSAGE_LEVEL_LOG = 1 << 0;
diff --git a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolate.aidl b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolate.aidl
index 1905d4f..3588abe 100644
--- a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolate.aidl
+++ b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolate.aidl
@@ -23,8 +23,8 @@
/**
* Used by the embedding app to execute JavaScript in a sandboxed environment.
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IJsSandboxIsolate {
/**
* @param code the JavaScript code
diff --git a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl
index 4b045e1..eb5a3d7 100644
--- a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl
+++ b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl
@@ -20,8 +20,8 @@
* Used to communicate the result of the JavaScript evaluation from the
* sandbox to the embedding app.
* DEPRECATED INTERFACE! Do not add methods or constants into this file.
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
oneway interface IJsSandboxIsolateCallback {
// An exception was thrown during the JS evaluation.
const int JS_EVALUATION_ERROR = 0;
diff --git a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateSyncCallback.aidl b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateSyncCallback.aidl
index 3225a60..9e67eb9 100644
--- a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateSyncCallback.aidl
+++ b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateSyncCallback.aidl
@@ -23,8 +23,8 @@
* sandbox to the embedding app.
* This interface is not marked 'oneway' like IJsSandboxIsolateCallback and should be preferred for
* ordering correctness.
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IJsSandboxIsolateSyncCallback {
// An exception was thrown during the JS evaluation.
const int JS_EVALUATION_ERROR = 0;
diff --git a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
index 2d65770..0453988 100644
--- a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
+++ b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
@@ -19,8 +19,8 @@
/**
* Used by the embedding app to execute JavaScript in a sandboxed environment.
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IJsSandboxService {
IJsSandboxIsolate createIsolate() = 0;
diff --git a/leanback/leanback/src/main/res/values-mk/strings.xml b/leanback/leanback/src/main/res/values-mk/strings.xml
index 2e7f3f8..7479c4c 100644
--- a/leanback/leanback/src/main/res/values-mk/strings.xml
+++ b/leanback/leanback/src/main/res/values-mk/strings.xml
@@ -50,7 +50,7 @@
<string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"Влези во режимот „Слика во слика“"</string>
<string name="lb_playback_time_separator" msgid="1471121602610716654">"/"</string>
<string name="lb_playback_controls_shown" msgid="8690223891515602822">"Контролите на аудиовизуелните датотеки се прикажани"</string>
- <string name="lb_playback_controls_hidden" msgid="5859666950961624736">"Контролите на аудиовизуелните датотеки се сокриени. Притиснете на навигациските копчиња за да се прикажат"</string>
+ <string name="lb_playback_controls_hidden" msgid="5859666950961624736">"Контролите на аудиовизуелните датотеки се скриени. Притиснете на навигациските копчиња за да се прикажат"</string>
<string name="lb_guidedaction_finish_title" msgid="3330958750346333890">"Готово"</string>
<string name="lb_guidedaction_continue_title" msgid="893619591225519922">"Продолжи"</string>
<string name="lb_media_player_error" msgid="3228326776757666747">"Код за грешка на MediaPlayer %1$d дополнително %2$d"</string>
diff --git a/libraryversions.toml b/libraryversions.toml
index 29e2e48..a7a5b9f 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -5,35 +5,36 @@
APPACTIONS_BUILTINTYPES = "1.0.0-alpha01"
APPACTIONS_INTERACTION = "1.0.0-alpha01"
APPCOMPAT = "1.7.0-alpha03"
-APPSEARCH = "1.1.0-alpha03"
+APPSEARCH = "1.1.0-alpha04"
ARCH_CORE = "2.3.0-alpha01"
ASYNCLAYOUTINFLATER = "1.1.0-alpha02"
-AUTOFILL = "1.3.0-alpha01"
-BENCHMARK = "1.2.0-alpha14"
+AUTOFILL = "1.3.0-alpha02"
+BENCHMARK = "1.2.0-alpha15"
BIOMETRIC = "1.2.0-alpha06"
BLUETOOTH = "1.0.0-alpha01"
-BROWSER = "1.6.0-alpha01"
+BROWSER = "1.6.0-alpha02"
BUILDSRC_TESTS = "1.0.0-alpha01"
-CAMERA = "1.3.0-alpha07"
+CAMERA = "1.3.0-alpha08"
CAMERA_PIPE = "1.0.0-alpha01"
CARDVIEW = "1.1.0-alpha01"
CAR_APP = "1.4.0-alpha01"
COLLECTION = "1.3.0-alpha05"
-COMPOSE = "1.5.0-beta01"
+COMPOSE = "1.6.0-alpha01"
COMPOSE_COMPILER = "1.4.7"
-COMPOSE_MATERIAL3 = "1.2.0-alpha02"
+COMPOSE_MATERIAL3 = "1.2.0-alpha03"
COMPOSE_MATERIAL3_ADAPTIVE = "1.0.0-alpha01"
COMPOSE_RUNTIME_TRACING = "1.0.0-alpha03"
-CONSTRAINTLAYOUT = "2.2.0-alpha10"
-CONSTRAINTLAYOUT_COMPOSE = "1.1.0-alpha10"
-CONSTRAINTLAYOUT_CORE = "1.1.0-alpha10"
+CONSTRAINTLAYOUT = "2.2.0-alpha11"
+CONSTRAINTLAYOUT_COMPOSE = "1.1.0-alpha11"
+CONSTRAINTLAYOUT_CORE = "1.1.0-alpha11"
CONTENTPAGER = "1.1.0-alpha01"
COORDINATORLAYOUT = "1.3.0-alpha01"
-CORE = "1.11.0-beta01"
+CORE = "1.11.0-beta02"
CORE_ANIMATION = "1.0.0-beta02"
CORE_ANIMATION_TESTING = "1.0.0-beta01"
CORE_APPDIGEST = "1.0.0-alpha01"
CORE_GOOGLE_SHORTCUTS = "1.2.0-alpha01"
+CORE_HAPTICS = "1.0.0-alpha01"
CORE_I18N = "1.0.0-alpha01"
CORE_LOCATION_ALTITUDE = "1.0.0-alpha01"
CORE_PERFORMANCE = "1.0.0-alpha03"
@@ -52,7 +53,7 @@
DYNAMICANIMATION = "1.1.0-alpha04"
DYNAMICANIMATION_KTX = "1.0.0-alpha04"
EMOJI = "1.2.0-alpha03"
-EMOJI2 = "1.4.0-beta04"
+EMOJI2 = "1.4.0-beta05"
ENTERPRISE = "1.1.0-rc01"
EXIFINTERFACE = "1.4.0-alpha01"
FRAGMENT = "1.7.0-alpha01"
@@ -64,7 +65,7 @@
GRAPHICS_CORE = "1.0.0-alpha04"
GRAPHICS_FILTERS = "1.0.0-alpha01"
GRAPHICS_SHAPES = "1.0.0-alpha03"
-GRIDLAYOUT = "1.1.0-beta01"
+GRIDLAYOUT = "1.1.0-beta02"
HEALTH_CONNECT = "1.0.0-alpha11"
HEALTH_SERVICES_CLIENT = "1.0.0-beta04"
HEIFWRITER = "1.1.0-alpha02"
@@ -88,9 +89,8 @@
MEDIA2 = "1.3.0-alpha01"
MEDIAROUTER = "1.5.0-alpha01"
METRICS = "1.0.0-alpha05"
-NAVIGATION = "2.7.0-alpha01"
-PAGING = "3.2.0-alpha06"
-PAGING_COMPOSE = "1.0.0-alpha20"
+NAVIGATION = "2.7.0-beta01"
+PAGING = "3.2.0-beta01"
PALETTE = "1.1.0-alpha01"
PERCENTLAYOUT = "1.1.0-alpha01"
PREFERENCE = "1.3.0-alpha01"
@@ -98,8 +98,8 @@
PRIVACYSANDBOX_ADS = "1.0.0-beta05"
PRIVACYSANDBOX_PLUGINS = "1.0.0-alpha02"
PRIVACYSANDBOX_SDKRUNTIME = "1.0.0-alpha05"
-PRIVACYSANDBOX_TOOLS = "1.0.0-alpha04"
-PRIVACYSANDBOX_UI = "1.0.0-alpha03"
+PRIVACYSANDBOX_TOOLS = "1.0.0-alpha05"
+PRIVACYSANDBOX_UI = "1.0.0-alpha04"
PROFILEINSTALLER = "1.4.0-alpha01"
RECOMMENDATION = "1.1.0-alpha01"
RECYCLERVIEW = "1.4.0-alpha01"
@@ -128,7 +128,7 @@
TESTSCREENSHOT = "1.0.0-alpha01"
TEST_UIAUTOMATOR = "2.3.0-alpha04"
TEXT = "1.0.0-alpha01"
-TRACING = "1.2.0-beta04"
+TRACING = "1.3.0-alpha01"
TRACING_PERFETTO = "1.0.0-alpha15"
TRANSITION = "1.5.0-alpha01"
TV = "1.0.0-alpha07"
@@ -138,20 +138,20 @@
VECTORDRAWABLE_SEEKABLE = "1.0.0-beta02"
VERSIONED_PARCELABLE = "1.2.0-alpha01"
VIEWPAGER = "1.1.0-alpha02"
-VIEWPAGER2 = "1.2.0-alpha01"
-WEAR = "1.3.0-alpha06"
-WEAR_COMPOSE = "1.2.0-beta01"
+VIEWPAGER2 = "1.1.0-beta03"
+WEAR = "1.3.0-beta01"
+WEAR_COMPOSE = "1.3.0-alpha01"
WEAR_COMPOSE_MATERIAL3 = "1.0.0-alpha05"
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-alpha10"
+WEAR_PROTOLAYOUT = "1.0.0-alpha11"
WEAR_REMOTE_INTERACTIONS = "1.1.0-alpha01"
-WEAR_TILES = "1.2.0-alpha06"
+WEAR_TILES = "1.2.0-alpha07"
WEAR_WATCHFACE = "1.2.0-alpha09"
WEBKIT = "1.8.0-alpha01"
-WINDOW = "1.2.0-alpha01"
+WINDOW = "1.2.0-alpha02"
WINDOW_EXTENSIONS = "1.2.0-alpha01"
WINDOW_EXTENSIONS_CORE = "1.1.0-alpha01"
WINDOW_SIDECAR = "1.0.0-rc01"
@@ -191,6 +191,7 @@
CONTENTPAGER = { group = "androidx.contentpager", atomicGroupVersion = "versions.CONTENTPAGER" }
COORDINATORLAYOUT = { group = "androidx.coordinatorlayout", atomicGroupVersion = "versions.COORDINATORLAYOUT" }
CORE = { group = "androidx.core" }
+CORE_HAPTICS = { group = "androidx.core.haptics", atomicGroupVersion = "versions.CORE_HAPTICS" }
CORE_UWB = { group = "androidx.core.uwb", atomicGroupVersion = "versions.CORE_UWB" }
CREDENTIALS = { group = "androidx.credentials", atomicGroupVersion = "versions.CREDENTIALS" }
CURSORADAPTER = { group = "androidx.cursoradapter", atomicGroupVersion = "versions.CURSORADAPTER" }
diff --git a/lifecycle/lifecycle-common/api/restricted_current.txt b/lifecycle/lifecycle-common/api/restricted_current.txt
index 0f03c8d..be2c2c0 100644
--- a/lifecycle/lifecycle-common/api/restricted_current.txt
+++ b/lifecycle/lifecycle-common/api/restricted_current.txt
@@ -94,6 +94,7 @@
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class Lifecycling {
method public static String getAdapterName(String className);
method public static androidx.lifecycle.LifecycleEventObserver lifecycleEventObserver(Object object);
+ field public static final androidx.lifecycle.Lifecycling INSTANCE;
}
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class MethodCallsLogger {
diff --git a/lifecycle/lifecycle-common/lint-baseline.xml b/lifecycle/lifecycle-common/lint-baseline.xml
deleted file mode 100644
index f182855..0000000
--- a/lifecycle/lifecycle-common/lint-baseline.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface GeneratedAdapter {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/lifecycle/GeneratedAdapter.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface GenericLifecycleObserver extends LifecycleEventObserver {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/lifecycle/GenericLifecycleObserver.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public var internalScopeRef: AtomicReference<Any> = AtomicReference<Any>()"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/lifecycle/Lifecycle.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public object Lifecycling {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/lifecycle/Lifecycling.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public open class MethodCallsLogger() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/lifecycle/MethodCallsLogger.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public open fun approveCall(name: String, type: Int): Boolean {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/lifecycle/MethodCallsLogger.kt"/>
- </issue>
-
-</issues>
diff --git a/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/GeneratedAdapter.kt b/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/GeneratedAdapter.kt
index ce776e5..e384aae 100644
--- a/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/GeneratedAdapter.kt
+++ b/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/GeneratedAdapter.kt
@@ -17,9 +17,6 @@
import androidx.annotation.RestrictTo
-/**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public interface GeneratedAdapter {
/**
diff --git a/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/GenericLifecycleObserver.java b/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/GenericLifecycleObserver.java
index 1c0c70a..9a7acb4 100644
--- a/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/GenericLifecycleObserver.java
+++ b/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/GenericLifecycleObserver.java
@@ -20,7 +20,6 @@
/**
* Class that can receive any lifecycle change and dispatch it to the receiver.
- * @hide
*
* @deprecated and it is scheduled to be removed in lifecycle 3.0
*/
diff --git a/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/Lifecycle.kt b/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/Lifecycle.kt
index f69c624..bbf1313 100644
--- a/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/Lifecycle.kt
+++ b/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/Lifecycle.kt
@@ -56,9 +56,11 @@
/**
* Lifecycle coroutines extensions stashes the CoroutineScope into this field.
*
- * @hide used by lifecycle-common-ktx
+ * RestrictTo as it is used by lifecycle-common-ktx
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @set:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public var internalScopeRef: AtomicReference<Any> = AtomicReference<Any>()
/**
diff --git a/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/Lifecycling.kt b/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/Lifecycling.kt
index f3a1b9f..64ce3be 100644
--- a/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/Lifecycling.kt
+++ b/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/Lifecycling.kt
@@ -21,8 +21,6 @@
/**
* Internal class to handle lifecycle conversion etc.
- *
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public object Lifecycling {
diff --git a/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/MethodCallsLogger.kt b/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/MethodCallsLogger.kt
index c14c15e..4e8b9d3 100644
--- a/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/MethodCallsLogger.kt
+++ b/lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/MethodCallsLogger.kt
@@ -17,16 +17,10 @@
import androidx.annotation.RestrictTo
-/**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public open class MethodCallsLogger() {
+public open class MethodCallsLogger {
private val calledMethods: MutableMap<String, Int> = HashMap()
- /**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public open fun approveCall(name: String, type: Int): Boolean {
val nullableMask = calledMethods[name]
diff --git a/lifecycle/lifecycle-runtime/lint-baseline.xml b/lifecycle/lifecycle-runtime/lint-baseline.xml
deleted file mode 100644
index c346106..0000000
--- a/lifecycle/lifecycle-runtime/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="open class ReportFragment() : android.app.Fragment() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/lifecycle/ReportFragment.kt"/>
- </issue>
-
-</issues>
diff --git a/lifecycle/lifecycle-runtime/src/main/java/androidx/lifecycle/ReportFragment.kt b/lifecycle/lifecycle-runtime/src/main/java/androidx/lifecycle/ReportFragment.kt
index a7ae3f40..9873795 100644
--- a/lifecycle/lifecycle-runtime/src/main/java/androidx/lifecycle/ReportFragment.kt
+++ b/lifecycle/lifecycle-runtime/src/main/java/androidx/lifecycle/ReportFragment.kt
@@ -24,8 +24,6 @@
/**
* Internal class that dispatches initialization events.
- *
- * @hide
*/
@Suppress("DEPRECATION")
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/lint-baseline.xml b/lifecycle/lifecycle-viewmodel-savedstate/lint-baseline.xml
deleted file mode 100644
index 5035758..0000000
--- a/lifecycle/lifecycle-viewmodel-savedstate/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override fun onRequery(viewModel: ViewModel) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/lifecycle/AbstractSavedStateViewModelFactory.kt"/>
- </issue>
-
-</issues>
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/AbstractSavedStateViewModelFactory.kt b/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/AbstractSavedStateViewModelFactory.kt
index 3e09793..2e06e75 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/AbstractSavedStateViewModelFactory.kt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/AbstractSavedStateViewModelFactory.kt
@@ -141,9 +141,6 @@
handle: SavedStateHandle
): T
- /**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
override fun onRequery(viewModel: ViewModel) {
// is need only for legacy path
diff --git a/lint-checks/src/main/java/androidx/build/lint/AndroidXIssueRegistry.kt b/lint-checks/src/main/java/androidx/build/lint/AndroidXIssueRegistry.kt
index 9df77d7..7de1624 100644
--- a/lint-checks/src/main/java/androidx/build/lint/AndroidXIssueRegistry.kt
+++ b/lint-checks/src/main/java/androidx/build/lint/AndroidXIssueRegistry.kt
@@ -71,8 +71,7 @@
IgnoreClassLevelDetector.ISSUE,
ExperimentalPropertyAnnotationDetector.ISSUE,
BanRestrictToTestsScope.ISSUE,
- // AIDL check is temporarily disabled due to race conditions (b/280346978).
- // UnstableAidlAnnotationDetector.ISSUE,
+ UnstableAidlAnnotationDetector.ISSUE,
// MissingJvmDefaultWithCompatibilityDetector is intentionally left out of the
// registry, see comments on the class for more details.
BanVisibleForTestingParams.ISSUE,
diff --git a/lint-checks/src/main/java/androidx/build/lint/SampledAnnotationDetector.kt b/lint-checks/src/main/java/androidx/build/lint/SampledAnnotationDetector.kt
index 403cb42..03d83b5 100644
--- a/lint-checks/src/main/java/androidx/build/lint/SampledAnnotationDetector.kt
+++ b/lint-checks/src/main/java/androidx/build/lint/SampledAnnotationDetector.kt
@@ -42,20 +42,15 @@
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.SourceCodeScanner
-import org.jetbrains.kotlin.backend.jvm.ir.psiElement
-import org.jetbrains.kotlin.descriptors.MemberDescriptor
+import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.kdoc.psi.api.KDoc
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtModifierListOwner
-import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
-import org.jetbrains.kotlin.resolve.BindingContext
-import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
import org.jetbrains.uast.UDeclaration
import org.jetbrains.uast.UMethod
-import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
/**
* Detector responsible for enforcing @Sampled annotation usage
@@ -240,34 +235,23 @@
private class KDocSampleLinkHandler(private val context: JavaContext) {
fun visitDeclaration(node: UDeclaration) {
val source = node.sourcePsi
- // TODO: remove workaround when https://youtrack.jetbrains.com/issue/KTIJ-19043 is fixed
- if (source is KtPropertyAccessor) {
- source.property.docComment?.let { handleSampleLink(it) }
- } else {
- node.comments
- .mapNotNull {
- it.sourcePsi as? KDoc
- }
- .forEach {
+ node.comments
+ .mapNotNull {
+ it.sourcePsi as? KDoc
+ }
+ .forEach {
+ handleSampleLink(it)
+ }
+ // Expect declarations are not visible in UAST, but they may have sample links on them.
+ // If we are looking at an actual declaration, also manually find the corresponding
+ // expect declaration for analysis.
+ if ((source as? KtModifierListOwner)?.hasActualModifier() == true) {
+ analyze(source) {
+ val member = (source as? KtDeclaration)?.getSymbol() ?: return
+ val expect = member.getExpectForActual() ?: return
+ (expect.psi as? KtDeclaration)?.docComment?.let {
handleSampleLink(it)
}
- // Expect declarations are not visible in UAST, but they may have sample links on them.
- // If we are looking at an actual declaration, also manually find the corresponding
- // expect declaration for analysis.
- if ((source as? KtModifierListOwner)?.hasActualModifier() == true) {
- val service = node.project.getService(KotlinUastResolveProviderService::class.java)
- val member = service.getBindingContext(source)
- .get(BindingContext.DECLARATION_TO_DESCRIPTOR, source) as? MemberDescriptor
- // Should never be null since `actual` is only applicable to members
- ?: return
- val expected = ExpectedActualResolver.findExpectedForActual(member) ?: return
- // There may be multiple possible candidates, we want to check them all regardless.
- expected.values.toList().flatten().forEach { descriptor ->
- val element = descriptor.psiElement
- (element as? KtDeclaration)?.docComment?.let {
- handleSampleLink(it)
- }
- }
}
}
}
diff --git a/lint-checks/src/main/java/androidx/com/android/tools/idea/lang/aidl/AidlLanguage.java b/lint-checks/src/main/java/androidx/com/android/tools/idea/lang/aidl/AidlLanguage.java
index 0a10e27..3e7d669 100644
--- a/lint-checks/src/main/java/androidx/com/android/tools/idea/lang/aidl/AidlLanguage.java
+++ b/lint-checks/src/main/java/androidx/com/android/tools/idea/lang/aidl/AidlLanguage.java
@@ -22,14 +22,12 @@
* Android IDL Language.
*/
public class AidlLanguage extends Language {
- private static final Object INSTANCE_LOCK = new Object();
-
public static final Language INSTANCE = getOrCreate();
private static Language getOrCreate() {
// The Language class is not thread-safe, so this is a best-effort to avoid a race condition
- // during our own access across multiple lint worker threads.
- synchronized (INSTANCE_LOCK) {
+ // during our own access across multiple lint worker threads and classloaders.
+ synchronized (Language.ANY) {
Language lang = Language.findLanguageByID(ID);
if (lang != null) {
return lang;
diff --git a/navigation/navigation-common-ktx/api/2.7.0-beta01.txt b/navigation/navigation-common-ktx/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-common-ktx/api/2.7.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-common-ktx/api/res-2.7.0-beta01.txt b/navigation/navigation-common-ktx/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-common-ktx/api/res-2.7.0-beta01.txt
diff --git a/navigation/navigation-common-ktx/api/restricted_2.7.0-beta01.txt b/navigation/navigation-common-ktx/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-common-ktx/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-common/api/2.7.0-beta01.txt b/navigation/navigation-common/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..51a77a6
--- /dev/null
+++ b/navigation/navigation-common/api/2.7.0-beta01.txt
@@ -0,0 +1,530 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+ public final class ActionOnlyNavDirections implements androidx.navigation.NavDirections {
+ ctor public ActionOnlyNavDirections(int actionId);
+ method public int component1();
+ method public androidx.navigation.ActionOnlyNavDirections copy(int actionId);
+ method public int getActionId();
+ method public android.os.Bundle getArguments();
+ property public int actionId;
+ property public android.os.Bundle arguments;
+ }
+
+ @androidx.navigation.NavOptionsDsl public final class AnimBuilder {
+ ctor public AnimBuilder();
+ method public int getEnter();
+ method public int getExit();
+ method public int getPopEnter();
+ method public int getPopExit();
+ method public void setEnter(int);
+ method public void setExit(int);
+ method public void setPopEnter(int);
+ method public void setPopExit(int);
+ property public final int enter;
+ property public final int exit;
+ property public final int popEnter;
+ property public final int popExit;
+ }
+
+ public interface FloatingWindow {
+ }
+
+ public final class NamedNavArgument {
+ method public operator String component1();
+ method public operator androidx.navigation.NavArgument component2();
+ method public androidx.navigation.NavArgument getArgument();
+ method public String getName();
+ property public final androidx.navigation.NavArgument argument;
+ property public final String name;
+ }
+
+ public final class NamedNavArgumentKt {
+ method public static androidx.navigation.NamedNavArgument navArgument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavAction {
+ ctor public NavAction(@IdRes int destinationId);
+ ctor public NavAction(@IdRes int destinationId, optional androidx.navigation.NavOptions? navOptions);
+ ctor public NavAction(@IdRes int destinationId, optional androidx.navigation.NavOptions? navOptions, optional android.os.Bundle? defaultArguments);
+ method public android.os.Bundle? getDefaultArguments();
+ method public int getDestinationId();
+ method public androidx.navigation.NavOptions? getNavOptions();
+ method public void setDefaultArguments(android.os.Bundle?);
+ method public void setNavOptions(androidx.navigation.NavOptions?);
+ property public final android.os.Bundle? defaultArguments;
+ property public final int destinationId;
+ property public final androidx.navigation.NavOptions? navOptions;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class NavActionBuilder {
+ ctor public NavActionBuilder();
+ method public java.util.Map<java.lang.String,java.lang.Object> getDefaultArguments();
+ method public int getDestinationId();
+ method public void navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+ method public void setDestinationId(int);
+ property public final java.util.Map<java.lang.String,java.lang.Object> defaultArguments;
+ property public final int destinationId;
+ }
+
+ public interface NavArgs {
+ }
+
+ public final class NavArgsLazy<Args extends androidx.navigation.NavArgs> implements kotlin.Lazy<Args> {
+ ctor public NavArgsLazy(kotlin.reflect.KClass<Args> navArgsClass, kotlin.jvm.functions.Function0<android.os.Bundle> argumentProducer);
+ method public Args getValue();
+ method public boolean isInitialized();
+ property public Args value;
+ }
+
+ public final class NavArgument {
+ method public Object? getDefaultValue();
+ method public androidx.navigation.NavType<java.lang.Object> getType();
+ method public boolean isDefaultValuePresent();
+ method public boolean isNullable();
+ property public final Object? defaultValue;
+ property public final boolean isDefaultValuePresent;
+ property public final boolean isNullable;
+ property public final androidx.navigation.NavType<java.lang.Object> type;
+ }
+
+ public static final class NavArgument.Builder {
+ ctor public NavArgument.Builder();
+ method public androidx.navigation.NavArgument build();
+ method public androidx.navigation.NavArgument.Builder setDefaultValue(Object? defaultValue);
+ method public androidx.navigation.NavArgument.Builder setIsNullable(boolean isNullable);
+ method public <T> androidx.navigation.NavArgument.Builder setType(androidx.navigation.NavType<T> type);
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class NavArgumentBuilder {
+ ctor public NavArgumentBuilder();
+ method public androidx.navigation.NavArgument build();
+ method public Object? getDefaultValue();
+ method public boolean getNullable();
+ method public androidx.navigation.NavType<?> getType();
+ method public void setDefaultValue(Object?);
+ method public void setNullable(boolean);
+ method public void setType(androidx.navigation.NavType<?>);
+ property public final Object? defaultValue;
+ property public final boolean nullable;
+ property public final androidx.navigation.NavType<?> type;
+ }
+
+ public final class NavBackStackEntry implements androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+ method public android.os.Bundle? getArguments();
+ method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+ method public androidx.navigation.NavDestination getDestination();
+ method public String getId();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method public androidx.lifecycle.SavedStateHandle getSavedStateHandle();
+ method public androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+ method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ property public final android.os.Bundle? arguments;
+ property public androidx.lifecycle.viewmodel.CreationExtras defaultViewModelCreationExtras;
+ property public androidx.lifecycle.ViewModelProvider.Factory defaultViewModelProviderFactory;
+ property public final androidx.navigation.NavDestination destination;
+ property public final String id;
+ property public androidx.lifecycle.Lifecycle lifecycle;
+ property public final androidx.lifecycle.SavedStateHandle savedStateHandle;
+ property public androidx.savedstate.SavedStateRegistry savedStateRegistry;
+ property public androidx.lifecycle.ViewModelStore viewModelStore;
+ }
+
+ public final class NavDeepLink {
+ method public String? getAction();
+ method public String? getMimeType();
+ method public String? getUriPattern();
+ property public final String? action;
+ property public final String? mimeType;
+ property public final String? uriPattern;
+ }
+
+ public static final class NavDeepLink.Builder {
+ method public androidx.navigation.NavDeepLink build();
+ method public static androidx.navigation.NavDeepLink.Builder fromAction(String action);
+ method public static androidx.navigation.NavDeepLink.Builder fromMimeType(String mimeType);
+ method public static androidx.navigation.NavDeepLink.Builder fromUriPattern(String uriPattern);
+ method public androidx.navigation.NavDeepLink.Builder setAction(String action);
+ method public androidx.navigation.NavDeepLink.Builder setMimeType(String mimeType);
+ method public androidx.navigation.NavDeepLink.Builder setUriPattern(String uriPattern);
+ }
+
+ @kotlin.DslMarker public @interface NavDeepLinkDsl {
+ }
+
+ @androidx.navigation.NavDeepLinkDsl public final class NavDeepLinkDslBuilder {
+ ctor public NavDeepLinkDslBuilder();
+ method public String? getAction();
+ method public String? getMimeType();
+ method public String? getUriPattern();
+ method public void setAction(String?);
+ method public void setMimeType(String?);
+ method public void setUriPattern(String?);
+ property public final String? action;
+ property public final String? mimeType;
+ property public final String? uriPattern;
+ }
+
+ public final class NavDeepLinkDslBuilderKt {
+ method public static androidx.navigation.NavDeepLink navDeepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
+ }
+
+ public class NavDeepLinkRequest {
+ method public String? getAction();
+ method public String? getMimeType();
+ method public android.net.Uri? getUri();
+ property public String? action;
+ property public String? mimeType;
+ property public android.net.Uri? uri;
+ }
+
+ public static final class NavDeepLinkRequest.Builder {
+ method public androidx.navigation.NavDeepLinkRequest build();
+ method public static androidx.navigation.NavDeepLinkRequest.Builder fromAction(String action);
+ method public static androidx.navigation.NavDeepLinkRequest.Builder fromMimeType(String mimeType);
+ method public static androidx.navigation.NavDeepLinkRequest.Builder fromUri(android.net.Uri uri);
+ method public androidx.navigation.NavDeepLinkRequest.Builder setAction(String action);
+ method public androidx.navigation.NavDeepLinkRequest.Builder setMimeType(String mimeType);
+ method public androidx.navigation.NavDeepLinkRequest.Builder setUri(android.net.Uri uri);
+ field public static final androidx.navigation.NavDeepLinkRequest.Builder.Companion Companion;
+ }
+
+ public static final class NavDeepLinkRequest.Builder.Companion {
+ method public androidx.navigation.NavDeepLinkRequest.Builder fromAction(String action);
+ method public androidx.navigation.NavDeepLinkRequest.Builder fromMimeType(String mimeType);
+ method public androidx.navigation.NavDeepLinkRequest.Builder fromUri(android.net.Uri uri);
+ }
+
+ public class NavDestination {
+ ctor public NavDestination(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+ ctor public NavDestination(String navigatorName);
+ method public final void addArgument(String argumentName, androidx.navigation.NavArgument argument);
+ method public final void addDeepLink(androidx.navigation.NavDeepLink navDeepLink);
+ method public final void addDeepLink(String uriPattern);
+ method public final String? fillInLabel(android.content.Context context, android.os.Bundle? bundle);
+ method public final androidx.navigation.NavAction? getAction(@IdRes int id);
+ method public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> getArguments();
+ method public static final kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
+ method @IdRes public final int getId();
+ method public final CharSequence? getLabel();
+ method public final String getNavigatorName();
+ method public final androidx.navigation.NavGraph? getParent();
+ method public final String? getRoute();
+ method public boolean hasDeepLink(android.net.Uri deepLink);
+ method public boolean hasDeepLink(androidx.navigation.NavDeepLinkRequest deepLinkRequest);
+ method @CallSuper public void onInflate(android.content.Context context, android.util.AttributeSet attrs);
+ method protected static final <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+ method public final void putAction(@IdRes int actionId, androidx.navigation.NavAction action);
+ method public final void putAction(@IdRes int actionId, @IdRes int destId);
+ method public final void removeAction(@IdRes int actionId);
+ method public final void removeArgument(String argumentName);
+ method public final void setId(@IdRes int);
+ method public final void setLabel(CharSequence?);
+ method public final void setRoute(String?);
+ property public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> arguments;
+ property @IdRes public final int id;
+ property public final CharSequence? label;
+ property public final String navigatorName;
+ property public final androidx.navigation.NavGraph? parent;
+ property public final String? route;
+ field public static final androidx.navigation.NavDestination.Companion Companion;
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface NavDestination.ClassType {
+ method public abstract kotlin.reflect.KClass<?> value();
+ property public abstract kotlin.reflect.KClass<?> value;
+ }
+
+ public static final class NavDestination.Companion {
+ method public kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
+ method protected <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+ }
+
+ @androidx.navigation.NavDestinationDsl public class NavDestinationBuilder<D extends androidx.navigation.NavDestination> {
+ ctor @Deprecated public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
+ ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, String? route);
+ method @Deprecated public final void action(int actionId, kotlin.jvm.functions.Function1<? super androidx.navigation.NavActionBuilder,kotlin.Unit> actionBuilder);
+ method public final void argument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> argumentBuilder);
+ method public D build();
+ method public final void deepLink(String uriPattern);
+ method public final void deepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> navDeepLink);
+ method public final int getId();
+ method public final CharSequence? getLabel();
+ method protected final androidx.navigation.Navigator<? extends D> getNavigator();
+ method public final String? getRoute();
+ method public final void setLabel(CharSequence?);
+ property public final int id;
+ property public final CharSequence? label;
+ property protected final androidx.navigation.Navigator<? extends D> navigator;
+ property public final String? route;
+ }
+
+ @kotlin.DslMarker public @interface NavDestinationDsl {
+ }
+
+ public interface NavDirections {
+ method @IdRes public int getActionId();
+ method public android.os.Bundle getArguments();
+ property @IdRes public abstract int actionId;
+ property public abstract android.os.Bundle arguments;
+ }
+
+ public class NavGraph extends androidx.navigation.NavDestination implements java.lang.Iterable<androidx.navigation.NavDestination> kotlin.jvm.internal.markers.KMappedMarker {
+ ctor public NavGraph(androidx.navigation.Navigator<? extends androidx.navigation.NavGraph> navGraphNavigator);
+ method public final void addAll(androidx.navigation.NavGraph other);
+ method public final void addDestination(androidx.navigation.NavDestination node);
+ method public final void addDestinations(androidx.navigation.NavDestination... nodes);
+ method public final void addDestinations(java.util.Collection<? extends androidx.navigation.NavDestination> nodes);
+ method public final void clear();
+ method public final androidx.navigation.NavDestination? findNode(@IdRes int resId);
+ method public final androidx.navigation.NavDestination? findNode(String? route);
+ method public static final androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
+ method @Deprecated @IdRes public final int getStartDestination();
+ method @IdRes public final int getStartDestinationId();
+ method public final String? getStartDestinationRoute();
+ method public final java.util.Iterator<androidx.navigation.NavDestination> iterator();
+ method public final void remove(androidx.navigation.NavDestination node);
+ method public final void setStartDestination(int startDestId);
+ method public final void setStartDestination(String startDestRoute);
+ property @IdRes public final int startDestinationId;
+ property public final String? startDestinationRoute;
+ field public static final androidx.navigation.NavGraph.Companion Companion;
+ }
+
+ public static final class NavGraph.Companion {
+ method public androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
+ }
+
+ @androidx.navigation.NavDestinationDsl public class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
+ ctor @Deprecated public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+ ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, String? route);
+ method public final void addDestination(androidx.navigation.NavDestination destination);
+ method public androidx.navigation.NavGraph build();
+ method public final <D extends androidx.navigation.NavDestination> void destination(androidx.navigation.NavDestinationBuilder<? extends D> navDestination);
+ method public final androidx.navigation.NavigatorProvider getProvider();
+ method public final operator void unaryPlus(androidx.navigation.NavDestination);
+ property public final androidx.navigation.NavigatorProvider provider;
+ }
+
+ public final class NavGraphBuilderKt {
+ method @Deprecated public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method public static inline void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavGraphKt {
+ method public static operator boolean contains(androidx.navigation.NavGraph, @IdRes int id);
+ method public static operator boolean contains(androidx.navigation.NavGraph, String route);
+ method public static inline operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, @IdRes int id);
+ method public static inline operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, String route);
+ method public static inline operator void minusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+ method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+ method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavGraph other);
+ }
+
+ @androidx.navigation.Navigator.Name("navigation") public class NavGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.NavGraph> {
+ ctor public NavGraphNavigator(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public androidx.navigation.NavGraph createDestination();
+ method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+ }
+
+ public final class NavOptions {
+ method @AnimRes @AnimatorRes public int getEnterAnim();
+ method @AnimRes @AnimatorRes public int getExitAnim();
+ method @AnimRes @AnimatorRes public int getPopEnterAnim();
+ method @AnimRes @AnimatorRes public int getPopExitAnim();
+ method @Deprecated @IdRes public int getPopUpTo();
+ method @IdRes public int getPopUpToId();
+ method public String? getPopUpToRoute();
+ method public boolean isPopUpToInclusive();
+ method public boolean shouldLaunchSingleTop();
+ method public boolean shouldPopUpToSaveState();
+ method public boolean shouldRestoreState();
+ property @AnimRes @AnimatorRes public final int enterAnim;
+ property @AnimRes @AnimatorRes public final int exitAnim;
+ property @AnimRes @AnimatorRes public final int popEnterAnim;
+ property @AnimRes @AnimatorRes public final int popExitAnim;
+ property @IdRes public final int popUpToId;
+ property public final String? popUpToRoute;
+ }
+
+ public static final class NavOptions.Builder {
+ ctor public NavOptions.Builder();
+ method public androidx.navigation.NavOptions build();
+ method public androidx.navigation.NavOptions.Builder setEnterAnim(@AnimRes @AnimatorRes int enterAnim);
+ method public androidx.navigation.NavOptions.Builder setExitAnim(@AnimRes @AnimatorRes int exitAnim);
+ method public androidx.navigation.NavOptions.Builder setLaunchSingleTop(boolean singleTop);
+ method public androidx.navigation.NavOptions.Builder setPopEnterAnim(@AnimRes @AnimatorRes int popEnterAnim);
+ method public androidx.navigation.NavOptions.Builder setPopExitAnim(@AnimRes @AnimatorRes int popExitAnim);
+ method public androidx.navigation.NavOptions.Builder setPopUpTo(@IdRes int destinationId, boolean inclusive);
+ method public androidx.navigation.NavOptions.Builder setPopUpTo(@IdRes int destinationId, boolean inclusive, optional boolean saveState);
+ method public androidx.navigation.NavOptions.Builder setPopUpTo(String? route, boolean inclusive);
+ method public androidx.navigation.NavOptions.Builder setPopUpTo(String? route, boolean inclusive, optional boolean saveState);
+ method public androidx.navigation.NavOptions.Builder setRestoreState(boolean restoreState);
+ }
+
+ @androidx.navigation.NavOptionsDsl public final class NavOptionsBuilder {
+ ctor public NavOptionsBuilder();
+ method public void anim(kotlin.jvm.functions.Function1<? super androidx.navigation.AnimBuilder,kotlin.Unit> animBuilder);
+ method public boolean getLaunchSingleTop();
+ method @Deprecated public int getPopUpTo();
+ method public int getPopUpToId();
+ method public String? getPopUpToRoute();
+ method public boolean getRestoreState();
+ method public void popUpTo(@IdRes int id, optional kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit> popUpToBuilder);
+ method public void popUpTo(String route, optional kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit> popUpToBuilder);
+ method public void setLaunchSingleTop(boolean);
+ method @Deprecated public void setPopUpTo(int);
+ method public void setRestoreState(boolean);
+ property public final boolean launchSingleTop;
+ property @Deprecated public final int popUpTo;
+ property public final int popUpToId;
+ property public final String? popUpToRoute;
+ property public final boolean restoreState;
+ }
+
+ public final class NavOptionsBuilderKt {
+ method public static androidx.navigation.NavOptions navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+ }
+
+ @kotlin.DslMarker public @interface NavOptionsDsl {
+ }
+
+ public abstract class NavType<T> {
+ ctor public NavType(boolean isNullableAllowed);
+ method public static androidx.navigation.NavType<?> fromArgType(String? type, String? packageName);
+ method public abstract operator T? get(android.os.Bundle bundle, String key);
+ method public String getName();
+ method public boolean isNullableAllowed();
+ method public abstract T parseValue(String value);
+ method public T parseValue(String value, T previousValue);
+ method public abstract void put(android.os.Bundle bundle, String key, T value);
+ method public String serializeAsValue(T value);
+ property public boolean isNullableAllowed;
+ property public String name;
+ field public static final androidx.navigation.NavType<boolean[]> BoolArrayType;
+ field public static final androidx.navigation.NavType<java.lang.Boolean> BoolType;
+ field public static final androidx.navigation.NavType.Companion Companion;
+ field public static final androidx.navigation.NavType<float[]> FloatArrayType;
+ field public static final androidx.navigation.NavType<java.lang.Float> FloatType;
+ field public static final androidx.navigation.NavType<int[]> IntArrayType;
+ field public static final androidx.navigation.NavType<java.lang.Integer> IntType;
+ field public static final androidx.navigation.NavType<long[]> LongArrayType;
+ field public static final androidx.navigation.NavType<java.lang.Long> LongType;
+ field public static final androidx.navigation.NavType<java.lang.Integer> ReferenceType;
+ field public static final androidx.navigation.NavType<java.lang.String[]> StringArrayType;
+ field public static final androidx.navigation.NavType<java.lang.String> StringType;
+ }
+
+ public static final class NavType.Companion {
+ method public androidx.navigation.NavType<?> fromArgType(String? type, String? packageName);
+ }
+
+ public static final class NavType.EnumType<D extends java.lang.Enum<?>> extends androidx.navigation.NavType.SerializableType<D> {
+ ctor public NavType.EnumType(Class<D> type);
+ property public String name;
+ }
+
+ public static final class NavType.ParcelableArrayType<D extends android.os.Parcelable> extends androidx.navigation.NavType<D[]> {
+ ctor public NavType.ParcelableArrayType(Class<D> type);
+ method public D![]? get(android.os.Bundle bundle, String key);
+ method public D![] parseValue(String value);
+ method public void put(android.os.Bundle bundle, String key, D![]? value);
+ property public String name;
+ }
+
+ public static final class NavType.ParcelableType<D> extends androidx.navigation.NavType<D> {
+ ctor public NavType.ParcelableType(Class<D> type);
+ method public D? get(android.os.Bundle bundle, String key);
+ method public D parseValue(String value);
+ method public void put(android.os.Bundle bundle, String key, D value);
+ property public String name;
+ }
+
+ public static final class NavType.SerializableArrayType<D extends java.io.Serializable> extends androidx.navigation.NavType<D[]> {
+ ctor public NavType.SerializableArrayType(Class<D> type);
+ method public D![]? get(android.os.Bundle bundle, String key);
+ method public D![] parseValue(String value);
+ method public void put(android.os.Bundle bundle, String key, D![]? value);
+ property public String name;
+ }
+
+ public static class NavType.SerializableType<D extends java.io.Serializable> extends androidx.navigation.NavType<D> {
+ ctor public NavType.SerializableType(Class<D> type);
+ method public D? get(android.os.Bundle bundle, String key);
+ method public D parseValue(String value);
+ method public void put(android.os.Bundle bundle, String key, D value);
+ property public String name;
+ }
+
+ public abstract class Navigator<D extends androidx.navigation.NavDestination> {
+ ctor public Navigator();
+ method public abstract D createDestination();
+ method protected final androidx.navigation.NavigatorState getState();
+ method public final boolean isAttached();
+ method public androidx.navigation.NavDestination? navigate(D destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ method public void navigate(java.util.List<androidx.navigation.NavBackStackEntry> entries, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ method @CallSuper public void onAttach(androidx.navigation.NavigatorState state);
+ method public void onLaunchSingleTop(androidx.navigation.NavBackStackEntry backStackEntry);
+ method public void onRestoreState(android.os.Bundle savedState);
+ method public android.os.Bundle? onSaveState();
+ method public boolean popBackStack();
+ method public void popBackStack(androidx.navigation.NavBackStackEntry popUpTo, boolean savedState);
+ property public final boolean isAttached;
+ property protected final androidx.navigation.NavigatorState state;
+ }
+
+ public static interface Navigator.Extras {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface Navigator.Name {
+ method public abstract String value();
+ property public abstract String value;
+ }
+
+ public class NavigatorProvider {
+ ctor public NavigatorProvider();
+ method public final androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+ method @CallSuper public androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(String name, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+ method public final <T extends androidx.navigation.Navigator<?>> T getNavigator(Class<T> navigatorClass);
+ method @CallSuper public <T extends androidx.navigation.Navigator<?>> T getNavigator(String name);
+ }
+
+ public final class NavigatorProviderKt {
+ method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, String name);
+ method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, kotlin.reflect.KClass<T> clazz);
+ method public static inline operator void plusAssign(androidx.navigation.NavigatorProvider, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+ method public static inline operator androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? set(androidx.navigation.NavigatorProvider, String name, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+ }
+
+ public abstract class NavigatorState {
+ ctor public NavigatorState();
+ method public abstract androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+ method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+ method public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> getTransitionsInProgress();
+ method public void markTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+ method @CallSuper public void onLaunchSingleTop(androidx.navigation.NavBackStackEntry backStackEntry);
+ method @CallSuper public void onLaunchSingleTopWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
+ method public void pop(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
+ method public void popWithTransition(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
+ method @CallSuper public void prepareForTransition(androidx.navigation.NavBackStackEntry entry);
+ method public void push(androidx.navigation.NavBackStackEntry backStackEntry);
+ method public void pushWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> transitionsInProgress;
+ }
+
+ @androidx.navigation.NavOptionsDsl public final class PopUpToBuilder {
+ ctor public PopUpToBuilder();
+ method public boolean getInclusive();
+ method public boolean getSaveState();
+ method public void setInclusive(boolean);
+ method public void setSaveState(boolean);
+ property public final boolean inclusive;
+ property public final boolean saveState;
+ }
+
+}
+
diff --git a/navigation/navigation-common/api/res-2.7.0-beta01.txt b/navigation/navigation-common/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-common/api/res-2.7.0-beta01.txt
diff --git a/navigation/navigation-common/api/restricted_2.7.0-beta01.txt b/navigation/navigation-common/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..51a77a6
--- /dev/null
+++ b/navigation/navigation-common/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1,530 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+ public final class ActionOnlyNavDirections implements androidx.navigation.NavDirections {
+ ctor public ActionOnlyNavDirections(int actionId);
+ method public int component1();
+ method public androidx.navigation.ActionOnlyNavDirections copy(int actionId);
+ method public int getActionId();
+ method public android.os.Bundle getArguments();
+ property public int actionId;
+ property public android.os.Bundle arguments;
+ }
+
+ @androidx.navigation.NavOptionsDsl public final class AnimBuilder {
+ ctor public AnimBuilder();
+ method public int getEnter();
+ method public int getExit();
+ method public int getPopEnter();
+ method public int getPopExit();
+ method public void setEnter(int);
+ method public void setExit(int);
+ method public void setPopEnter(int);
+ method public void setPopExit(int);
+ property public final int enter;
+ property public final int exit;
+ property public final int popEnter;
+ property public final int popExit;
+ }
+
+ public interface FloatingWindow {
+ }
+
+ public final class NamedNavArgument {
+ method public operator String component1();
+ method public operator androidx.navigation.NavArgument component2();
+ method public androidx.navigation.NavArgument getArgument();
+ method public String getName();
+ property public final androidx.navigation.NavArgument argument;
+ property public final String name;
+ }
+
+ public final class NamedNavArgumentKt {
+ method public static androidx.navigation.NamedNavArgument navArgument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavAction {
+ ctor public NavAction(@IdRes int destinationId);
+ ctor public NavAction(@IdRes int destinationId, optional androidx.navigation.NavOptions? navOptions);
+ ctor public NavAction(@IdRes int destinationId, optional androidx.navigation.NavOptions? navOptions, optional android.os.Bundle? defaultArguments);
+ method public android.os.Bundle? getDefaultArguments();
+ method public int getDestinationId();
+ method public androidx.navigation.NavOptions? getNavOptions();
+ method public void setDefaultArguments(android.os.Bundle?);
+ method public void setNavOptions(androidx.navigation.NavOptions?);
+ property public final android.os.Bundle? defaultArguments;
+ property public final int destinationId;
+ property public final androidx.navigation.NavOptions? navOptions;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class NavActionBuilder {
+ ctor public NavActionBuilder();
+ method public java.util.Map<java.lang.String,java.lang.Object> getDefaultArguments();
+ method public int getDestinationId();
+ method public void navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+ method public void setDestinationId(int);
+ property public final java.util.Map<java.lang.String,java.lang.Object> defaultArguments;
+ property public final int destinationId;
+ }
+
+ public interface NavArgs {
+ }
+
+ public final class NavArgsLazy<Args extends androidx.navigation.NavArgs> implements kotlin.Lazy<Args> {
+ ctor public NavArgsLazy(kotlin.reflect.KClass<Args> navArgsClass, kotlin.jvm.functions.Function0<android.os.Bundle> argumentProducer);
+ method public Args getValue();
+ method public boolean isInitialized();
+ property public Args value;
+ }
+
+ public final class NavArgument {
+ method public Object? getDefaultValue();
+ method public androidx.navigation.NavType<java.lang.Object> getType();
+ method public boolean isDefaultValuePresent();
+ method public boolean isNullable();
+ property public final Object? defaultValue;
+ property public final boolean isDefaultValuePresent;
+ property public final boolean isNullable;
+ property public final androidx.navigation.NavType<java.lang.Object> type;
+ }
+
+ public static final class NavArgument.Builder {
+ ctor public NavArgument.Builder();
+ method public androidx.navigation.NavArgument build();
+ method public androidx.navigation.NavArgument.Builder setDefaultValue(Object? defaultValue);
+ method public androidx.navigation.NavArgument.Builder setIsNullable(boolean isNullable);
+ method public <T> androidx.navigation.NavArgument.Builder setType(androidx.navigation.NavType<T> type);
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class NavArgumentBuilder {
+ ctor public NavArgumentBuilder();
+ method public androidx.navigation.NavArgument build();
+ method public Object? getDefaultValue();
+ method public boolean getNullable();
+ method public androidx.navigation.NavType<?> getType();
+ method public void setDefaultValue(Object?);
+ method public void setNullable(boolean);
+ method public void setType(androidx.navigation.NavType<?>);
+ property public final Object? defaultValue;
+ property public final boolean nullable;
+ property public final androidx.navigation.NavType<?> type;
+ }
+
+ public final class NavBackStackEntry implements androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+ method public android.os.Bundle? getArguments();
+ method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+ method public androidx.navigation.NavDestination getDestination();
+ method public String getId();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method public androidx.lifecycle.SavedStateHandle getSavedStateHandle();
+ method public androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+ method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ property public final android.os.Bundle? arguments;
+ property public androidx.lifecycle.viewmodel.CreationExtras defaultViewModelCreationExtras;
+ property public androidx.lifecycle.ViewModelProvider.Factory defaultViewModelProviderFactory;
+ property public final androidx.navigation.NavDestination destination;
+ property public final String id;
+ property public androidx.lifecycle.Lifecycle lifecycle;
+ property public final androidx.lifecycle.SavedStateHandle savedStateHandle;
+ property public androidx.savedstate.SavedStateRegistry savedStateRegistry;
+ property public androidx.lifecycle.ViewModelStore viewModelStore;
+ }
+
+ public final class NavDeepLink {
+ method public String? getAction();
+ method public String? getMimeType();
+ method public String? getUriPattern();
+ property public final String? action;
+ property public final String? mimeType;
+ property public final String? uriPattern;
+ }
+
+ public static final class NavDeepLink.Builder {
+ method public androidx.navigation.NavDeepLink build();
+ method public static androidx.navigation.NavDeepLink.Builder fromAction(String action);
+ method public static androidx.navigation.NavDeepLink.Builder fromMimeType(String mimeType);
+ method public static androidx.navigation.NavDeepLink.Builder fromUriPattern(String uriPattern);
+ method public androidx.navigation.NavDeepLink.Builder setAction(String action);
+ method public androidx.navigation.NavDeepLink.Builder setMimeType(String mimeType);
+ method public androidx.navigation.NavDeepLink.Builder setUriPattern(String uriPattern);
+ }
+
+ @kotlin.DslMarker public @interface NavDeepLinkDsl {
+ }
+
+ @androidx.navigation.NavDeepLinkDsl public final class NavDeepLinkDslBuilder {
+ ctor public NavDeepLinkDslBuilder();
+ method public String? getAction();
+ method public String? getMimeType();
+ method public String? getUriPattern();
+ method public void setAction(String?);
+ method public void setMimeType(String?);
+ method public void setUriPattern(String?);
+ property public final String? action;
+ property public final String? mimeType;
+ property public final String? uriPattern;
+ }
+
+ public final class NavDeepLinkDslBuilderKt {
+ method public static androidx.navigation.NavDeepLink navDeepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
+ }
+
+ public class NavDeepLinkRequest {
+ method public String? getAction();
+ method public String? getMimeType();
+ method public android.net.Uri? getUri();
+ property public String? action;
+ property public String? mimeType;
+ property public android.net.Uri? uri;
+ }
+
+ public static final class NavDeepLinkRequest.Builder {
+ method public androidx.navigation.NavDeepLinkRequest build();
+ method public static androidx.navigation.NavDeepLinkRequest.Builder fromAction(String action);
+ method public static androidx.navigation.NavDeepLinkRequest.Builder fromMimeType(String mimeType);
+ method public static androidx.navigation.NavDeepLinkRequest.Builder fromUri(android.net.Uri uri);
+ method public androidx.navigation.NavDeepLinkRequest.Builder setAction(String action);
+ method public androidx.navigation.NavDeepLinkRequest.Builder setMimeType(String mimeType);
+ method public androidx.navigation.NavDeepLinkRequest.Builder setUri(android.net.Uri uri);
+ field public static final androidx.navigation.NavDeepLinkRequest.Builder.Companion Companion;
+ }
+
+ public static final class NavDeepLinkRequest.Builder.Companion {
+ method public androidx.navigation.NavDeepLinkRequest.Builder fromAction(String action);
+ method public androidx.navigation.NavDeepLinkRequest.Builder fromMimeType(String mimeType);
+ method public androidx.navigation.NavDeepLinkRequest.Builder fromUri(android.net.Uri uri);
+ }
+
+ public class NavDestination {
+ ctor public NavDestination(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+ ctor public NavDestination(String navigatorName);
+ method public final void addArgument(String argumentName, androidx.navigation.NavArgument argument);
+ method public final void addDeepLink(androidx.navigation.NavDeepLink navDeepLink);
+ method public final void addDeepLink(String uriPattern);
+ method public final String? fillInLabel(android.content.Context context, android.os.Bundle? bundle);
+ method public final androidx.navigation.NavAction? getAction(@IdRes int id);
+ method public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> getArguments();
+ method public static final kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
+ method @IdRes public final int getId();
+ method public final CharSequence? getLabel();
+ method public final String getNavigatorName();
+ method public final androidx.navigation.NavGraph? getParent();
+ method public final String? getRoute();
+ method public boolean hasDeepLink(android.net.Uri deepLink);
+ method public boolean hasDeepLink(androidx.navigation.NavDeepLinkRequest deepLinkRequest);
+ method @CallSuper public void onInflate(android.content.Context context, android.util.AttributeSet attrs);
+ method protected static final <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+ method public final void putAction(@IdRes int actionId, androidx.navigation.NavAction action);
+ method public final void putAction(@IdRes int actionId, @IdRes int destId);
+ method public final void removeAction(@IdRes int actionId);
+ method public final void removeArgument(String argumentName);
+ method public final void setId(@IdRes int);
+ method public final void setLabel(CharSequence?);
+ method public final void setRoute(String?);
+ property public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> arguments;
+ property @IdRes public final int id;
+ property public final CharSequence? label;
+ property public final String navigatorName;
+ property public final androidx.navigation.NavGraph? parent;
+ property public final String? route;
+ field public static final androidx.navigation.NavDestination.Companion Companion;
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface NavDestination.ClassType {
+ method public abstract kotlin.reflect.KClass<?> value();
+ property public abstract kotlin.reflect.KClass<?> value;
+ }
+
+ public static final class NavDestination.Companion {
+ method public kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
+ method protected <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+ }
+
+ @androidx.navigation.NavDestinationDsl public class NavDestinationBuilder<D extends androidx.navigation.NavDestination> {
+ ctor @Deprecated public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
+ ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, String? route);
+ method @Deprecated public final void action(int actionId, kotlin.jvm.functions.Function1<? super androidx.navigation.NavActionBuilder,kotlin.Unit> actionBuilder);
+ method public final void argument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> argumentBuilder);
+ method public D build();
+ method public final void deepLink(String uriPattern);
+ method public final void deepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> navDeepLink);
+ method public final int getId();
+ method public final CharSequence? getLabel();
+ method protected final androidx.navigation.Navigator<? extends D> getNavigator();
+ method public final String? getRoute();
+ method public final void setLabel(CharSequence?);
+ property public final int id;
+ property public final CharSequence? label;
+ property protected final androidx.navigation.Navigator<? extends D> navigator;
+ property public final String? route;
+ }
+
+ @kotlin.DslMarker public @interface NavDestinationDsl {
+ }
+
+ public interface NavDirections {
+ method @IdRes public int getActionId();
+ method public android.os.Bundle getArguments();
+ property @IdRes public abstract int actionId;
+ property public abstract android.os.Bundle arguments;
+ }
+
+ public class NavGraph extends androidx.navigation.NavDestination implements java.lang.Iterable<androidx.navigation.NavDestination> kotlin.jvm.internal.markers.KMappedMarker {
+ ctor public NavGraph(androidx.navigation.Navigator<? extends androidx.navigation.NavGraph> navGraphNavigator);
+ method public final void addAll(androidx.navigation.NavGraph other);
+ method public final void addDestination(androidx.navigation.NavDestination node);
+ method public final void addDestinations(androidx.navigation.NavDestination... nodes);
+ method public final void addDestinations(java.util.Collection<? extends androidx.navigation.NavDestination> nodes);
+ method public final void clear();
+ method public final androidx.navigation.NavDestination? findNode(@IdRes int resId);
+ method public final androidx.navigation.NavDestination? findNode(String? route);
+ method public static final androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
+ method @Deprecated @IdRes public final int getStartDestination();
+ method @IdRes public final int getStartDestinationId();
+ method public final String? getStartDestinationRoute();
+ method public final java.util.Iterator<androidx.navigation.NavDestination> iterator();
+ method public final void remove(androidx.navigation.NavDestination node);
+ method public final void setStartDestination(int startDestId);
+ method public final void setStartDestination(String startDestRoute);
+ property @IdRes public final int startDestinationId;
+ property public final String? startDestinationRoute;
+ field public static final androidx.navigation.NavGraph.Companion Companion;
+ }
+
+ public static final class NavGraph.Companion {
+ method public androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
+ }
+
+ @androidx.navigation.NavDestinationDsl public class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
+ ctor @Deprecated public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+ ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, String? route);
+ method public final void addDestination(androidx.navigation.NavDestination destination);
+ method public androidx.navigation.NavGraph build();
+ method public final <D extends androidx.navigation.NavDestination> void destination(androidx.navigation.NavDestinationBuilder<? extends D> navDestination);
+ method public final androidx.navigation.NavigatorProvider getProvider();
+ method public final operator void unaryPlus(androidx.navigation.NavDestination);
+ property public final androidx.navigation.NavigatorProvider provider;
+ }
+
+ public final class NavGraphBuilderKt {
+ method @Deprecated public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method public static inline void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavGraphKt {
+ method public static operator boolean contains(androidx.navigation.NavGraph, @IdRes int id);
+ method public static operator boolean contains(androidx.navigation.NavGraph, String route);
+ method public static inline operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, @IdRes int id);
+ method public static inline operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, String route);
+ method public static inline operator void minusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+ method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+ method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavGraph other);
+ }
+
+ @androidx.navigation.Navigator.Name("navigation") public class NavGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.NavGraph> {
+ ctor public NavGraphNavigator(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public androidx.navigation.NavGraph createDestination();
+ method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+ }
+
+ public final class NavOptions {
+ method @AnimRes @AnimatorRes public int getEnterAnim();
+ method @AnimRes @AnimatorRes public int getExitAnim();
+ method @AnimRes @AnimatorRes public int getPopEnterAnim();
+ method @AnimRes @AnimatorRes public int getPopExitAnim();
+ method @Deprecated @IdRes public int getPopUpTo();
+ method @IdRes public int getPopUpToId();
+ method public String? getPopUpToRoute();
+ method public boolean isPopUpToInclusive();
+ method public boolean shouldLaunchSingleTop();
+ method public boolean shouldPopUpToSaveState();
+ method public boolean shouldRestoreState();
+ property @AnimRes @AnimatorRes public final int enterAnim;
+ property @AnimRes @AnimatorRes public final int exitAnim;
+ property @AnimRes @AnimatorRes public final int popEnterAnim;
+ property @AnimRes @AnimatorRes public final int popExitAnim;
+ property @IdRes public final int popUpToId;
+ property public final String? popUpToRoute;
+ }
+
+ public static final class NavOptions.Builder {
+ ctor public NavOptions.Builder();
+ method public androidx.navigation.NavOptions build();
+ method public androidx.navigation.NavOptions.Builder setEnterAnim(@AnimRes @AnimatorRes int enterAnim);
+ method public androidx.navigation.NavOptions.Builder setExitAnim(@AnimRes @AnimatorRes int exitAnim);
+ method public androidx.navigation.NavOptions.Builder setLaunchSingleTop(boolean singleTop);
+ method public androidx.navigation.NavOptions.Builder setPopEnterAnim(@AnimRes @AnimatorRes int popEnterAnim);
+ method public androidx.navigation.NavOptions.Builder setPopExitAnim(@AnimRes @AnimatorRes int popExitAnim);
+ method public androidx.navigation.NavOptions.Builder setPopUpTo(@IdRes int destinationId, boolean inclusive);
+ method public androidx.navigation.NavOptions.Builder setPopUpTo(@IdRes int destinationId, boolean inclusive, optional boolean saveState);
+ method public androidx.navigation.NavOptions.Builder setPopUpTo(String? route, boolean inclusive);
+ method public androidx.navigation.NavOptions.Builder setPopUpTo(String? route, boolean inclusive, optional boolean saveState);
+ method public androidx.navigation.NavOptions.Builder setRestoreState(boolean restoreState);
+ }
+
+ @androidx.navigation.NavOptionsDsl public final class NavOptionsBuilder {
+ ctor public NavOptionsBuilder();
+ method public void anim(kotlin.jvm.functions.Function1<? super androidx.navigation.AnimBuilder,kotlin.Unit> animBuilder);
+ method public boolean getLaunchSingleTop();
+ method @Deprecated public int getPopUpTo();
+ method public int getPopUpToId();
+ method public String? getPopUpToRoute();
+ method public boolean getRestoreState();
+ method public void popUpTo(@IdRes int id, optional kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit> popUpToBuilder);
+ method public void popUpTo(String route, optional kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit> popUpToBuilder);
+ method public void setLaunchSingleTop(boolean);
+ method @Deprecated public void setPopUpTo(int);
+ method public void setRestoreState(boolean);
+ property public final boolean launchSingleTop;
+ property @Deprecated public final int popUpTo;
+ property public final int popUpToId;
+ property public final String? popUpToRoute;
+ property public final boolean restoreState;
+ }
+
+ public final class NavOptionsBuilderKt {
+ method public static androidx.navigation.NavOptions navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+ }
+
+ @kotlin.DslMarker public @interface NavOptionsDsl {
+ }
+
+ public abstract class NavType<T> {
+ ctor public NavType(boolean isNullableAllowed);
+ method public static androidx.navigation.NavType<?> fromArgType(String? type, String? packageName);
+ method public abstract operator T? get(android.os.Bundle bundle, String key);
+ method public String getName();
+ method public boolean isNullableAllowed();
+ method public abstract T parseValue(String value);
+ method public T parseValue(String value, T previousValue);
+ method public abstract void put(android.os.Bundle bundle, String key, T value);
+ method public String serializeAsValue(T value);
+ property public boolean isNullableAllowed;
+ property public String name;
+ field public static final androidx.navigation.NavType<boolean[]> BoolArrayType;
+ field public static final androidx.navigation.NavType<java.lang.Boolean> BoolType;
+ field public static final androidx.navigation.NavType.Companion Companion;
+ field public static final androidx.navigation.NavType<float[]> FloatArrayType;
+ field public static final androidx.navigation.NavType<java.lang.Float> FloatType;
+ field public static final androidx.navigation.NavType<int[]> IntArrayType;
+ field public static final androidx.navigation.NavType<java.lang.Integer> IntType;
+ field public static final androidx.navigation.NavType<long[]> LongArrayType;
+ field public static final androidx.navigation.NavType<java.lang.Long> LongType;
+ field public static final androidx.navigation.NavType<java.lang.Integer> ReferenceType;
+ field public static final androidx.navigation.NavType<java.lang.String[]> StringArrayType;
+ field public static final androidx.navigation.NavType<java.lang.String> StringType;
+ }
+
+ public static final class NavType.Companion {
+ method public androidx.navigation.NavType<?> fromArgType(String? type, String? packageName);
+ }
+
+ public static final class NavType.EnumType<D extends java.lang.Enum<?>> extends androidx.navigation.NavType.SerializableType<D> {
+ ctor public NavType.EnumType(Class<D> type);
+ property public String name;
+ }
+
+ public static final class NavType.ParcelableArrayType<D extends android.os.Parcelable> extends androidx.navigation.NavType<D[]> {
+ ctor public NavType.ParcelableArrayType(Class<D> type);
+ method public D![]? get(android.os.Bundle bundle, String key);
+ method public D![] parseValue(String value);
+ method public void put(android.os.Bundle bundle, String key, D![]? value);
+ property public String name;
+ }
+
+ public static final class NavType.ParcelableType<D> extends androidx.navigation.NavType<D> {
+ ctor public NavType.ParcelableType(Class<D> type);
+ method public D? get(android.os.Bundle bundle, String key);
+ method public D parseValue(String value);
+ method public void put(android.os.Bundle bundle, String key, D value);
+ property public String name;
+ }
+
+ public static final class NavType.SerializableArrayType<D extends java.io.Serializable> extends androidx.navigation.NavType<D[]> {
+ ctor public NavType.SerializableArrayType(Class<D> type);
+ method public D![]? get(android.os.Bundle bundle, String key);
+ method public D![] parseValue(String value);
+ method public void put(android.os.Bundle bundle, String key, D![]? value);
+ property public String name;
+ }
+
+ public static class NavType.SerializableType<D extends java.io.Serializable> extends androidx.navigation.NavType<D> {
+ ctor public NavType.SerializableType(Class<D> type);
+ method public D? get(android.os.Bundle bundle, String key);
+ method public D parseValue(String value);
+ method public void put(android.os.Bundle bundle, String key, D value);
+ property public String name;
+ }
+
+ public abstract class Navigator<D extends androidx.navigation.NavDestination> {
+ ctor public Navigator();
+ method public abstract D createDestination();
+ method protected final androidx.navigation.NavigatorState getState();
+ method public final boolean isAttached();
+ method public androidx.navigation.NavDestination? navigate(D destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ method public void navigate(java.util.List<androidx.navigation.NavBackStackEntry> entries, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ method @CallSuper public void onAttach(androidx.navigation.NavigatorState state);
+ method public void onLaunchSingleTop(androidx.navigation.NavBackStackEntry backStackEntry);
+ method public void onRestoreState(android.os.Bundle savedState);
+ method public android.os.Bundle? onSaveState();
+ method public boolean popBackStack();
+ method public void popBackStack(androidx.navigation.NavBackStackEntry popUpTo, boolean savedState);
+ property public final boolean isAttached;
+ property protected final androidx.navigation.NavigatorState state;
+ }
+
+ public static interface Navigator.Extras {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface Navigator.Name {
+ method public abstract String value();
+ property public abstract String value;
+ }
+
+ public class NavigatorProvider {
+ ctor public NavigatorProvider();
+ method public final androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+ method @CallSuper public androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(String name, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+ method public final <T extends androidx.navigation.Navigator<?>> T getNavigator(Class<T> navigatorClass);
+ method @CallSuper public <T extends androidx.navigation.Navigator<?>> T getNavigator(String name);
+ }
+
+ public final class NavigatorProviderKt {
+ method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, String name);
+ method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, kotlin.reflect.KClass<T> clazz);
+ method public static inline operator void plusAssign(androidx.navigation.NavigatorProvider, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+ method public static inline operator androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? set(androidx.navigation.NavigatorProvider, String name, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+ }
+
+ public abstract class NavigatorState {
+ ctor public NavigatorState();
+ method public abstract androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+ method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+ method public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> getTransitionsInProgress();
+ method public void markTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+ method @CallSuper public void onLaunchSingleTop(androidx.navigation.NavBackStackEntry backStackEntry);
+ method @CallSuper public void onLaunchSingleTopWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
+ method public void pop(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
+ method public void popWithTransition(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
+ method @CallSuper public void prepareForTransition(androidx.navigation.NavBackStackEntry entry);
+ method public void push(androidx.navigation.NavBackStackEntry backStackEntry);
+ method public void pushWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> transitionsInProgress;
+ }
+
+ @androidx.navigation.NavOptionsDsl public final class PopUpToBuilder {
+ ctor public PopUpToBuilder();
+ method public boolean getInclusive();
+ method public boolean getSaveState();
+ method public void setInclusive(boolean);
+ method public void setSaveState(boolean);
+ property public final boolean inclusive;
+ property public final boolean saveState;
+ }
+
+}
+
diff --git a/navigation/navigation-common/lint-baseline.xml b/navigation/navigation-common/lint-baseline.xml
index 6deec5b..af90ea4 100644
--- a/navigation/navigation-common/lint-baseline.xml
+++ b/navigation/navigation-common/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
+<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">
<issue
id="BanHideAnnotation"
@@ -10,103 +10,4 @@
file="src/main/java/androidx/navigation/NavBackStackEntry.kt"/>
</issue>
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public fun create("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/navigation/NavBackStackEntry.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public open val displayName: String"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/NavDestination.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public fun getDisplayName(context: Context, id: Int): String {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/NavDestination.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public fun getDisplayName(context: Context, id: Int): String {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/NavDestination.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public fun createRoute(route: String?): String ="
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/NavDestination.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public fun findNode(@IdRes resId: Int, searchParents: Boolean): NavDestination? {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/NavGraph.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public fun findNode(route: String, searchParents: Boolean): NavDestination? {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/NavGraph.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" override val displayName: String"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/NavGraph.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface NavViewModelStoreProvider {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/NavViewModelStoreProvider.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public var isNavigating = false"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/NavigatorState.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class NoOpNavigator : Navigator<NavDestination>() {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/NoOpNavigator.kt"/>
- </issue>
-
</issues>
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
index 36301ef..0cf2b96 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
@@ -89,9 +89,6 @@
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public companion object {
- /**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public fun create(
context: Context?,
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavDestination.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavDestination.kt
index 99e410b..81ce6af 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavDestination.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavDestination.kt
@@ -232,11 +232,8 @@
field = route
}
- /**
- * @hide
- */
- @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public open val displayName: String
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
get() = idName ?: id.toString()
/**
@@ -793,7 +790,6 @@
* @param id The id to get a display name for
* @return The resource's name if it is a valid id or just the id itself if it is not
* a valid resource
- * @hide
*/
@JvmStatic
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -809,9 +805,6 @@
}
}
- /**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public fun createRoute(route: String?): String =
if (route != null) "android-app://androidx.navigation/$route" else ""
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
index 6ec0153..f05a46d 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
@@ -180,9 +180,6 @@
return if (!route.isNullOrBlank()) findNode(route, true) else null
}
- /**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public fun findNode(@IdRes resId: Int, searchParents: Boolean): NavDestination? {
val destination = nodes[resId]
@@ -192,9 +189,6 @@
?: if (searchParents && parent != null) parent!!.findNode(resId) else null
}
- /**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public fun findNode(route: String, searchParents: Boolean): NavDestination? {
// first try matching with routePattern
@@ -281,11 +275,8 @@
}
}
- @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
override val displayName: String
- /**
- * @hide
- */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
get() = if (id != 0) super.displayName else "the root navigation"
/**
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavViewModelStoreProvider.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavViewModelStoreProvider.kt
index 74fdc56..93959be 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavViewModelStoreProvider.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavViewModelStoreProvider.kt
@@ -22,8 +22,6 @@
/**
* Interface that allows you to retrieve a [ViewModelStore] associated with a
* particular [NavBackStackEntry.id].
- *
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public interface NavViewModelStoreProvider {
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavigatorState.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavigatorState.kt
index 9cbe30e..cb2ae8f 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavigatorState.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavigatorState.kt
@@ -36,10 +36,8 @@
private val _transitionsInProgress: MutableStateFlow<Set<NavBackStackEntry>> =
MutableStateFlow(setOf())
- /**
- * @hide
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @set:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public var isNavigating = false
/**
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NoOpNavigator.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NoOpNavigator.kt
index 07a78b8..2314f172 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NoOpNavigator.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NoOpNavigator.kt
@@ -20,8 +20,6 @@
/**
* A [Navigator] that only supports creating destinations.
- *
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Navigator.Name("NoOp")
diff --git a/navigation/navigation-compose/api/2.7.0-beta01.txt b/navigation/navigation-compose/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..6794d3e
--- /dev/null
+++ b/navigation/navigation-compose/api/2.7.0-beta01.txt
@@ -0,0 +1,55 @@
+// Signature format: 4.0
+package androidx.navigation.compose {
+
+ @androidx.navigation.Navigator.Name("composable") public final class ComposeNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.ComposeNavigator.Destination> {
+ ctor public ComposeNavigator();
+ method public androidx.navigation.compose.ComposeNavigator.Destination createDestination();
+ method public kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+ method public void onTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+ }
+
+ @androidx.navigation.NavDestination.ClassType(Composable::class) public static final class ComposeNavigator.Destination extends androidx.navigation.NavDestination {
+ ctor @Deprecated public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedContentScope,androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ }
+
+ public final class DialogHostKt {
+ method @androidx.compose.runtime.Composable public static void DialogHost(androidx.navigation.compose.DialogNavigator dialogNavigator);
+ }
+
+ @androidx.navigation.Navigator.Name("dialog") public final class DialogNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.DialogNavigator.Destination> {
+ ctor public DialogNavigator();
+ method public androidx.navigation.compose.DialogNavigator.Destination createDestination();
+ }
+
+ @androidx.navigation.NavDestination.ClassType(Composable::class) public static final class DialogNavigator.Destination extends androidx.navigation.NavDestination implements androidx.navigation.FloatingWindow {
+ ctor public DialogNavigator.Destination(androidx.navigation.compose.DialogNavigator navigator, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ }
+
+ public final class NavBackStackEntryProviderKt {
+ method @androidx.compose.runtime.Composable public static void LocalOwnersProvider(androidx.navigation.NavBackStackEntry, androidx.compose.runtime.saveable.SaveableStateHolder saveableStateHolder, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ public final class NavGraphBuilderKt {
+ method @Deprecated public static void composable(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ method public static void composable(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, optional kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition>? enterTransition, optional kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition>? exitTransition, optional kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition>? popEnterTransition, optional kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition>? popExitTransition, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedContentScope,? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ method public static void dialog(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ method public static void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition>? enterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition>? exitTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition>? popEnterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition>? popExitTransition, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavHostControllerKt {
+ method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<androidx.navigation.NavBackStackEntry> currentBackStackEntryAsState(androidx.navigation.NavController);
+ method @androidx.compose.runtime.Composable public static androidx.navigation.NavHostController rememberNavController(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>... navigators);
+ }
+
+ public final class NavHostKt {
+ method @Deprecated @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, androidx.navigation.NavGraph graph, optional androidx.compose.ui.Modifier modifier);
+ method @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, androidx.navigation.NavGraph graph, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.Alignment contentAlignment, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition> enterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition> exitTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition> popEnterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition> popExitTransition);
+ method @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, String startDestination, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.Alignment contentAlignment, optional String? route, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition> enterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition> exitTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition> popEnterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition> popExitTransition, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, String startDestination, optional androidx.compose.ui.Modifier modifier, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ }
+
+}
+
diff --git a/navigation/navigation-compose/api/res-2.7.0-beta01.txt b/navigation/navigation-compose/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-compose/api/res-2.7.0-beta01.txt
diff --git a/navigation/navigation-compose/api/restricted_2.7.0-beta01.txt b/navigation/navigation-compose/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..6794d3e
--- /dev/null
+++ b/navigation/navigation-compose/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1,55 @@
+// Signature format: 4.0
+package androidx.navigation.compose {
+
+ @androidx.navigation.Navigator.Name("composable") public final class ComposeNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.ComposeNavigator.Destination> {
+ ctor public ComposeNavigator();
+ method public androidx.navigation.compose.ComposeNavigator.Destination createDestination();
+ method public kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+ method public void onTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+ }
+
+ @androidx.navigation.NavDestination.ClassType(Composable::class) public static final class ComposeNavigator.Destination extends androidx.navigation.NavDestination {
+ ctor @Deprecated public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedContentScope,androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ }
+
+ public final class DialogHostKt {
+ method @androidx.compose.runtime.Composable public static void DialogHost(androidx.navigation.compose.DialogNavigator dialogNavigator);
+ }
+
+ @androidx.navigation.Navigator.Name("dialog") public final class DialogNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.DialogNavigator.Destination> {
+ ctor public DialogNavigator();
+ method public androidx.navigation.compose.DialogNavigator.Destination createDestination();
+ }
+
+ @androidx.navigation.NavDestination.ClassType(Composable::class) public static final class DialogNavigator.Destination extends androidx.navigation.NavDestination implements androidx.navigation.FloatingWindow {
+ ctor public DialogNavigator.Destination(androidx.navigation.compose.DialogNavigator navigator, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ }
+
+ public final class NavBackStackEntryProviderKt {
+ method @androidx.compose.runtime.Composable public static void LocalOwnersProvider(androidx.navigation.NavBackStackEntry, androidx.compose.runtime.saveable.SaveableStateHolder saveableStateHolder, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ public final class NavGraphBuilderKt {
+ method @Deprecated public static void composable(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ method public static void composable(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, optional kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition>? enterTransition, optional kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition>? exitTransition, optional kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition>? popEnterTransition, optional kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition>? popExitTransition, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedContentScope,? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ method public static void dialog(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ method public static void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition>? enterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition>? exitTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition>? popEnterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition>? popExitTransition, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavHostControllerKt {
+ method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<androidx.navigation.NavBackStackEntry> currentBackStackEntryAsState(androidx.navigation.NavController);
+ method @androidx.compose.runtime.Composable public static androidx.navigation.NavHostController rememberNavController(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>... navigators);
+ }
+
+ public final class NavHostKt {
+ method @Deprecated @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, androidx.navigation.NavGraph graph, optional androidx.compose.ui.Modifier modifier);
+ method @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, androidx.navigation.NavGraph graph, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.Alignment contentAlignment, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition> enterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition> exitTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition> popEnterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition> popExitTransition);
+ method @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, String startDestination, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.Alignment contentAlignment, optional String? route, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition> enterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition> exitTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.EnterTransition> popEnterTransition, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,? extends androidx.compose.animation.ExitTransition> popExitTransition, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, String startDestination, optional androidx.compose.ui.Modifier modifier, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ }
+
+}
+
diff --git a/navigation/navigation-compose/build.gradle b/navigation/navigation-compose/build.gradle
index 1b0b02e..0d6aae2 100644
--- a/navigation/navigation-compose/build.gradle
+++ b/navigation/navigation-compose/build.gradle
@@ -27,12 +27,12 @@
dependencies {
implementation(libs.kotlinStdlib)
- implementation(projectOrArtifact(":compose:foundation:foundation-layout"))
+ implementation("androidx.compose.foundation:foundation-layout:1.5.0-beta01")
api("androidx.activity:activity-compose:1.7.0")
- api(projectOrArtifact(":compose:animation:animation"))
- api(projectOrArtifact(":compose:runtime:runtime"))
- api(projectOrArtifact(":compose:runtime:runtime-saveable"))
- api(projectOrArtifact(":compose:ui:ui"))
+ api("androidx.compose.animation:animation:1.5.0-beta01")
+ api("androidx.compose.runtime:runtime:1.5.0-beta01")
+ api("androidx.compose.runtime:runtime-saveable:1.5.0-beta01")
+ api("androidx.compose.ui:ui:1.5.0-beta01")
api("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
api(projectOrArtifact(":navigation:navigation-runtime-ktx"))
diff --git a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
index 57ffee0..f73a52e 100644
--- a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
+++ b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
@@ -23,6 +23,7 @@
import android.os.Bundle
import androidx.activity.OnBackPressedDispatcher
import androidx.activity.OnBackPressedDispatcherOwner
+import androidx.activity.compose.BackHandler
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.animation.core.AnimationConstants.DefaultDurationMillis
import androidx.compose.foundation.layout.Column
@@ -1161,7 +1162,7 @@
composeTestRule.runOnIdle {
assertThat(onBackPressedDispatcher.hasEnabledCallbacks()).isFalse()
innerNavController.navigate("innerSecond")
- assertThat(onBackPressedDispatcher.hasEnabledCallbacks()).isTrue()
+ assertThat(onBackPressedDispatcher.hasEnabledCallbacks()).isFalse()
}
// Now navigate to a second destination in the outer NavHost
@@ -1228,6 +1229,49 @@
}
}
+ @Test
+ fun testPopWithBackHandler() {
+ lateinit var navController: NavHostController
+ var lifecycleOwner = TestLifecycleOwner(Lifecycle.State.RESUMED)
+ var backPressedDispatcher: OnBackPressedDispatcher? = null
+ var count = 0
+ var wasCalled = false
+ composeTestRule.setContent {
+ navController = rememberNavController()
+ backPressedDispatcher =
+ LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
+ CompositionLocalProvider(LocalLifecycleOwner provides lifecycleOwner) {
+ BackHandler { wasCalled = true }
+ NavHost(navController, startDestination = "first") {
+ composable("first") {
+ BackHandler { count++ }
+ }
+ }
+ }
+ }
+
+ composeTestRule.runOnUiThread {
+ backPressedDispatcher?.onBackPressed()
+ assertThat(count).isEqualTo(1)
+ }
+
+ // move to the back ground to unregister the BackHandlers
+ composeTestRule.runOnIdle {
+ lifecycleOwner.currentState = Lifecycle.State.CREATED
+ }
+
+ // register the BackHandlers again
+ composeTestRule.runOnIdle {
+ lifecycleOwner.currentState = Lifecycle.State.RESUMED
+ }
+
+ composeTestRule.runOnUiThread {
+ backPressedDispatcher?.onBackPressed()
+ assertThat(count).isEqualTo(2)
+ assertThat(wasCalled).isFalse()
+ }
+ }
+
private fun createNavController(context: Context): TestNavHostController {
val navController = TestNavHostController(context)
val navigator = TestNavigator()
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
index 210dd46..8ffef75 100644
--- a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
@@ -17,7 +17,7 @@
package androidx.navigation.compose
import android.annotation.SuppressLint
-import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
+import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform
@@ -199,23 +199,26 @@
val viewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
"NavHost requires a ViewModelStoreOwner to be provided via LocalViewModelStoreOwner"
}
- val onBackPressedDispatcherOwner = LocalOnBackPressedDispatcherOwner.current
- val onBackPressedDispatcher = onBackPressedDispatcherOwner?.onBackPressedDispatcher
+
+ // Intercept back only when there's a destination to pop
+ val currentBackStack by remember(navController.currentBackStack) {
+ navController.currentBackStack.map {
+ it.filter { entry ->
+ entry.destination.navigatorName == ComposeNavigator.NAME
+ }
+ }
+ }.collectAsState(emptyList())
+ BackHandler(currentBackStack.size > 1) {
+ navController.popBackStack()
+ }
// Setup the navController with proper owners
- navController.setLifecycleOwner(lifecycleOwner)
+ DisposableEffect(lifecycleOwner) {
+ // Setup the navController with proper owners
+ navController.setLifecycleOwner(lifecycleOwner)
+ onDispose { }
+ }
navController.setViewModelStore(viewModelStoreOwner.viewModelStore)
- if (onBackPressedDispatcher != null) {
- navController.setOnBackPressedDispatcher(onBackPressedDispatcher)
- }
- // Ensure that the NavController only receives back events while
- // the NavHost is in composition
- DisposableEffect(navController) {
- navController.enableOnBackPressed(true)
- onDispose {
- navController.enableOnBackPressed(false)
- }
- }
// Then set the graph
navController.graph = graph
diff --git a/navigation/navigation-dynamic-features-fragment/api/2.7.0-beta01.txt b/navigation/navigation-dynamic-features-fragment/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..adb3dae
--- /dev/null
+++ b/navigation/navigation-dynamic-features-fragment/api/2.7.0-beta01.txt
@@ -0,0 +1,69 @@
+// Signature format: 4.0
+package androidx.navigation.dynamicfeatures.fragment {
+
+ @androidx.navigation.Navigator.Name("fragment") public final class DynamicFragmentNavigator extends androidx.navigation.fragment.FragmentNavigator {
+ ctor public DynamicFragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager manager, int containerId, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+ method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination createDestination();
+ }
+
+ public static final class DynamicFragmentNavigator.Destination extends androidx.navigation.fragment.FragmentNavigator.Destination {
+ ctor public DynamicFragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> fragmentNavigator);
+ ctor public DynamicFragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public String? getModuleName();
+ method public void setModuleName(String?);
+ property public final String? moduleName;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class DynamicFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
+ ctor @Deprecated public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, @IdRes int id, String fragmentClassName);
+ ctor public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, String route, String fragmentClassName);
+ method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination build();
+ method public String? getModuleName();
+ method public void setModuleName(String?);
+ property public final String? moduleName;
+ }
+
+ public final class DynamicFragmentNavigatorDestinationBuilderKt {
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id);
+ method @Deprecated public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route);
+ method public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ }
+
+ public class DynamicNavHostFragment extends androidx.navigation.fragment.NavHostFragment {
+ ctor public DynamicNavHostFragment();
+ method public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId);
+ method public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+ method protected com.google.android.play.core.splitinstall.SplitInstallManager createSplitInstallManager();
+ field public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment.Companion Companion;
+ }
+
+ public static final class DynamicNavHostFragment.Companion {
+ method public androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId);
+ method public androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+ }
+
+}
+
+package androidx.navigation.dynamicfeatures.fragment.ui {
+
+ public abstract class AbstractProgressFragment extends androidx.fragment.app.Fragment {
+ ctor public AbstractProgressFragment();
+ ctor public AbstractProgressFragment(int contentLayoutId);
+ method protected abstract void onCancelled();
+ method protected abstract void onFailed(@com.google.android.play.core.splitinstall.model.SplitInstallErrorCode int errorCode);
+ method protected void onInstalled();
+ method protected abstract void onProgress(@com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus int status, long bytesDownloaded, long bytesTotal);
+ }
+
+ public final class DefaultProgressFragment extends androidx.navigation.dynamicfeatures.fragment.ui.AbstractProgressFragment {
+ ctor public DefaultProgressFragment();
+ method protected void onCancelled();
+ method protected void onFailed(@com.google.android.play.core.splitinstall.model.SplitInstallErrorCode int errorCode);
+ method protected void onProgress(int status, long bytesDownloaded, long bytesTotal);
+ }
+
+}
+
diff --git a/navigation/navigation-dynamic-features-fragment/api/res-2.7.0-beta01.txt b/navigation/navigation-dynamic-features-fragment/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-dynamic-features-fragment/api/res-2.7.0-beta01.txt
diff --git a/navigation/navigation-dynamic-features-fragment/api/restricted_2.7.0-beta01.txt b/navigation/navigation-dynamic-features-fragment/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..adb3dae
--- /dev/null
+++ b/navigation/navigation-dynamic-features-fragment/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1,69 @@
+// Signature format: 4.0
+package androidx.navigation.dynamicfeatures.fragment {
+
+ @androidx.navigation.Navigator.Name("fragment") public final class DynamicFragmentNavigator extends androidx.navigation.fragment.FragmentNavigator {
+ ctor public DynamicFragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager manager, int containerId, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+ method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination createDestination();
+ }
+
+ public static final class DynamicFragmentNavigator.Destination extends androidx.navigation.fragment.FragmentNavigator.Destination {
+ ctor public DynamicFragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> fragmentNavigator);
+ ctor public DynamicFragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public String? getModuleName();
+ method public void setModuleName(String?);
+ property public final String? moduleName;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class DynamicFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
+ ctor @Deprecated public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, @IdRes int id, String fragmentClassName);
+ ctor public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, String route, String fragmentClassName);
+ method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination build();
+ method public String? getModuleName();
+ method public void setModuleName(String?);
+ property public final String? moduleName;
+ }
+
+ public final class DynamicFragmentNavigatorDestinationBuilderKt {
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id);
+ method @Deprecated public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route);
+ method public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ }
+
+ public class DynamicNavHostFragment extends androidx.navigation.fragment.NavHostFragment {
+ ctor public DynamicNavHostFragment();
+ method public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId);
+ method public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+ method protected com.google.android.play.core.splitinstall.SplitInstallManager createSplitInstallManager();
+ field public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment.Companion Companion;
+ }
+
+ public static final class DynamicNavHostFragment.Companion {
+ method public androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId);
+ method public androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+ }
+
+}
+
+package androidx.navigation.dynamicfeatures.fragment.ui {
+
+ public abstract class AbstractProgressFragment extends androidx.fragment.app.Fragment {
+ ctor public AbstractProgressFragment();
+ ctor public AbstractProgressFragment(int contentLayoutId);
+ method protected abstract void onCancelled();
+ method protected abstract void onFailed(@com.google.android.play.core.splitinstall.model.SplitInstallErrorCode int errorCode);
+ method protected void onInstalled();
+ method protected abstract void onProgress(@com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus int status, long bytesDownloaded, long bytesTotal);
+ }
+
+ public final class DefaultProgressFragment extends androidx.navigation.dynamicfeatures.fragment.ui.AbstractProgressFragment {
+ ctor public DefaultProgressFragment();
+ method protected void onCancelled();
+ method protected void onFailed(@com.google.android.play.core.splitinstall.model.SplitInstallErrorCode int errorCode);
+ method protected void onProgress(int status, long bytesDownloaded, long bytesTotal);
+ }
+
+}
+
diff --git a/navigation/navigation-dynamic-features-runtime/api/2.7.0-beta01.txt b/navigation/navigation-dynamic-features-runtime/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..ff4252b
--- /dev/null
+++ b/navigation/navigation-dynamic-features-runtime/api/2.7.0-beta01.txt
@@ -0,0 +1,154 @@
+// Signature format: 4.0
+package androidx.navigation.dynamicfeatures {
+
+ @androidx.navigation.Navigator.Name("activity") public final class DynamicActivityNavigator extends androidx.navigation.ActivityNavigator {
+ ctor public DynamicActivityNavigator(android.content.Context context, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+ method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination createDestination();
+ }
+
+ public static final class DynamicActivityNavigator.Destination extends androidx.navigation.ActivityNavigator.Destination {
+ ctor public DynamicActivityNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.ActivityNavigator.Destination> activityNavigator);
+ ctor public DynamicActivityNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public String? getModuleName();
+ method public void setModuleName(String?);
+ property public final String? moduleName;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class DynamicActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
+ ctor @Deprecated public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, @IdRes int id);
+ ctor public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, String route);
+ method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination build();
+ method public String? getAction();
+ method public String? getActivityClassName();
+ method public android.net.Uri? getData();
+ method public String? getDataPattern();
+ method public String? getModuleName();
+ method public String? getTargetPackage();
+ method public void setAction(String?);
+ method public void setActivityClassName(String?);
+ method public void setData(android.net.Uri?);
+ method public void setDataPattern(String?);
+ method public void setModuleName(String?);
+ method public void setTargetPackage(String?);
+ property public final String? action;
+ property public final String? activityClassName;
+ property public final android.net.Uri? data;
+ property public final String? dataPattern;
+ property public final String? moduleName;
+ property public final String? targetPackage;
+ }
+
+ public final class DynamicActivityNavigatorDestinationBuilderKt {
+ method @Deprecated public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ }
+
+ public final class DynamicExtras implements androidx.navigation.Navigator.Extras {
+ ctor public DynamicExtras();
+ ctor public DynamicExtras(optional androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor);
+ ctor public DynamicExtras(optional androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor, optional androidx.navigation.Navigator.Extras? destinationExtras);
+ method public androidx.navigation.Navigator.Extras? getDestinationExtras();
+ method public androidx.navigation.dynamicfeatures.DynamicInstallMonitor? getInstallMonitor();
+ property public final androidx.navigation.Navigator.Extras? destinationExtras;
+ property public final androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor;
+ }
+
+ @androidx.navigation.Navigator.Name("navigation") public final class DynamicGraphNavigator extends androidx.navigation.NavGraphNavigator {
+ ctor public DynamicGraphNavigator(androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+ method public androidx.navigation.dynamicfeatures.DynamicGraphNavigator.DynamicNavGraph createDestination();
+ method public void installDefaultProgressDestination(kotlin.jvm.functions.Function0<? extends androidx.navigation.NavDestination> progressDestinationSupplier);
+ }
+
+ public static final class DynamicGraphNavigator.DynamicNavGraph extends androidx.navigation.NavGraph {
+ ctor public DynamicGraphNavigator.DynamicNavGraph(androidx.navigation.dynamicfeatures.DynamicGraphNavigator navGraphNavigator, androidx.navigation.NavigatorProvider navigatorProvider);
+ method public String? getModuleName();
+ method public int getProgressDestination();
+ method public void setModuleName(String?);
+ method public void setProgressDestination(int);
+ property public final String? moduleName;
+ property public final int progressDestination;
+ }
+
+ @androidx.navigation.Navigator.Name("include-dynamic") public final class DynamicIncludeGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
+ ctor public DynamicIncludeGraphNavigator(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.NavInflater navInflater, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+ method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph createDestination();
+ }
+
+ public static final class DynamicIncludeGraphNavigator.DynamicIncludeNavGraph extends androidx.navigation.NavDestination {
+ method public String? getGraphPackage();
+ method public String? getGraphResourceName();
+ method public String? getModuleName();
+ method public void setGraphPackage(String?);
+ method public void setGraphResourceName(String?);
+ method public void setModuleName(String?);
+ property public final String? graphPackage;
+ property public final String? graphResourceName;
+ property public final String? moduleName;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class DynamicIncludeNavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
+ ctor @Deprecated public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, @IdRes int id, String moduleName, String graphResourceName);
+ ctor public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, String route, String moduleName, String graphResourceName);
+ method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph build();
+ method public String? getGraphPackage();
+ method public void setGraphPackage(String?);
+ property public final String? graphPackage;
+ }
+
+ public final class DynamicIncludeNavGraphBuilderKt {
+ method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName);
+ method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName);
+ method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public class DynamicInstallManager {
+ ctor public DynamicInstallManager(android.content.Context context, com.google.android.play.core.splitinstall.SplitInstallManager splitInstallManager);
+ }
+
+ public final class DynamicInstallMonitor {
+ ctor public DynamicInstallMonitor();
+ method public void cancelInstall();
+ method public Exception? getException();
+ method public int getSessionId();
+ method public androidx.lifecycle.LiveData<com.google.android.play.core.splitinstall.SplitInstallSessionState> getStatus();
+ method public boolean isInstallRequired();
+ property public final Exception? exception;
+ property public final boolean isInstallRequired;
+ property public final int sessionId;
+ property public final androidx.lifecycle.LiveData<com.google.android.play.core.splitinstall.SplitInstallSessionState> status;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class DynamicNavGraphBuilder extends androidx.navigation.NavGraphBuilder {
+ ctor @Deprecated public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+ ctor public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, optional String? route);
+ method public String? getModuleName();
+ method public int getProgressDestination();
+ method public String? getProgressDestinationRoute();
+ method public void setModuleName(String?);
+ method public void setProgressDestination(int);
+ method public void setProgressDestinationRoute(String?);
+ property public final String? moduleName;
+ property public final int progressDestination;
+ property public final String? progressDestinationRoute;
+ }
+
+ public final class DynamicNavGraphBuilderKt {
+ method @Deprecated public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavControllerKt {
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavHostKt {
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ }
+
+}
+
diff --git a/navigation/navigation-dynamic-features-runtime/api/res-2.7.0-beta01.txt b/navigation/navigation-dynamic-features-runtime/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-dynamic-features-runtime/api/res-2.7.0-beta01.txt
diff --git a/navigation/navigation-dynamic-features-runtime/api/restricted_2.7.0-beta01.txt b/navigation/navigation-dynamic-features-runtime/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..ff4252b
--- /dev/null
+++ b/navigation/navigation-dynamic-features-runtime/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1,154 @@
+// Signature format: 4.0
+package androidx.navigation.dynamicfeatures {
+
+ @androidx.navigation.Navigator.Name("activity") public final class DynamicActivityNavigator extends androidx.navigation.ActivityNavigator {
+ ctor public DynamicActivityNavigator(android.content.Context context, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+ method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination createDestination();
+ }
+
+ public static final class DynamicActivityNavigator.Destination extends androidx.navigation.ActivityNavigator.Destination {
+ ctor public DynamicActivityNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.ActivityNavigator.Destination> activityNavigator);
+ ctor public DynamicActivityNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public String? getModuleName();
+ method public void setModuleName(String?);
+ property public final String? moduleName;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class DynamicActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
+ ctor @Deprecated public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, @IdRes int id);
+ ctor public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, String route);
+ method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination build();
+ method public String? getAction();
+ method public String? getActivityClassName();
+ method public android.net.Uri? getData();
+ method public String? getDataPattern();
+ method public String? getModuleName();
+ method public String? getTargetPackage();
+ method public void setAction(String?);
+ method public void setActivityClassName(String?);
+ method public void setData(android.net.Uri?);
+ method public void setDataPattern(String?);
+ method public void setModuleName(String?);
+ method public void setTargetPackage(String?);
+ property public final String? action;
+ property public final String? activityClassName;
+ property public final android.net.Uri? data;
+ property public final String? dataPattern;
+ property public final String? moduleName;
+ property public final String? targetPackage;
+ }
+
+ public final class DynamicActivityNavigatorDestinationBuilderKt {
+ method @Deprecated public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ }
+
+ public final class DynamicExtras implements androidx.navigation.Navigator.Extras {
+ ctor public DynamicExtras();
+ ctor public DynamicExtras(optional androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor);
+ ctor public DynamicExtras(optional androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor, optional androidx.navigation.Navigator.Extras? destinationExtras);
+ method public androidx.navigation.Navigator.Extras? getDestinationExtras();
+ method public androidx.navigation.dynamicfeatures.DynamicInstallMonitor? getInstallMonitor();
+ property public final androidx.navigation.Navigator.Extras? destinationExtras;
+ property public final androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor;
+ }
+
+ @androidx.navigation.Navigator.Name("navigation") public final class DynamicGraphNavigator extends androidx.navigation.NavGraphNavigator {
+ ctor public DynamicGraphNavigator(androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+ method public androidx.navigation.dynamicfeatures.DynamicGraphNavigator.DynamicNavGraph createDestination();
+ method public void installDefaultProgressDestination(kotlin.jvm.functions.Function0<? extends androidx.navigation.NavDestination> progressDestinationSupplier);
+ }
+
+ public static final class DynamicGraphNavigator.DynamicNavGraph extends androidx.navigation.NavGraph {
+ ctor public DynamicGraphNavigator.DynamicNavGraph(androidx.navigation.dynamicfeatures.DynamicGraphNavigator navGraphNavigator, androidx.navigation.NavigatorProvider navigatorProvider);
+ method public String? getModuleName();
+ method public int getProgressDestination();
+ method public void setModuleName(String?);
+ method public void setProgressDestination(int);
+ property public final String? moduleName;
+ property public final int progressDestination;
+ }
+
+ @androidx.navigation.Navigator.Name("include-dynamic") public final class DynamicIncludeGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
+ ctor public DynamicIncludeGraphNavigator(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.NavInflater navInflater, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+ method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph createDestination();
+ }
+
+ public static final class DynamicIncludeGraphNavigator.DynamicIncludeNavGraph extends androidx.navigation.NavDestination {
+ method public String? getGraphPackage();
+ method public String? getGraphResourceName();
+ method public String? getModuleName();
+ method public void setGraphPackage(String?);
+ method public void setGraphResourceName(String?);
+ method public void setModuleName(String?);
+ property public final String? graphPackage;
+ property public final String? graphResourceName;
+ property public final String? moduleName;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class DynamicIncludeNavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
+ ctor @Deprecated public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, @IdRes int id, String moduleName, String graphResourceName);
+ ctor public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, String route, String moduleName, String graphResourceName);
+ method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph build();
+ method public String? getGraphPackage();
+ method public void setGraphPackage(String?);
+ property public final String? graphPackage;
+ }
+
+ public final class DynamicIncludeNavGraphBuilderKt {
+ method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName);
+ method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName);
+ method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public class DynamicInstallManager {
+ ctor public DynamicInstallManager(android.content.Context context, com.google.android.play.core.splitinstall.SplitInstallManager splitInstallManager);
+ }
+
+ public final class DynamicInstallMonitor {
+ ctor public DynamicInstallMonitor();
+ method public void cancelInstall();
+ method public Exception? getException();
+ method public int getSessionId();
+ method public androidx.lifecycle.LiveData<com.google.android.play.core.splitinstall.SplitInstallSessionState> getStatus();
+ method public boolean isInstallRequired();
+ property public final Exception? exception;
+ property public final boolean isInstallRequired;
+ property public final int sessionId;
+ property public final androidx.lifecycle.LiveData<com.google.android.play.core.splitinstall.SplitInstallSessionState> status;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class DynamicNavGraphBuilder extends androidx.navigation.NavGraphBuilder {
+ ctor @Deprecated public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+ ctor public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, optional String? route);
+ method public String? getModuleName();
+ method public int getProgressDestination();
+ method public String? getProgressDestinationRoute();
+ method public void setModuleName(String?);
+ method public void setProgressDestination(int);
+ method public void setProgressDestinationRoute(String?);
+ property public final String? moduleName;
+ property public final int progressDestination;
+ property public final String? progressDestinationRoute;
+ }
+
+ public final class DynamicNavGraphBuilderKt {
+ method @Deprecated public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavControllerKt {
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavHostKt {
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ }
+
+}
+
diff --git a/navigation/navigation-dynamic-features-runtime/lint-baseline.xml b/navigation/navigation-dynamic-features-runtime/lint-baseline.xml
deleted file mode 100644
index 065e679..0000000
--- a/navigation/navigation-dynamic-features-runtime/lint-baseline.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public object Constants {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/dynamicfeatures/Constants.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" internal val navGraphNavigator: DynamicGraphNavigator,"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/dynamicfeatures/DynamicGraphNavigator.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" internal val navGraphNavigator: DynamicGraphNavigator,"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/dynamicfeatures/DynamicGraphNavigator.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" internal val navGraphNavigator: DynamicGraphNavigator,"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/dynamicfeatures/DynamicGraphNavigator.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" internal val navigatorProvider: NavigatorProvider"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/dynamicfeatures/DynamicGraphNavigator.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" internal val navigatorProvider: NavigatorProvider"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/dynamicfeatures/DynamicGraphNavigator.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" internal val navigatorProvider: NavigatorProvider"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/dynamicfeatures/DynamicGraphNavigator.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public fun performInstall("
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallManager.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public fun needsInstall(module: String): Boolean {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallManager.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public var splitInstallManager: SplitInstallManager? = null"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallMonitor.kt"/>
- </issue>
-
-</issues>
diff --git a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/Constants.kt b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/Constants.kt
index 0f4ffcb..30fd5da 100644
--- a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/Constants.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/Constants.kt
@@ -20,8 +20,6 @@
/**
* Internal constants for dynamic feature navigator.
- *
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public object Constants {
diff --git a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicGraphNavigator.kt b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicGraphNavigator.kt
index 82f1315..77a154d 100644
--- a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicGraphNavigator.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicGraphNavigator.kt
@@ -180,14 +180,8 @@
* The [NavGraph] for dynamic features.
*/
public class DynamicNavGraph(
- /**
- * @hide
- */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
internal val navGraphNavigator: DynamicGraphNavigator,
- /**
- * @hide
- */
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
internal val navigatorProvider: NavigatorProvider
) : NavGraph(navGraphNavigator) {
diff --git a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallManager.kt b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallManager.kt
index 1670b75..86855bc 100644
--- a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallManager.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallManager.kt
@@ -59,9 +59,6 @@
}
}
- /**
- * @hide
- */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public fun performInstall(
backStackEntry: NavBackStackEntry,
@@ -93,7 +90,6 @@
/**
* @param module The module to install.
* @return Whether the requested module needs installation.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public fun needsInstall(module: String): Boolean {
diff --git a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallMonitor.kt b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallMonitor.kt
index 77b4f71..266a82d 100644
--- a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallMonitor.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallMonitor.kt
@@ -68,8 +68,8 @@
/**
* The [SplitInstallManager] used to monitor the installation if any was set.
- * @hide
*/
+ @set:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public var splitInstallManager: SplitInstallManager? = null
diff --git a/navigation/navigation-fragment-ktx/api/2.7.0-beta01.txt b/navigation/navigation-fragment-ktx/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-fragment-ktx/api/2.7.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-fragment-ktx/api/res-2.7.0-beta01.txt b/navigation/navigation-fragment-ktx/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-fragment-ktx/api/res-2.7.0-beta01.txt
diff --git a/navigation/navigation-fragment-ktx/api/restricted_2.7.0-beta01.txt b/navigation/navigation-fragment-ktx/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-fragment-ktx/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-fragment/api/2.7.0-beta01.txt b/navigation/navigation-fragment/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..e9cbc61
--- /dev/null
+++ b/navigation/navigation-fragment/api/2.7.0-beta01.txt
@@ -0,0 +1,125 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+ public final class NavGraphViewModelLazyKt {
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> navGraphViewModels(androidx.fragment.app.Fragment, @IdRes int navGraphId, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+ method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> navGraphViewModels(androidx.fragment.app.Fragment, @IdRes int navGraphId, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> navGraphViewModels(androidx.fragment.app.Fragment, String navGraphRoute, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+ method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> navGraphViewModels(androidx.fragment.app.Fragment, String navGraphRoute, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+ }
+
+}
+
+package androidx.navigation.fragment {
+
+ public abstract class AbstractListDetailFragment extends androidx.fragment.app.Fragment {
+ ctor public AbstractListDetailFragment();
+ method public final androidx.navigation.fragment.NavHostFragment getDetailPaneNavHostFragment();
+ method public final androidx.slidingpanelayout.widget.SlidingPaneLayout getSlidingPaneLayout();
+ method public androidx.navigation.fragment.NavHostFragment onCreateDetailPaneNavHostFragment();
+ method public abstract android.view.View onCreateListPaneView(android.view.LayoutInflater inflater, android.view.ViewGroup? container, android.os.Bundle? savedInstanceState);
+ method @CallSuper public final android.view.View onCreateView(android.view.LayoutInflater inflater, android.view.ViewGroup? container, android.os.Bundle? savedInstanceState);
+ method public void onListPaneViewCreated(android.view.View view, android.os.Bundle? savedInstanceState);
+ method @CallSuper public final void onViewCreated(android.view.View view, android.os.Bundle? savedInstanceState);
+ property public final androidx.navigation.fragment.NavHostFragment detailPaneNavHostFragment;
+ property public final androidx.slidingpanelayout.widget.SlidingPaneLayout slidingPaneLayout;
+ }
+
+ @androidx.navigation.Navigator.Name("dialog") public final class DialogFragmentNavigator extends androidx.navigation.Navigator<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
+ ctor public DialogFragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager);
+ method public androidx.navigation.fragment.DialogFragmentNavigator.Destination createDestination();
+ }
+
+ @androidx.navigation.NavDestination.ClassType(DialogFragment::class) public static class DialogFragmentNavigator.Destination extends androidx.navigation.NavDestination implements androidx.navigation.FloatingWindow {
+ ctor public DialogFragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.DialogFragmentNavigator.Destination> fragmentNavigator);
+ ctor public DialogFragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public final String getClassName();
+ method public final androidx.navigation.fragment.DialogFragmentNavigator.Destination setClassName(String className);
+ property public final String className;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class DialogFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
+ ctor @Deprecated public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+ ctor public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+ method public androidx.navigation.fragment.DialogFragmentNavigator.Destination build();
+ }
+
+ public final class DialogFragmentNavigatorDestinationBuilderKt {
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id);
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route);
+ method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ }
+
+ public final class FragmentKt {
+ method public static androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment);
+ }
+
+ public final class FragmentNavArgsLazyKt {
+ method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args> navArgs(androidx.fragment.app.Fragment);
+ }
+
+ @androidx.navigation.Navigator.Name("fragment") public class FragmentNavigator extends androidx.navigation.Navigator<androidx.navigation.fragment.FragmentNavigator.Destination> {
+ ctor public FragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager, int containerId);
+ method public androidx.navigation.fragment.FragmentNavigator.Destination createDestination();
+ method @Deprecated public androidx.fragment.app.Fragment instantiateFragment(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager, String className, android.os.Bundle? args);
+ }
+
+ @androidx.navigation.NavDestination.ClassType(Fragment::class) public static class FragmentNavigator.Destination extends androidx.navigation.NavDestination {
+ ctor public FragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> fragmentNavigator);
+ ctor public FragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public final String getClassName();
+ method public final androidx.navigation.fragment.FragmentNavigator.Destination setClassName(String className);
+ property public final String className;
+ }
+
+ public static final class FragmentNavigator.Extras implements androidx.navigation.Navigator.Extras {
+ method public java.util.Map<android.view.View,java.lang.String> getSharedElements();
+ property public final java.util.Map<android.view.View,java.lang.String> sharedElements;
+ }
+
+ public static final class FragmentNavigator.Extras.Builder {
+ ctor public FragmentNavigator.Extras.Builder();
+ method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElement(android.view.View sharedElement, String name);
+ method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElements(java.util.Map<android.view.View,java.lang.String> sharedElements);
+ method public androidx.navigation.fragment.FragmentNavigator.Extras build();
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class FragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
+ ctor @Deprecated public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+ ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+ method public androidx.navigation.fragment.FragmentNavigator.Destination build();
+ }
+
+ public final class FragmentNavigatorDestinationBuilderKt {
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id);
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.FragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, String route);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.FragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ }
+
+ public final class FragmentNavigatorExtrasKt {
+ method public static androidx.navigation.fragment.FragmentNavigator.Extras FragmentNavigatorExtras(kotlin.Pair<? extends android.view.View,java.lang.String>... sharedElements);
+ }
+
+ public class NavHostFragment extends androidx.fragment.app.Fragment implements androidx.navigation.NavHost {
+ ctor public NavHostFragment();
+ method public static final androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId);
+ method public static final androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+ method @Deprecated protected androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> createFragmentNavigator();
+ method public static final androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment fragment);
+ method public final androidx.navigation.NavController getNavController();
+ method @Deprecated @CallSuper protected void onCreateNavController(androidx.navigation.NavController navController);
+ method @CallSuper protected void onCreateNavHostController(androidx.navigation.NavHostController navHostController);
+ property public final androidx.navigation.NavController navController;
+ field public static final androidx.navigation.fragment.NavHostFragment.Companion Companion;
+ }
+
+ public static final class NavHostFragment.Companion {
+ method public androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId);
+ method public androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+ method public androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment fragment);
+ }
+
+}
+
diff --git a/navigation/navigation-fragment/api/res-2.7.0-beta01.txt b/navigation/navigation-fragment/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-fragment/api/res-2.7.0-beta01.txt
diff --git a/navigation/navigation-fragment/api/restricted_2.7.0-beta01.txt b/navigation/navigation-fragment/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..e9cbc61
--- /dev/null
+++ b/navigation/navigation-fragment/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1,125 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+ public final class NavGraphViewModelLazyKt {
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> navGraphViewModels(androidx.fragment.app.Fragment, @IdRes int navGraphId, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+ method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> navGraphViewModels(androidx.fragment.app.Fragment, @IdRes int navGraphId, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> navGraphViewModels(androidx.fragment.app.Fragment, String navGraphRoute, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+ method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> navGraphViewModels(androidx.fragment.app.Fragment, String navGraphRoute, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+ }
+
+}
+
+package androidx.navigation.fragment {
+
+ public abstract class AbstractListDetailFragment extends androidx.fragment.app.Fragment {
+ ctor public AbstractListDetailFragment();
+ method public final androidx.navigation.fragment.NavHostFragment getDetailPaneNavHostFragment();
+ method public final androidx.slidingpanelayout.widget.SlidingPaneLayout getSlidingPaneLayout();
+ method public androidx.navigation.fragment.NavHostFragment onCreateDetailPaneNavHostFragment();
+ method public abstract android.view.View onCreateListPaneView(android.view.LayoutInflater inflater, android.view.ViewGroup? container, android.os.Bundle? savedInstanceState);
+ method @CallSuper public final android.view.View onCreateView(android.view.LayoutInflater inflater, android.view.ViewGroup? container, android.os.Bundle? savedInstanceState);
+ method public void onListPaneViewCreated(android.view.View view, android.os.Bundle? savedInstanceState);
+ method @CallSuper public final void onViewCreated(android.view.View view, android.os.Bundle? savedInstanceState);
+ property public final androidx.navigation.fragment.NavHostFragment detailPaneNavHostFragment;
+ property public final androidx.slidingpanelayout.widget.SlidingPaneLayout slidingPaneLayout;
+ }
+
+ @androidx.navigation.Navigator.Name("dialog") public final class DialogFragmentNavigator extends androidx.navigation.Navigator<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
+ ctor public DialogFragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager);
+ method public androidx.navigation.fragment.DialogFragmentNavigator.Destination createDestination();
+ }
+
+ @androidx.navigation.NavDestination.ClassType(DialogFragment::class) public static class DialogFragmentNavigator.Destination extends androidx.navigation.NavDestination implements androidx.navigation.FloatingWindow {
+ ctor public DialogFragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.DialogFragmentNavigator.Destination> fragmentNavigator);
+ ctor public DialogFragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public final String getClassName();
+ method public final androidx.navigation.fragment.DialogFragmentNavigator.Destination setClassName(String className);
+ property public final String className;
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class DialogFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
+ ctor @Deprecated public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+ ctor public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+ method public androidx.navigation.fragment.DialogFragmentNavigator.Destination build();
+ }
+
+ public final class DialogFragmentNavigatorDestinationBuilderKt {
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id);
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route);
+ method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ }
+
+ public final class FragmentKt {
+ method public static androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment);
+ }
+
+ public final class FragmentNavArgsLazyKt {
+ method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args> navArgs(androidx.fragment.app.Fragment);
+ }
+
+ @androidx.navigation.Navigator.Name("fragment") public class FragmentNavigator extends androidx.navigation.Navigator<androidx.navigation.fragment.FragmentNavigator.Destination> {
+ ctor public FragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager, int containerId);
+ method public androidx.navigation.fragment.FragmentNavigator.Destination createDestination();
+ method @Deprecated public androidx.fragment.app.Fragment instantiateFragment(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager, String className, android.os.Bundle? args);
+ }
+
+ @androidx.navigation.NavDestination.ClassType(Fragment::class) public static class FragmentNavigator.Destination extends androidx.navigation.NavDestination {
+ ctor public FragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> fragmentNavigator);
+ ctor public FragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public final String getClassName();
+ method public final androidx.navigation.fragment.FragmentNavigator.Destination setClassName(String className);
+ property public final String className;
+ }
+
+ public static final class FragmentNavigator.Extras implements androidx.navigation.Navigator.Extras {
+ method public java.util.Map<android.view.View,java.lang.String> getSharedElements();
+ property public final java.util.Map<android.view.View,java.lang.String> sharedElements;
+ }
+
+ public static final class FragmentNavigator.Extras.Builder {
+ ctor public FragmentNavigator.Extras.Builder();
+ method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElement(android.view.View sharedElement, String name);
+ method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElements(java.util.Map<android.view.View,java.lang.String> sharedElements);
+ method public androidx.navigation.fragment.FragmentNavigator.Extras build();
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class FragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
+ ctor @Deprecated public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+ ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+ method public androidx.navigation.fragment.FragmentNavigator.Destination build();
+ }
+
+ public final class FragmentNavigatorDestinationBuilderKt {
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id);
+ method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.FragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, String route);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.FragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ }
+
+ public final class FragmentNavigatorExtrasKt {
+ method public static androidx.navigation.fragment.FragmentNavigator.Extras FragmentNavigatorExtras(kotlin.Pair<? extends android.view.View,java.lang.String>... sharedElements);
+ }
+
+ public class NavHostFragment extends androidx.fragment.app.Fragment implements androidx.navigation.NavHost {
+ ctor public NavHostFragment();
+ method public static final androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId);
+ method public static final androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+ method @Deprecated protected androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> createFragmentNavigator();
+ method public static final androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment fragment);
+ method public final androidx.navigation.NavController getNavController();
+ method @Deprecated @CallSuper protected void onCreateNavController(androidx.navigation.NavController navController);
+ method @CallSuper protected void onCreateNavHostController(androidx.navigation.NavHostController navHostController);
+ property public final androidx.navigation.NavController navController;
+ field public static final androidx.navigation.fragment.NavHostFragment.Companion Companion;
+ }
+
+ public static final class NavHostFragment.Companion {
+ method public androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId);
+ method public androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+ method public androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment fragment);
+ }
+
+}
+
diff --git a/navigation/navigation-runtime-ktx/api/2.7.0-beta01.txt b/navigation/navigation-runtime-ktx/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-runtime-ktx/api/2.7.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-runtime-ktx/api/res-2.7.0-beta01.txt b/navigation/navigation-runtime-ktx/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-runtime-ktx/api/res-2.7.0-beta01.txt
diff --git a/navigation/navigation-runtime-ktx/api/restricted_2.7.0-beta01.txt b/navigation/navigation-runtime-ktx/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-runtime-ktx/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-runtime/api/2.7.0-beta01.txt b/navigation/navigation-runtime/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..2ec837e
--- /dev/null
+++ b/navigation/navigation-runtime/api/2.7.0-beta01.txt
@@ -0,0 +1,229 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+ public final class ActivityKt {
+ method public static androidx.navigation.NavController findNavController(android.app.Activity, @IdRes int viewId);
+ }
+
+ public final class ActivityNavArgsLazyKt {
+ method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args> navArgs(android.app.Activity);
+ }
+
+ @androidx.navigation.Navigator.Name("activity") public class ActivityNavigator extends androidx.navigation.Navigator<androidx.navigation.ActivityNavigator.Destination> {
+ ctor public ActivityNavigator(android.content.Context context);
+ method public static final void applyPopAnimationsToPendingTransition(android.app.Activity activity);
+ method public androidx.navigation.ActivityNavigator.Destination createDestination();
+ method public androidx.navigation.NavDestination? navigate(androidx.navigation.ActivityNavigator.Destination destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ field public static final androidx.navigation.ActivityNavigator.Companion Companion;
+ }
+
+ public static final class ActivityNavigator.Companion {
+ method public void applyPopAnimationsToPendingTransition(android.app.Activity activity);
+ }
+
+ @androidx.navigation.NavDestination.ClassType(Activity::class) public static class ActivityNavigator.Destination extends androidx.navigation.NavDestination {
+ ctor public ActivityNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.ActivityNavigator.Destination> activityNavigator);
+ ctor public ActivityNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public final String? getAction();
+ method public final android.content.ComponentName? getComponent();
+ method public final android.net.Uri? getData();
+ method public final String? getDataPattern();
+ method public final android.content.Intent? getIntent();
+ method public final String? getTargetPackage();
+ method public final androidx.navigation.ActivityNavigator.Destination setAction(String? action);
+ method public final androidx.navigation.ActivityNavigator.Destination setComponentName(android.content.ComponentName? name);
+ method public final androidx.navigation.ActivityNavigator.Destination setData(android.net.Uri? data);
+ method public final androidx.navigation.ActivityNavigator.Destination setDataPattern(String? dataPattern);
+ method public final androidx.navigation.ActivityNavigator.Destination setIntent(android.content.Intent? intent);
+ method public final androidx.navigation.ActivityNavigator.Destination setTargetPackage(String? packageName);
+ property public final String? action;
+ property public final android.content.ComponentName? component;
+ property public final android.net.Uri? data;
+ property public final String? dataPattern;
+ property public final android.content.Intent? intent;
+ property public final String? targetPackage;
+ }
+
+ public static final class ActivityNavigator.Extras implements androidx.navigation.Navigator.Extras {
+ method public androidx.core.app.ActivityOptionsCompat? getActivityOptions();
+ method public int getFlags();
+ property public final androidx.core.app.ActivityOptionsCompat? activityOptions;
+ property public final int flags;
+ }
+
+ public static final class ActivityNavigator.Extras.Builder {
+ ctor public ActivityNavigator.Extras.Builder();
+ method public androidx.navigation.ActivityNavigator.Extras.Builder addFlags(int flags);
+ method public androidx.navigation.ActivityNavigator.Extras build();
+ method public androidx.navigation.ActivityNavigator.Extras.Builder setActivityOptions(androidx.core.app.ActivityOptionsCompat activityOptions);
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class ActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
+ ctor @Deprecated public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
+ ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, String route);
+ method public androidx.navigation.ActivityNavigator.Destination build();
+ method public String? getAction();
+ method public kotlin.reflect.KClass<? extends android.app.Activity>? getActivityClass();
+ method public android.net.Uri? getData();
+ method public String? getDataPattern();
+ method public String? getTargetPackage();
+ method public void setAction(String?);
+ method public void setActivityClass(kotlin.reflect.KClass<? extends android.app.Activity>?);
+ method public void setData(android.net.Uri?);
+ method public void setDataPattern(String?);
+ method public void setTargetPackage(String?);
+ property public final String? action;
+ property public final kotlin.reflect.KClass<? extends android.app.Activity>? activityClass;
+ property public final android.net.Uri? data;
+ property public final String? dataPattern;
+ property public final String? targetPackage;
+ }
+
+ public final class ActivityNavigatorDestinationBuilderKt {
+ method @Deprecated public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline void activity(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ }
+
+ public final class ActivityNavigatorExtrasKt {
+ method public static androidx.navigation.ActivityNavigator.Extras ActivityNavigatorExtras(optional androidx.core.app.ActivityOptionsCompat? activityOptions, optional int flags);
+ }
+
+ public class NavController {
+ ctor public NavController(android.content.Context context);
+ method public void addOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener listener);
+ method @MainThread public final boolean clearBackStack(@IdRes int destinationId);
+ method @MainThread public final boolean clearBackStack(String route);
+ method public androidx.navigation.NavDeepLinkBuilder createDeepLink();
+ method @androidx.navigation.NavDeepLinkSaveStateControl public static final void enableDeepLinkSaveState(boolean saveState);
+ method public androidx.navigation.NavBackStackEntry getBackStackEntry(@IdRes int destinationId);
+ method public final androidx.navigation.NavBackStackEntry getBackStackEntry(String route);
+ method public androidx.navigation.NavBackStackEntry? getCurrentBackStackEntry();
+ method public final kotlinx.coroutines.flow.Flow<androidx.navigation.NavBackStackEntry> getCurrentBackStackEntryFlow();
+ method public androidx.navigation.NavDestination? getCurrentDestination();
+ method @MainThread public androidx.navigation.NavGraph getGraph();
+ method public androidx.navigation.NavInflater getNavInflater();
+ method public androidx.navigation.NavigatorProvider getNavigatorProvider();
+ method public androidx.navigation.NavBackStackEntry? getPreviousBackStackEntry();
+ method public androidx.lifecycle.ViewModelStoreOwner getViewModelStoreOwner(@IdRes int navGraphId);
+ method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getVisibleEntries();
+ method @MainThread public boolean handleDeepLink(android.content.Intent? intent);
+ method @MainThread public void navigate(android.net.Uri deepLink);
+ method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions);
+ method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request);
+ method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request, androidx.navigation.NavOptions? navOptions);
+ method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ method @MainThread public void navigate(androidx.navigation.NavDirections directions);
+ method @MainThread public void navigate(androidx.navigation.NavDirections directions, androidx.navigation.Navigator.Extras navigatorExtras);
+ method @MainThread public void navigate(androidx.navigation.NavDirections directions, androidx.navigation.NavOptions? navOptions);
+ method @MainThread public void navigate(@IdRes int resId);
+ method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args);
+ method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions);
+ method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ method @MainThread public final void navigate(String route);
+ method @MainThread public final void navigate(String route, optional androidx.navigation.NavOptions? navOptions);
+ method @MainThread public final void navigate(String route, optional androidx.navigation.NavOptions? navOptions, optional androidx.navigation.Navigator.Extras? navigatorExtras);
+ method @MainThread public final void navigate(String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> builder);
+ method @MainThread public boolean navigateUp();
+ method @MainThread public boolean popBackStack();
+ method @MainThread public boolean popBackStack(@IdRes int destinationId, boolean inclusive);
+ method @MainThread public boolean popBackStack(@IdRes int destinationId, boolean inclusive, boolean saveState);
+ method @MainThread public final boolean popBackStack(String route, boolean inclusive);
+ method @MainThread public final boolean popBackStack(String route, boolean inclusive, optional boolean saveState);
+ method public void removeOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener listener);
+ method @CallSuper public void restoreState(android.os.Bundle? navState);
+ method @CallSuper public android.os.Bundle? saveState();
+ method @CallSuper @MainThread public void setGraph(androidx.navigation.NavGraph);
+ method @CallSuper @MainThread public void setGraph(androidx.navigation.NavGraph graph, android.os.Bundle? startDestinationArgs);
+ method @CallSuper @MainThread public void setGraph(@NavigationRes int graphResId);
+ method @CallSuper @MainThread public void setGraph(@NavigationRes int graphResId, android.os.Bundle? startDestinationArgs);
+ property public androidx.navigation.NavBackStackEntry? currentBackStackEntry;
+ property public final kotlinx.coroutines.flow.Flow<androidx.navigation.NavBackStackEntry> currentBackStackEntryFlow;
+ property public androidx.navigation.NavDestination? currentDestination;
+ property @MainThread public androidx.navigation.NavGraph graph;
+ property public androidx.navigation.NavInflater navInflater;
+ property public androidx.navigation.NavigatorProvider navigatorProvider;
+ property public androidx.navigation.NavBackStackEntry? previousBackStackEntry;
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> visibleEntries;
+ field public static final androidx.navigation.NavController.Companion Companion;
+ field public static final String KEY_DEEP_LINK_INTENT = "android-support-nav:controller:deepLinkIntent";
+ }
+
+ public static final class NavController.Companion {
+ method @androidx.navigation.NavDeepLinkSaveStateControl public void enableDeepLinkSaveState(boolean saveState);
+ }
+
+ public static fun interface NavController.OnDestinationChangedListener {
+ method public void onDestinationChanged(androidx.navigation.NavController controller, androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+ }
+
+ public final class NavControllerKt {
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavDeepLinkBuilder {
+ ctor public NavDeepLinkBuilder(android.content.Context context);
+ method public androidx.navigation.NavDeepLinkBuilder addDestination(@IdRes int destId);
+ method public androidx.navigation.NavDeepLinkBuilder addDestination(@IdRes int destId, optional android.os.Bundle? args);
+ method public androidx.navigation.NavDeepLinkBuilder addDestination(String route);
+ method public androidx.navigation.NavDeepLinkBuilder addDestination(String route, optional android.os.Bundle? args);
+ method public android.app.PendingIntent createPendingIntent();
+ method public androidx.core.app.TaskStackBuilder createTaskStackBuilder();
+ method public androidx.navigation.NavDeepLinkBuilder setArguments(android.os.Bundle? args);
+ method public androidx.navigation.NavDeepLinkBuilder setComponentName(android.content.ComponentName componentName);
+ method public androidx.navigation.NavDeepLinkBuilder setComponentName(Class<? extends android.app.Activity> activityClass);
+ method public androidx.navigation.NavDeepLinkBuilder setDestination(@IdRes int destId);
+ method public androidx.navigation.NavDeepLinkBuilder setDestination(@IdRes int destId, optional android.os.Bundle? args);
+ method public androidx.navigation.NavDeepLinkBuilder setDestination(String destRoute);
+ method public androidx.navigation.NavDeepLinkBuilder setDestination(String destRoute, optional android.os.Bundle? args);
+ method public androidx.navigation.NavDeepLinkBuilder setGraph(androidx.navigation.NavGraph navGraph);
+ method public androidx.navigation.NavDeepLinkBuilder setGraph(@NavigationRes int navGraphId);
+ }
+
+ @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface NavDeepLinkSaveStateControl {
+ }
+
+ public interface NavHost {
+ method public androidx.navigation.NavController getNavController();
+ property public abstract androidx.navigation.NavController navController;
+ }
+
+ public class NavHostController extends androidx.navigation.NavController {
+ ctor public NavHostController(android.content.Context context);
+ method public final void enableOnBackPressed(boolean enabled);
+ method public final void setLifecycleOwner(androidx.lifecycle.LifecycleOwner owner);
+ method public final void setOnBackPressedDispatcher(androidx.activity.OnBackPressedDispatcher dispatcher);
+ method public final void setViewModelStore(androidx.lifecycle.ViewModelStore viewModelStore);
+ }
+
+ public final class NavHostKt {
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavInflater {
+ ctor public NavInflater(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider);
+ method public androidx.navigation.NavGraph inflate(@NavigationRes int graphResId);
+ field public static final androidx.navigation.NavInflater.Companion Companion;
+ }
+
+ public static final class NavInflater.Companion {
+ }
+
+ public final class Navigation {
+ method public static android.view.View.OnClickListener createNavigateOnClickListener(androidx.navigation.NavDirections directions);
+ method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int resId);
+ method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int resId, optional android.os.Bundle? args);
+ method public static androidx.navigation.NavController findNavController(android.app.Activity activity, @IdRes int viewId);
+ method public static androidx.navigation.NavController findNavController(android.view.View view);
+ method public static void setViewNavController(android.view.View view, androidx.navigation.NavController? controller);
+ field public static final androidx.navigation.Navigation INSTANCE;
+ }
+
+ public final class ViewKt {
+ method public static androidx.navigation.NavController findNavController(android.view.View);
+ }
+
+}
+
diff --git a/navigation/navigation-runtime/api/res-2.7.0-beta01.txt b/navigation/navigation-runtime/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-runtime/api/res-2.7.0-beta01.txt
diff --git a/navigation/navigation-runtime/api/restricted_2.7.0-beta01.txt b/navigation/navigation-runtime/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..2ec837e
--- /dev/null
+++ b/navigation/navigation-runtime/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1,229 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+ public final class ActivityKt {
+ method public static androidx.navigation.NavController findNavController(android.app.Activity, @IdRes int viewId);
+ }
+
+ public final class ActivityNavArgsLazyKt {
+ method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args> navArgs(android.app.Activity);
+ }
+
+ @androidx.navigation.Navigator.Name("activity") public class ActivityNavigator extends androidx.navigation.Navigator<androidx.navigation.ActivityNavigator.Destination> {
+ ctor public ActivityNavigator(android.content.Context context);
+ method public static final void applyPopAnimationsToPendingTransition(android.app.Activity activity);
+ method public androidx.navigation.ActivityNavigator.Destination createDestination();
+ method public androidx.navigation.NavDestination? navigate(androidx.navigation.ActivityNavigator.Destination destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ field public static final androidx.navigation.ActivityNavigator.Companion Companion;
+ }
+
+ public static final class ActivityNavigator.Companion {
+ method public void applyPopAnimationsToPendingTransition(android.app.Activity activity);
+ }
+
+ @androidx.navigation.NavDestination.ClassType(Activity::class) public static class ActivityNavigator.Destination extends androidx.navigation.NavDestination {
+ ctor public ActivityNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.ActivityNavigator.Destination> activityNavigator);
+ ctor public ActivityNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+ method public final String? getAction();
+ method public final android.content.ComponentName? getComponent();
+ method public final android.net.Uri? getData();
+ method public final String? getDataPattern();
+ method public final android.content.Intent? getIntent();
+ method public final String? getTargetPackage();
+ method public final androidx.navigation.ActivityNavigator.Destination setAction(String? action);
+ method public final androidx.navigation.ActivityNavigator.Destination setComponentName(android.content.ComponentName? name);
+ method public final androidx.navigation.ActivityNavigator.Destination setData(android.net.Uri? data);
+ method public final androidx.navigation.ActivityNavigator.Destination setDataPattern(String? dataPattern);
+ method public final androidx.navigation.ActivityNavigator.Destination setIntent(android.content.Intent? intent);
+ method public final androidx.navigation.ActivityNavigator.Destination setTargetPackage(String? packageName);
+ property public final String? action;
+ property public final android.content.ComponentName? component;
+ property public final android.net.Uri? data;
+ property public final String? dataPattern;
+ property public final android.content.Intent? intent;
+ property public final String? targetPackage;
+ }
+
+ public static final class ActivityNavigator.Extras implements androidx.navigation.Navigator.Extras {
+ method public androidx.core.app.ActivityOptionsCompat? getActivityOptions();
+ method public int getFlags();
+ property public final androidx.core.app.ActivityOptionsCompat? activityOptions;
+ property public final int flags;
+ }
+
+ public static final class ActivityNavigator.Extras.Builder {
+ ctor public ActivityNavigator.Extras.Builder();
+ method public androidx.navigation.ActivityNavigator.Extras.Builder addFlags(int flags);
+ method public androidx.navigation.ActivityNavigator.Extras build();
+ method public androidx.navigation.ActivityNavigator.Extras.Builder setActivityOptions(androidx.core.app.ActivityOptionsCompat activityOptions);
+ }
+
+ @androidx.navigation.NavDestinationDsl public final class ActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
+ ctor @Deprecated public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
+ ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, String route);
+ method public androidx.navigation.ActivityNavigator.Destination build();
+ method public String? getAction();
+ method public kotlin.reflect.KClass<? extends android.app.Activity>? getActivityClass();
+ method public android.net.Uri? getData();
+ method public String? getDataPattern();
+ method public String? getTargetPackage();
+ method public void setAction(String?);
+ method public void setActivityClass(kotlin.reflect.KClass<? extends android.app.Activity>?);
+ method public void setData(android.net.Uri?);
+ method public void setDataPattern(String?);
+ method public void setTargetPackage(String?);
+ property public final String? action;
+ property public final kotlin.reflect.KClass<? extends android.app.Activity>? activityClass;
+ property public final android.net.Uri? data;
+ property public final String? dataPattern;
+ property public final String? targetPackage;
+ }
+
+ public final class ActivityNavigatorDestinationBuilderKt {
+ method @Deprecated public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method public static inline void activity(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ }
+
+ public final class ActivityNavigatorExtrasKt {
+ method public static androidx.navigation.ActivityNavigator.Extras ActivityNavigatorExtras(optional androidx.core.app.ActivityOptionsCompat? activityOptions, optional int flags);
+ }
+
+ public class NavController {
+ ctor public NavController(android.content.Context context);
+ method public void addOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener listener);
+ method @MainThread public final boolean clearBackStack(@IdRes int destinationId);
+ method @MainThread public final boolean clearBackStack(String route);
+ method public androidx.navigation.NavDeepLinkBuilder createDeepLink();
+ method @androidx.navigation.NavDeepLinkSaveStateControl public static final void enableDeepLinkSaveState(boolean saveState);
+ method public androidx.navigation.NavBackStackEntry getBackStackEntry(@IdRes int destinationId);
+ method public final androidx.navigation.NavBackStackEntry getBackStackEntry(String route);
+ method public androidx.navigation.NavBackStackEntry? getCurrentBackStackEntry();
+ method public final kotlinx.coroutines.flow.Flow<androidx.navigation.NavBackStackEntry> getCurrentBackStackEntryFlow();
+ method public androidx.navigation.NavDestination? getCurrentDestination();
+ method @MainThread public androidx.navigation.NavGraph getGraph();
+ method public androidx.navigation.NavInflater getNavInflater();
+ method public androidx.navigation.NavigatorProvider getNavigatorProvider();
+ method public androidx.navigation.NavBackStackEntry? getPreviousBackStackEntry();
+ method public androidx.lifecycle.ViewModelStoreOwner getViewModelStoreOwner(@IdRes int navGraphId);
+ method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getVisibleEntries();
+ method @MainThread public boolean handleDeepLink(android.content.Intent? intent);
+ method @MainThread public void navigate(android.net.Uri deepLink);
+ method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions);
+ method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request);
+ method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request, androidx.navigation.NavOptions? navOptions);
+ method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ method @MainThread public void navigate(androidx.navigation.NavDirections directions);
+ method @MainThread public void navigate(androidx.navigation.NavDirections directions, androidx.navigation.Navigator.Extras navigatorExtras);
+ method @MainThread public void navigate(androidx.navigation.NavDirections directions, androidx.navigation.NavOptions? navOptions);
+ method @MainThread public void navigate(@IdRes int resId);
+ method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args);
+ method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions);
+ method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+ method @MainThread public final void navigate(String route);
+ method @MainThread public final void navigate(String route, optional androidx.navigation.NavOptions? navOptions);
+ method @MainThread public final void navigate(String route, optional androidx.navigation.NavOptions? navOptions, optional androidx.navigation.Navigator.Extras? navigatorExtras);
+ method @MainThread public final void navigate(String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> builder);
+ method @MainThread public boolean navigateUp();
+ method @MainThread public boolean popBackStack();
+ method @MainThread public boolean popBackStack(@IdRes int destinationId, boolean inclusive);
+ method @MainThread public boolean popBackStack(@IdRes int destinationId, boolean inclusive, boolean saveState);
+ method @MainThread public final boolean popBackStack(String route, boolean inclusive);
+ method @MainThread public final boolean popBackStack(String route, boolean inclusive, optional boolean saveState);
+ method public void removeOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener listener);
+ method @CallSuper public void restoreState(android.os.Bundle? navState);
+ method @CallSuper public android.os.Bundle? saveState();
+ method @CallSuper @MainThread public void setGraph(androidx.navigation.NavGraph);
+ method @CallSuper @MainThread public void setGraph(androidx.navigation.NavGraph graph, android.os.Bundle? startDestinationArgs);
+ method @CallSuper @MainThread public void setGraph(@NavigationRes int graphResId);
+ method @CallSuper @MainThread public void setGraph(@NavigationRes int graphResId, android.os.Bundle? startDestinationArgs);
+ property public androidx.navigation.NavBackStackEntry? currentBackStackEntry;
+ property public final kotlinx.coroutines.flow.Flow<androidx.navigation.NavBackStackEntry> currentBackStackEntryFlow;
+ property public androidx.navigation.NavDestination? currentDestination;
+ property @MainThread public androidx.navigation.NavGraph graph;
+ property public androidx.navigation.NavInflater navInflater;
+ property public androidx.navigation.NavigatorProvider navigatorProvider;
+ property public androidx.navigation.NavBackStackEntry? previousBackStackEntry;
+ property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> visibleEntries;
+ field public static final androidx.navigation.NavController.Companion Companion;
+ field public static final String KEY_DEEP_LINK_INTENT = "android-support-nav:controller:deepLinkIntent";
+ }
+
+ public static final class NavController.Companion {
+ method @androidx.navigation.NavDeepLinkSaveStateControl public void enableDeepLinkSaveState(boolean saveState);
+ }
+
+ public static fun interface NavController.OnDestinationChangedListener {
+ method public void onDestinationChanged(androidx.navigation.NavController controller, androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+ }
+
+ public final class NavControllerKt {
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavDeepLinkBuilder {
+ ctor public NavDeepLinkBuilder(android.content.Context context);
+ method public androidx.navigation.NavDeepLinkBuilder addDestination(@IdRes int destId);
+ method public androidx.navigation.NavDeepLinkBuilder addDestination(@IdRes int destId, optional android.os.Bundle? args);
+ method public androidx.navigation.NavDeepLinkBuilder addDestination(String route);
+ method public androidx.navigation.NavDeepLinkBuilder addDestination(String route, optional android.os.Bundle? args);
+ method public android.app.PendingIntent createPendingIntent();
+ method public androidx.core.app.TaskStackBuilder createTaskStackBuilder();
+ method public androidx.navigation.NavDeepLinkBuilder setArguments(android.os.Bundle? args);
+ method public androidx.navigation.NavDeepLinkBuilder setComponentName(android.content.ComponentName componentName);
+ method public androidx.navigation.NavDeepLinkBuilder setComponentName(Class<? extends android.app.Activity> activityClass);
+ method public androidx.navigation.NavDeepLinkBuilder setDestination(@IdRes int destId);
+ method public androidx.navigation.NavDeepLinkBuilder setDestination(@IdRes int destId, optional android.os.Bundle? args);
+ method public androidx.navigation.NavDeepLinkBuilder setDestination(String destRoute);
+ method public androidx.navigation.NavDeepLinkBuilder setDestination(String destRoute, optional android.os.Bundle? args);
+ method public androidx.navigation.NavDeepLinkBuilder setGraph(androidx.navigation.NavGraph navGraph);
+ method public androidx.navigation.NavDeepLinkBuilder setGraph(@NavigationRes int navGraphId);
+ }
+
+ @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface NavDeepLinkSaveStateControl {
+ }
+
+ public interface NavHost {
+ method public androidx.navigation.NavController getNavController();
+ property public abstract androidx.navigation.NavController navController;
+ }
+
+ public class NavHostController extends androidx.navigation.NavController {
+ ctor public NavHostController(android.content.Context context);
+ method public final void enableOnBackPressed(boolean enabled);
+ method public final void setLifecycleOwner(androidx.lifecycle.LifecycleOwner owner);
+ method public final void setOnBackPressedDispatcher(androidx.activity.OnBackPressedDispatcher dispatcher);
+ method public final void setViewModelStore(androidx.lifecycle.ViewModelStore viewModelStore);
+ }
+
+ public final class NavHostKt {
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ }
+
+ public final class NavInflater {
+ ctor public NavInflater(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider);
+ method public androidx.navigation.NavGraph inflate(@NavigationRes int graphResId);
+ field public static final androidx.navigation.NavInflater.Companion Companion;
+ }
+
+ public static final class NavInflater.Companion {
+ }
+
+ public final class Navigation {
+ method public static android.view.View.OnClickListener createNavigateOnClickListener(androidx.navigation.NavDirections directions);
+ method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int resId);
+ method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int resId, optional android.os.Bundle? args);
+ method public static androidx.navigation.NavController findNavController(android.app.Activity activity, @IdRes int viewId);
+ method public static androidx.navigation.NavController findNavController(android.view.View view);
+ method public static void setViewNavController(android.view.View view, androidx.navigation.NavController? controller);
+ field public static final androidx.navigation.Navigation INSTANCE;
+ }
+
+ public final class ViewKt {
+ method public static androidx.navigation.NavController findNavController(android.view.View);
+ }
+
+}
+
diff --git a/navigation/navigation-testing/api/2.7.0-beta01.txt b/navigation/navigation-testing/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..90caa3a
--- /dev/null
+++ b/navigation/navigation-testing/api/2.7.0-beta01.txt
@@ -0,0 +1,23 @@
+// Signature format: 4.0
+package androidx.navigation.testing {
+
+ public final class TestNavHostController extends androidx.navigation.NavHostController {
+ ctor public TestNavHostController(android.content.Context context);
+ method public java.util.List<androidx.navigation.NavBackStackEntry> getBackStack();
+ method public void setCurrentDestination(@IdRes int destId);
+ method public void setCurrentDestination(@IdRes int destId, optional android.os.Bundle args);
+ method public void setCurrentDestination(String destRoute);
+ method public void setCurrentDestination(String destRoute, optional android.os.Bundle args);
+ property public final java.util.List<androidx.navigation.NavBackStackEntry> backStack;
+ }
+
+ public final class TestNavigatorState extends androidx.navigation.NavigatorState {
+ ctor public TestNavigatorState();
+ ctor public TestNavigatorState(optional android.content.Context? context);
+ ctor public TestNavigatorState(optional android.content.Context? context, optional kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
+ method public androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+ method public androidx.navigation.NavBackStackEntry restoreBackStackEntry(androidx.navigation.NavBackStackEntry previouslySavedEntry);
+ }
+
+}
+
diff --git a/navigation/navigation-testing/api/res-2.7.0-beta01.txt b/navigation/navigation-testing/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-testing/api/res-2.7.0-beta01.txt
diff --git a/navigation/navigation-testing/api/restricted_2.7.0-beta01.txt b/navigation/navigation-testing/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..90caa3a
--- /dev/null
+++ b/navigation/navigation-testing/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1,23 @@
+// Signature format: 4.0
+package androidx.navigation.testing {
+
+ public final class TestNavHostController extends androidx.navigation.NavHostController {
+ ctor public TestNavHostController(android.content.Context context);
+ method public java.util.List<androidx.navigation.NavBackStackEntry> getBackStack();
+ method public void setCurrentDestination(@IdRes int destId);
+ method public void setCurrentDestination(@IdRes int destId, optional android.os.Bundle args);
+ method public void setCurrentDestination(String destRoute);
+ method public void setCurrentDestination(String destRoute, optional android.os.Bundle args);
+ property public final java.util.List<androidx.navigation.NavBackStackEntry> backStack;
+ }
+
+ public final class TestNavigatorState extends androidx.navigation.NavigatorState {
+ ctor public TestNavigatorState();
+ ctor public TestNavigatorState(optional android.content.Context? context);
+ ctor public TestNavigatorState(optional android.content.Context? context, optional kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
+ method public androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+ method public androidx.navigation.NavBackStackEntry restoreBackStackEntry(androidx.navigation.NavBackStackEntry previouslySavedEntry);
+ }
+
+}
+
diff --git a/navigation/navigation-ui-ktx/api/2.7.0-beta01.txt b/navigation/navigation-ui-ktx/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-ui-ktx/api/2.7.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-ui-ktx/api/res-2.7.0-beta01.txt b/navigation/navigation-ui-ktx/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-ui-ktx/api/res-2.7.0-beta01.txt
diff --git a/navigation/navigation-ui-ktx/api/restricted_2.7.0-beta01.txt b/navigation/navigation-ui-ktx/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-ui-ktx/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-ui/api/2.7.0-beta01.txt b/navigation/navigation-ui/api/2.7.0-beta01.txt
new file mode 100644
index 0000000..5094c7e
--- /dev/null
+++ b/navigation/navigation-ui/api/2.7.0-beta01.txt
@@ -0,0 +1,94 @@
+// Signature format: 4.0
+package androidx.navigation.ui {
+
+ public final class ActivityKt {
+ method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+ method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ }
+
+ public final class AppBarConfiguration {
+ method @Deprecated public androidx.drawerlayout.widget.DrawerLayout? getDrawerLayout();
+ method public androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? getFallbackOnNavigateUpListener();
+ method public androidx.customview.widget.Openable? getOpenableLayout();
+ method public java.util.Set<java.lang.Integer> getTopLevelDestinations();
+ method public boolean isTopLevelDestination(androidx.navigation.NavDestination destination);
+ property @Deprecated public final androidx.drawerlayout.widget.DrawerLayout? drawerLayout;
+ property public final androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? fallbackOnNavigateUpListener;
+ property public final androidx.customview.widget.Openable? openableLayout;
+ property public final java.util.Set<java.lang.Integer> topLevelDestinations;
+ }
+
+ public static final class AppBarConfiguration.Builder {
+ ctor public AppBarConfiguration.Builder(android.view.Menu topLevelMenu);
+ ctor public AppBarConfiguration.Builder(androidx.navigation.NavGraph navGraph);
+ ctor public AppBarConfiguration.Builder(int... topLevelDestinationIds);
+ ctor public AppBarConfiguration.Builder(java.util.Set<java.lang.Integer> topLevelDestinationIds);
+ method public androidx.navigation.ui.AppBarConfiguration build();
+ method @Deprecated public androidx.navigation.ui.AppBarConfiguration.Builder setDrawerLayout(androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+ method public androidx.navigation.ui.AppBarConfiguration.Builder setFallbackOnNavigateUpListener(androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? fallbackOnNavigateUpListener);
+ method public androidx.navigation.ui.AppBarConfiguration.Builder setOpenableLayout(androidx.customview.widget.Openable? openableLayout);
+ }
+
+ public static fun interface AppBarConfiguration.OnNavigateUpListener {
+ method public boolean onNavigateUp();
+ }
+
+ public final class AppBarConfigurationKt {
+ method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(android.view.Menu topLevelMenu, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+ method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(androidx.navigation.NavGraph navGraph, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+ method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(java.util.Set<java.lang.Integer> topLevelDestinationIds, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+ }
+
+ public final class BottomNavigationViewKt {
+ method public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView, androidx.navigation.NavController navController);
+ }
+
+ public final class CollapsingToolbarLayoutKt {
+ method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+ method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ }
+
+ public final class MenuItemKt {
+ method public static boolean onNavDestinationSelected(android.view.MenuItem, androidx.navigation.NavController navController);
+ }
+
+ public final class NavControllerKt {
+ method public static boolean navigateUp(androidx.navigation.NavController, androidx.customview.widget.Openable? drawerLayout);
+ method public static boolean navigateUp(androidx.navigation.NavController, androidx.navigation.ui.AppBarConfiguration appBarConfiguration);
+ }
+
+ public final class NavigationUI {
+ method public static boolean navigateUp(androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+ method public static boolean navigateUp(androidx.navigation.NavController navController, androidx.navigation.ui.AppBarConfiguration configuration);
+ method public static boolean onNavDestinationSelected(android.view.MenuItem item, androidx.navigation.NavController navController);
+ method @androidx.navigation.ui.NavigationUiSaveStateControl public static boolean onNavDestinationSelected(android.view.MenuItem item, androidx.navigation.NavController navController, boolean saveState);
+ method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController);
+ method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+ method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController);
+ method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+ method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController);
+ method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+ method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ method public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView navigationBarView, androidx.navigation.NavController navController);
+ method @androidx.navigation.ui.NavigationUiSaveStateControl public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView navigationBarView, androidx.navigation.NavController navController, boolean saveState);
+ method public static void setupWithNavController(com.google.android.material.navigation.NavigationView navigationView, androidx.navigation.NavController navController);
+ method @androidx.navigation.ui.NavigationUiSaveStateControl public static void setupWithNavController(com.google.android.material.navigation.NavigationView navigationView, androidx.navigation.NavController navController, boolean saveState);
+ field public static final androidx.navigation.ui.NavigationUI INSTANCE;
+ }
+
+ @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface NavigationUiSaveStateControl {
+ }
+
+ public final class NavigationViewKt {
+ method public static void setupWithNavController(com.google.android.material.navigation.NavigationView, androidx.navigation.NavController navController);
+ }
+
+ public final class ToolbarKt {
+ method public static void setupWithNavController(androidx.appcompat.widget.Toolbar, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+ method public static void setupWithNavController(androidx.appcompat.widget.Toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ }
+
+}
+
diff --git a/navigation/navigation-ui/api/res-2.7.0-beta01.txt b/navigation/navigation-ui/api/res-2.7.0-beta01.txt
new file mode 100644
index 0000000..e65fdbe
--- /dev/null
+++ b/navigation/navigation-ui/api/res-2.7.0-beta01.txt
@@ -0,0 +1,8 @@
+anim nav_default_enter_anim
+anim nav_default_exit_anim
+anim nav_default_pop_enter_anim
+anim nav_default_pop_exit_anim
+animator nav_default_enter_anim
+animator nav_default_exit_anim
+animator nav_default_pop_enter_anim
+animator nav_default_pop_exit_anim
diff --git a/navigation/navigation-ui/api/restricted_2.7.0-beta01.txt b/navigation/navigation-ui/api/restricted_2.7.0-beta01.txt
new file mode 100644
index 0000000..5094c7e
--- /dev/null
+++ b/navigation/navigation-ui/api/restricted_2.7.0-beta01.txt
@@ -0,0 +1,94 @@
+// Signature format: 4.0
+package androidx.navigation.ui {
+
+ public final class ActivityKt {
+ method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+ method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ }
+
+ public final class AppBarConfiguration {
+ method @Deprecated public androidx.drawerlayout.widget.DrawerLayout? getDrawerLayout();
+ method public androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? getFallbackOnNavigateUpListener();
+ method public androidx.customview.widget.Openable? getOpenableLayout();
+ method public java.util.Set<java.lang.Integer> getTopLevelDestinations();
+ method public boolean isTopLevelDestination(androidx.navigation.NavDestination destination);
+ property @Deprecated public final androidx.drawerlayout.widget.DrawerLayout? drawerLayout;
+ property public final androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? fallbackOnNavigateUpListener;
+ property public final androidx.customview.widget.Openable? openableLayout;
+ property public final java.util.Set<java.lang.Integer> topLevelDestinations;
+ }
+
+ public static final class AppBarConfiguration.Builder {
+ ctor public AppBarConfiguration.Builder(android.view.Menu topLevelMenu);
+ ctor public AppBarConfiguration.Builder(androidx.navigation.NavGraph navGraph);
+ ctor public AppBarConfiguration.Builder(int... topLevelDestinationIds);
+ ctor public AppBarConfiguration.Builder(java.util.Set<java.lang.Integer> topLevelDestinationIds);
+ method public androidx.navigation.ui.AppBarConfiguration build();
+ method @Deprecated public androidx.navigation.ui.AppBarConfiguration.Builder setDrawerLayout(androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+ method public androidx.navigation.ui.AppBarConfiguration.Builder setFallbackOnNavigateUpListener(androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? fallbackOnNavigateUpListener);
+ method public androidx.navigation.ui.AppBarConfiguration.Builder setOpenableLayout(androidx.customview.widget.Openable? openableLayout);
+ }
+
+ public static fun interface AppBarConfiguration.OnNavigateUpListener {
+ method public boolean onNavigateUp();
+ }
+
+ public final class AppBarConfigurationKt {
+ method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(android.view.Menu topLevelMenu, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+ method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(androidx.navigation.NavGraph navGraph, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+ method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(java.util.Set<java.lang.Integer> topLevelDestinationIds, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+ }
+
+ public final class BottomNavigationViewKt {
+ method public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView, androidx.navigation.NavController navController);
+ }
+
+ public final class CollapsingToolbarLayoutKt {
+ method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+ method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ }
+
+ public final class MenuItemKt {
+ method public static boolean onNavDestinationSelected(android.view.MenuItem, androidx.navigation.NavController navController);
+ }
+
+ public final class NavControllerKt {
+ method public static boolean navigateUp(androidx.navigation.NavController, androidx.customview.widget.Openable? drawerLayout);
+ method public static boolean navigateUp(androidx.navigation.NavController, androidx.navigation.ui.AppBarConfiguration appBarConfiguration);
+ }
+
+ public final class NavigationUI {
+ method public static boolean navigateUp(androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+ method public static boolean navigateUp(androidx.navigation.NavController navController, androidx.navigation.ui.AppBarConfiguration configuration);
+ method public static boolean onNavDestinationSelected(android.view.MenuItem item, androidx.navigation.NavController navController);
+ method @androidx.navigation.ui.NavigationUiSaveStateControl public static boolean onNavDestinationSelected(android.view.MenuItem item, androidx.navigation.NavController navController, boolean saveState);
+ method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController);
+ method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+ method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController);
+ method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+ method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController);
+ method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+ method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ method public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView navigationBarView, androidx.navigation.NavController navController);
+ method @androidx.navigation.ui.NavigationUiSaveStateControl public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView navigationBarView, androidx.navigation.NavController navController, boolean saveState);
+ method public static void setupWithNavController(com.google.android.material.navigation.NavigationView navigationView, androidx.navigation.NavController navController);
+ method @androidx.navigation.ui.NavigationUiSaveStateControl public static void setupWithNavController(com.google.android.material.navigation.NavigationView navigationView, androidx.navigation.NavController navController, boolean saveState);
+ field public static final androidx.navigation.ui.NavigationUI INSTANCE;
+ }
+
+ @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface NavigationUiSaveStateControl {
+ }
+
+ public final class NavigationViewKt {
+ method public static void setupWithNavController(com.google.android.material.navigation.NavigationView, androidx.navigation.NavController navController);
+ }
+
+ public final class ToolbarKt {
+ method public static void setupWithNavController(androidx.appcompat.widget.Toolbar, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+ method public static void setupWithNavController(androidx.appcompat.widget.Toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+ }
+
+}
+
diff --git a/paging/paging-common-ktx/api/3.2.0-beta01.txt b/paging/paging-common-ktx/api/3.2.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/paging/paging-common-ktx/api/3.2.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/paging/paging-common-ktx/api/restricted_3.2.0-beta01.txt b/paging/paging-common-ktx/api/restricted_3.2.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/paging/paging-common-ktx/api/restricted_3.2.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/paging/paging-common/api/3.2.0-beta01.txt b/paging/paging-common/api/3.2.0-beta01.txt
new file mode 100644
index 0000000..a9a0517
--- /dev/null
+++ b/paging/paging-common/api/3.2.0-beta01.txt
@@ -0,0 +1,510 @@
+// Signature format: 4.0
+package androidx.paging {
+
+ public final class CachedPagingDataKt {
+ method @CheckResult public static <T> kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<T>> cachedIn(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ }
+
+ public final class CombinedLoadStates {
+ ctor public CombinedLoadStates(androidx.paging.LoadState refresh, androidx.paging.LoadState prepend, androidx.paging.LoadState append, androidx.paging.LoadStates source, optional androidx.paging.LoadStates? mediator);
+ method public androidx.paging.LoadState getAppend();
+ method public androidx.paging.LoadStates? getMediator();
+ method public androidx.paging.LoadState getPrepend();
+ method public androidx.paging.LoadState getRefresh();
+ method public androidx.paging.LoadStates getSource();
+ property public final androidx.paging.LoadState append;
+ property public final androidx.paging.LoadStates? mediator;
+ property public final androidx.paging.LoadState prepend;
+ property public final androidx.paging.LoadState refresh;
+ property public final androidx.paging.LoadStates source;
+ }
+
+ public abstract class DataSource<Key, Value> {
+ method @AnyThread public void addInvalidatedCallback(androidx.paging.DataSource.InvalidatedCallback onInvalidatedCallback);
+ method @AnyThread public void invalidate();
+ method @WorkerThread public boolean isInvalid();
+ method public <ToValue> androidx.paging.DataSource<Key,ToValue> map(androidx.arch.core.util.Function<Value,ToValue> function);
+ method @kotlin.jvm.JvmSynthetic public <ToValue> androidx.paging.DataSource<Key,ToValue> map(kotlin.jvm.functions.Function1<? super Value,? extends ToValue> function);
+ method public <ToValue> androidx.paging.DataSource<Key,ToValue> mapByPage(androidx.arch.core.util.Function<java.util.List<Value>,java.util.List<ToValue>> function);
+ method @kotlin.jvm.JvmSynthetic public <ToValue> androidx.paging.DataSource<Key,ToValue> mapByPage(kotlin.jvm.functions.Function1<? super java.util.List<? extends Value>,? extends java.util.List<? extends ToValue>> function);
+ method @AnyThread public void removeInvalidatedCallback(androidx.paging.DataSource.InvalidatedCallback onInvalidatedCallback);
+ property @WorkerThread public boolean isInvalid;
+ }
+
+ public abstract static class DataSource.Factory<Key, Value> {
+ ctor public DataSource.Factory();
+ method public final kotlin.jvm.functions.Function0<androidx.paging.PagingSource<Key,Value>> asPagingSourceFactory();
+ method public final kotlin.jvm.functions.Function0<androidx.paging.PagingSource<Key,Value>> asPagingSourceFactory(optional kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ method public abstract androidx.paging.DataSource<Key,Value> create();
+ method public <ToValue> androidx.paging.DataSource.Factory<Key,ToValue> map(androidx.arch.core.util.Function<Value,ToValue> function);
+ method @kotlin.jvm.JvmSynthetic public <ToValue> androidx.paging.DataSource.Factory<Key,ToValue> map(kotlin.jvm.functions.Function1<? super Value,? extends ToValue> function);
+ method public <ToValue> androidx.paging.DataSource.Factory<Key,ToValue> mapByPage(androidx.arch.core.util.Function<java.util.List<Value>,java.util.List<ToValue>> function);
+ method @kotlin.jvm.JvmSynthetic public <ToValue> androidx.paging.DataSource.Factory<Key,ToValue> mapByPage(kotlin.jvm.functions.Function1<? super java.util.List<? extends Value>,? extends java.util.List<? extends ToValue>> function);
+ }
+
+ public static fun interface DataSource.InvalidatedCallback {
+ method @AnyThread public void onInvalidated();
+ }
+
+ @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalPagingApi {
+ }
+
+ public final class InvalidatingPagingSourceFactory<Key, Value> implements androidx.paging.PagingSourceFactory<Key,Value> {
+ ctor public InvalidatingPagingSourceFactory(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory);
+ method public void invalidate();
+ method public androidx.paging.PagingSource<Key,Value> invoke();
+ }
+
+ @Deprecated public abstract class ItemKeyedDataSource<Key, Value> extends androidx.paging.DataSource<Key,Value> {
+ ctor @Deprecated public ItemKeyedDataSource();
+ method @Deprecated public abstract Key getKey(Value item);
+ method @Deprecated public abstract void loadAfter(androidx.paging.ItemKeyedDataSource.LoadParams<Key> params, androidx.paging.ItemKeyedDataSource.LoadCallback<Value> callback);
+ method @Deprecated public abstract void loadBefore(androidx.paging.ItemKeyedDataSource.LoadParams<Key> params, androidx.paging.ItemKeyedDataSource.LoadCallback<Value> callback);
+ method @Deprecated public abstract void loadInitial(androidx.paging.ItemKeyedDataSource.LoadInitialParams<Key> params, androidx.paging.ItemKeyedDataSource.LoadInitialCallback<Value> callback);
+ method @Deprecated public final <ToValue> androidx.paging.ItemKeyedDataSource<Key,ToValue> map(androidx.arch.core.util.Function<Value,ToValue> function);
+ method @Deprecated public final <ToValue> androidx.paging.ItemKeyedDataSource<Key,ToValue> map(kotlin.jvm.functions.Function1<? super Value,? extends ToValue> function);
+ method @Deprecated public final <ToValue> androidx.paging.ItemKeyedDataSource<Key,ToValue> mapByPage(androidx.arch.core.util.Function<java.util.List<Value>,java.util.List<ToValue>> function);
+ method @Deprecated public final <ToValue> androidx.paging.ItemKeyedDataSource<Key,ToValue> mapByPage(kotlin.jvm.functions.Function1<? super java.util.List<? extends Value>,? extends java.util.List<? extends ToValue>> function);
+ }
+
+ @Deprecated public abstract static class ItemKeyedDataSource.LoadCallback<Value> {
+ ctor @Deprecated public ItemKeyedDataSource.LoadCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends Value> data);
+ }
+
+ @Deprecated public abstract static class ItemKeyedDataSource.LoadInitialCallback<Value> extends androidx.paging.ItemKeyedDataSource.LoadCallback<Value> {
+ ctor @Deprecated public ItemKeyedDataSource.LoadInitialCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends Value> data, int position, int totalCount);
+ }
+
+ @Deprecated public static class ItemKeyedDataSource.LoadInitialParams<Key> {
+ ctor @Deprecated public ItemKeyedDataSource.LoadInitialParams(Key? requestedInitialKey, int requestedLoadSize, boolean placeholdersEnabled);
+ field @Deprecated public final boolean placeholdersEnabled;
+ field @Deprecated public final Key? requestedInitialKey;
+ field @Deprecated public final int requestedLoadSize;
+ }
+
+ @Deprecated public static class ItemKeyedDataSource.LoadParams<Key> {
+ ctor @Deprecated public ItemKeyedDataSource.LoadParams(Key key, int requestedLoadSize);
+ field @Deprecated public final Key key;
+ field @Deprecated public final int requestedLoadSize;
+ }
+
+ public final class ItemSnapshotList<T> extends kotlin.collections.AbstractList<T> {
+ ctor public ItemSnapshotList(@IntRange(from=0L) int placeholdersBefore, @IntRange(from=0L) int placeholdersAfter, java.util.List<? extends T> items);
+ method public T? get(int index);
+ method public java.util.List<T> getItems();
+ method public int getPlaceholdersAfter();
+ method public int getPlaceholdersBefore();
+ method public int getSize();
+ property public final java.util.List<T> items;
+ property public final int placeholdersAfter;
+ property public final int placeholdersBefore;
+ property public int size;
+ }
+
+ public abstract sealed class LoadState {
+ method public final boolean getEndOfPaginationReached();
+ property public final boolean endOfPaginationReached;
+ }
+
+ public static final class LoadState.Error extends androidx.paging.LoadState {
+ ctor public LoadState.Error(Throwable error);
+ method public Throwable getError();
+ property public final Throwable error;
+ }
+
+ public static final class LoadState.Loading extends androidx.paging.LoadState {
+ field public static final androidx.paging.LoadState.Loading INSTANCE;
+ }
+
+ public static final class LoadState.NotLoading extends androidx.paging.LoadState {
+ ctor public LoadState.NotLoading(boolean endOfPaginationReached);
+ }
+
+ public final class LoadStates {
+ ctor public LoadStates(androidx.paging.LoadState refresh, androidx.paging.LoadState prepend, androidx.paging.LoadState append);
+ method public androidx.paging.LoadState component1();
+ method public androidx.paging.LoadState component2();
+ method public androidx.paging.LoadState component3();
+ method public androidx.paging.LoadStates copy(androidx.paging.LoadState refresh, androidx.paging.LoadState prepend, androidx.paging.LoadState append);
+ method public androidx.paging.LoadState getAppend();
+ method public androidx.paging.LoadState getPrepend();
+ method public androidx.paging.LoadState getRefresh();
+ property public final androidx.paging.LoadState append;
+ property public final androidx.paging.LoadState prepend;
+ property public final androidx.paging.LoadState refresh;
+ }
+
+ public enum LoadType {
+ method public static androidx.paging.LoadType valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.paging.LoadType[] values();
+ enum_constant public static final androidx.paging.LoadType APPEND;
+ enum_constant public static final androidx.paging.LoadType PREPEND;
+ enum_constant public static final androidx.paging.LoadType REFRESH;
+ }
+
+ @kotlin.jvm.JvmDefaultWithCompatibility public interface Logger {
+ method public boolean isLoggable(int level);
+ method public void log(int level, String message, optional Throwable? tr);
+ }
+
+ @Deprecated public abstract class PageKeyedDataSource<Key, Value> extends androidx.paging.DataSource<Key,Value> {
+ ctor @Deprecated public PageKeyedDataSource();
+ method @Deprecated public abstract void loadAfter(androidx.paging.PageKeyedDataSource.LoadParams<Key> params, androidx.paging.PageKeyedDataSource.LoadCallback<Key,Value> callback);
+ method @Deprecated public abstract void loadBefore(androidx.paging.PageKeyedDataSource.LoadParams<Key> params, androidx.paging.PageKeyedDataSource.LoadCallback<Key,Value> callback);
+ method @Deprecated public abstract void loadInitial(androidx.paging.PageKeyedDataSource.LoadInitialParams<Key> params, androidx.paging.PageKeyedDataSource.LoadInitialCallback<Key,Value> callback);
+ method @Deprecated public final <ToValue> androidx.paging.PageKeyedDataSource<Key,ToValue> map(androidx.arch.core.util.Function<Value,ToValue> function);
+ method @Deprecated public final <ToValue> androidx.paging.PageKeyedDataSource<Key,ToValue> map(kotlin.jvm.functions.Function1<? super Value,? extends ToValue> function);
+ method @Deprecated public final <ToValue> androidx.paging.PageKeyedDataSource<Key,ToValue> mapByPage(androidx.arch.core.util.Function<java.util.List<Value>,java.util.List<ToValue>> function);
+ method @Deprecated public final <ToValue> androidx.paging.PageKeyedDataSource<Key,ToValue> mapByPage(kotlin.jvm.functions.Function1<? super java.util.List<? extends Value>,? extends java.util.List<? extends ToValue>> function);
+ }
+
+ @Deprecated public abstract static class PageKeyedDataSource.LoadCallback<Key, Value> {
+ ctor @Deprecated public PageKeyedDataSource.LoadCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends Value> data, Key? adjacentPageKey);
+ }
+
+ @Deprecated public abstract static class PageKeyedDataSource.LoadInitialCallback<Key, Value> {
+ ctor @Deprecated public PageKeyedDataSource.LoadInitialCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends Value> data, int position, int totalCount, Key? previousPageKey, Key? nextPageKey);
+ method @Deprecated public abstract void onResult(java.util.List<? extends Value> data, Key? previousPageKey, Key? nextPageKey);
+ }
+
+ @Deprecated public static class PageKeyedDataSource.LoadInitialParams<Key> {
+ ctor @Deprecated public PageKeyedDataSource.LoadInitialParams(int requestedLoadSize, boolean placeholdersEnabled);
+ field @Deprecated public final boolean placeholdersEnabled;
+ field @Deprecated public final int requestedLoadSize;
+ }
+
+ @Deprecated public static class PageKeyedDataSource.LoadParams<Key> {
+ ctor @Deprecated public PageKeyedDataSource.LoadParams(Key key, int requestedLoadSize);
+ field @Deprecated public final Key key;
+ field @Deprecated public final int requestedLoadSize;
+ }
+
+ @Deprecated public abstract class PagedList<T> extends java.util.AbstractList<T> {
+ method @Deprecated public final void addWeakCallback(androidx.paging.PagedList.Callback callback);
+ method @Deprecated public final void addWeakCallback(java.util.List<? extends T>? previousSnapshot, androidx.paging.PagedList.Callback callback);
+ method @Deprecated public final void addWeakLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public abstract void detach();
+ method @Deprecated public T? get(int index);
+ method @Deprecated public final androidx.paging.PagedList.Config getConfig();
+ method @Deprecated public final androidx.paging.DataSource<?,T> getDataSource();
+ method @Deprecated public abstract Object? getLastKey();
+ method @Deprecated public final int getLoadedCount();
+ method @Deprecated public final int getPositionOffset();
+ method @Deprecated public int getSize();
+ method @Deprecated public abstract boolean isDetached();
+ method @Deprecated public boolean isImmutable();
+ method @Deprecated public final void loadAround(int index);
+ method @Deprecated public final void removeWeakCallback(androidx.paging.PagedList.Callback callback);
+ method @Deprecated public final void removeWeakLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public void retry();
+ method @Deprecated public final java.util.List<T> snapshot();
+ property @Deprecated public final androidx.paging.PagedList.Config config;
+ property @Deprecated public final androidx.paging.DataSource<?,T> dataSource;
+ property @Deprecated public abstract boolean isDetached;
+ property @Deprecated public boolean isImmutable;
+ property @Deprecated public abstract Object? lastKey;
+ property @Deprecated public final int loadedCount;
+ property @Deprecated public final int positionOffset;
+ property @Deprecated public int size;
+ }
+
+ @Deprecated @MainThread public abstract static class PagedList.BoundaryCallback<T> {
+ ctor @Deprecated public PagedList.BoundaryCallback();
+ method @Deprecated public void onItemAtEndLoaded(T itemAtEnd);
+ method @Deprecated public void onItemAtFrontLoaded(T itemAtFront);
+ method @Deprecated public void onZeroItemsLoaded();
+ }
+
+ @Deprecated public static final class PagedList.Builder<Key, Value> {
+ ctor @Deprecated public PagedList.Builder(androidx.paging.DataSource<Key,Value> dataSource, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public PagedList.Builder(androidx.paging.DataSource<Key,Value> dataSource, int pageSize);
+ ctor @Deprecated public PagedList.Builder(androidx.paging.PagingSource<Key,Value> pagingSource, androidx.paging.PagingSource.LoadResult.Page<Key,Value> initialPage, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public PagedList.Builder(androidx.paging.PagingSource<Key,Value> pagingSource, androidx.paging.PagingSource.LoadResult.Page<Key,Value> initialPage, int pageSize);
+ method @Deprecated public androidx.paging.PagedList<Value> build();
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setCoroutineScope(kotlinx.coroutines.CoroutineScope coroutineScope);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setFetchDispatcher(kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setInitialKey(Key? initialKey);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setNotifyDispatcher(kotlinx.coroutines.CoroutineDispatcher notifyDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setNotifyExecutor(java.util.concurrent.Executor notifyExecutor);
+ }
+
+ @Deprecated public abstract static class PagedList.Callback {
+ ctor @Deprecated public PagedList.Callback();
+ method @Deprecated public abstract void onChanged(int position, int count);
+ method @Deprecated public abstract void onInserted(int position, int count);
+ method @Deprecated public abstract void onRemoved(int position, int count);
+ }
+
+ @Deprecated public static final class PagedList.Config {
+ field @Deprecated public static final int MAX_SIZE_UNBOUNDED = 2147483647; // 0x7fffffff
+ field @Deprecated public final boolean enablePlaceholders;
+ field @Deprecated public final int initialLoadSizeHint;
+ field @Deprecated public final int maxSize;
+ field @Deprecated public final int pageSize;
+ field @Deprecated public final int prefetchDistance;
+ }
+
+ @Deprecated public static final class PagedList.Config.Builder {
+ ctor @Deprecated public PagedList.Config.Builder();
+ method @Deprecated public androidx.paging.PagedList.Config build();
+ method @Deprecated public androidx.paging.PagedList.Config.Builder setEnablePlaceholders(boolean enablePlaceholders);
+ method @Deprecated public androidx.paging.PagedList.Config.Builder setInitialLoadSizeHint(@IntRange(from=1L) int initialLoadSizeHint);
+ method @Deprecated public androidx.paging.PagedList.Config.Builder setMaxSize(@IntRange(from=2L) int maxSize);
+ method @Deprecated public androidx.paging.PagedList.Config.Builder setPageSize(@IntRange(from=1L) int pageSize);
+ method @Deprecated public androidx.paging.PagedList.Config.Builder setPrefetchDistance(@IntRange(from=0L) int prefetchDistance);
+ }
+
+ public final class PagedListConfigKt {
+ method @kotlin.jvm.JvmSynthetic public static androidx.paging.PagedList.Config Config(int pageSize, optional int prefetchDistance, optional boolean enablePlaceholders, optional int initialLoadSizeHint, optional int maxSize);
+ }
+
+ public final class PagedListKt {
+ method @Deprecated @kotlin.jvm.JvmSynthetic public static <Key extends java.lang.Object, Value> androidx.paging.PagedList<Value> PagedList(androidx.paging.DataSource<Key,Value> dataSource, androidx.paging.PagedList.Config config, java.util.concurrent.Executor notifyExecutor, java.util.concurrent.Executor fetchExecutor, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional Key? initialKey);
+ }
+
+ public final class Pager<Key, Value> {
+ ctor @androidx.paging.ExperimentalPagingApi public Pager(androidx.paging.PagingConfig config, optional Key? initialKey, androidx.paging.RemoteMediator<Key,Value>? remoteMediator, kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory);
+ ctor public Pager(androidx.paging.PagingConfig config, optional Key? initialKey, kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory);
+ ctor public Pager(androidx.paging.PagingConfig config, kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory);
+ method public kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>> getFlow();
+ property public final kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>> flow;
+ }
+
+ public final class PagingConfig {
+ ctor public PagingConfig(int pageSize);
+ ctor public PagingConfig(int pageSize, optional @IntRange(from=0L) int prefetchDistance);
+ ctor public PagingConfig(int pageSize, optional @IntRange(from=0L) int prefetchDistance, optional boolean enablePlaceholders);
+ ctor public PagingConfig(int pageSize, optional @IntRange(from=0L) int prefetchDistance, optional boolean enablePlaceholders, optional @IntRange(from=1L) int initialLoadSize);
+ ctor public PagingConfig(int pageSize, optional @IntRange(from=0L) int prefetchDistance, optional boolean enablePlaceholders, optional @IntRange(from=1L) int initialLoadSize, optional @IntRange(from=2L) int maxSize);
+ ctor public PagingConfig(int pageSize, optional @IntRange(from=0L) int prefetchDistance, optional boolean enablePlaceholders, optional @IntRange(from=1L) int initialLoadSize, optional @IntRange(from=2L) int maxSize, optional int jumpThreshold);
+ field public static final androidx.paging.PagingConfig.Companion Companion;
+ field public static final int MAX_SIZE_UNBOUNDED = 2147483647; // 0x7fffffff
+ field public final boolean enablePlaceholders;
+ field public final int initialLoadSize;
+ field public final int jumpThreshold;
+ field public final int maxSize;
+ field public final int pageSize;
+ field public final int prefetchDistance;
+ }
+
+ public static final class PagingConfig.Companion {
+ }
+
+ public final class PagingData<T> {
+ method public static <T> androidx.paging.PagingData<T> empty();
+ method public static <T> androidx.paging.PagingData<T> empty(androidx.paging.LoadStates sourceLoadStates);
+ method public static <T> androidx.paging.PagingData<T> empty(androidx.paging.LoadStates sourceLoadStates, optional androidx.paging.LoadStates? mediatorLoadStates);
+ method public static <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data);
+ method public static <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data, androidx.paging.LoadStates sourceLoadStates);
+ method public static <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data, androidx.paging.LoadStates sourceLoadStates, optional androidx.paging.LoadStates? mediatorLoadStates);
+ field public static final androidx.paging.PagingData.Companion Companion;
+ }
+
+ public static final class PagingData.Companion {
+ method public <T> androidx.paging.PagingData<T> empty();
+ method public <T> androidx.paging.PagingData<T> empty(androidx.paging.LoadStates sourceLoadStates);
+ method public <T> androidx.paging.PagingData<T> empty(androidx.paging.LoadStates sourceLoadStates, optional androidx.paging.LoadStates? mediatorLoadStates);
+ method public <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data);
+ method public <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data, androidx.paging.LoadStates sourceLoadStates);
+ method public <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data, androidx.paging.LoadStates sourceLoadStates, optional androidx.paging.LoadStates? mediatorLoadStates);
+ }
+
+ public final class PagingDataTransforms {
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> predicate);
+ method @CheckResult @kotlin.jvm.JvmSynthetic public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super java.lang.Boolean>,?> predicate);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,? extends java.lang.Iterable<? extends R>> transform);
+ method @CheckResult @kotlin.jvm.JvmSynthetic public static <T extends java.lang.Object, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super java.lang.Iterable<? extends R>>,?> transform);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertFooterItem(androidx.paging.PagingData<T>, optional androidx.paging.TerminalSeparatorType terminalSeparatorType, T item);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertFooterItem(androidx.paging.PagingData<T>, T item);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertHeaderItem(androidx.paging.PagingData<T>, optional androidx.paging.TerminalSeparatorType terminalSeparatorType, T item);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertHeaderItem(androidx.paging.PagingData<T>, T item);
+ method @CheckResult public static <R, T extends R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, optional androidx.paging.TerminalSeparatorType terminalSeparatorType, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
+ method @CheckResult @kotlin.jvm.JvmSynthetic public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, optional androidx.paging.TerminalSeparatorType terminalSeparatorType, kotlin.jvm.functions.Function3<? super T,? super T,? super kotlin.coroutines.Continuation<? super R>,?> generator);
+ method @CheckResult public static <R, T extends R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,? extends R> transform);
+ method @CheckResult @kotlin.jvm.JvmSynthetic public static <T extends java.lang.Object, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super R>,?> transform);
+ }
+
+ public abstract class PagingSource<Key, Value> {
+ ctor public PagingSource();
+ method public final boolean getInvalid();
+ method public boolean getJumpingSupported();
+ method public boolean getKeyReuseSupported();
+ method public abstract Key? getRefreshKey(androidx.paging.PagingState<Key,Value> state);
+ method public final void invalidate();
+ method public abstract suspend Object? load(androidx.paging.PagingSource.LoadParams<Key> params, kotlin.coroutines.Continuation<? super androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public final void registerInvalidatedCallback(kotlin.jvm.functions.Function0<kotlin.Unit> onInvalidatedCallback);
+ method public final void unregisterInvalidatedCallback(kotlin.jvm.functions.Function0<kotlin.Unit> onInvalidatedCallback);
+ property public final boolean invalid;
+ property public boolean jumpingSupported;
+ property public boolean keyReuseSupported;
+ }
+
+ public abstract static sealed class PagingSource.LoadParams<Key> {
+ method public abstract Key? getKey();
+ method public final int getLoadSize();
+ method public final boolean getPlaceholdersEnabled();
+ property public abstract Key? key;
+ property public final int loadSize;
+ property public final boolean placeholdersEnabled;
+ }
+
+ public static final class PagingSource.LoadParams.Append<Key> extends androidx.paging.PagingSource.LoadParams<Key> {
+ ctor public PagingSource.LoadParams.Append(Key key, int loadSize, boolean placeholdersEnabled);
+ method public Key getKey();
+ property public Key key;
+ }
+
+ public static final class PagingSource.LoadParams.Prepend<Key> extends androidx.paging.PagingSource.LoadParams<Key> {
+ ctor public PagingSource.LoadParams.Prepend(Key key, int loadSize, boolean placeholdersEnabled);
+ method public Key getKey();
+ property public Key key;
+ }
+
+ public static final class PagingSource.LoadParams.Refresh<Key> extends androidx.paging.PagingSource.LoadParams<Key> {
+ ctor public PagingSource.LoadParams.Refresh(Key? key, int loadSize, boolean placeholdersEnabled);
+ method public Key? getKey();
+ property public Key? key;
+ }
+
+ public abstract static sealed class PagingSource.LoadResult<Key, Value> {
+ }
+
+ public static final class PagingSource.LoadResult.Error<Key, Value> extends androidx.paging.PagingSource.LoadResult<Key,Value> {
+ ctor public PagingSource.LoadResult.Error(Throwable throwable);
+ method public Throwable component1();
+ method public androidx.paging.PagingSource.LoadResult.Error<Key,Value> copy(Throwable throwable);
+ method public Throwable getThrowable();
+ property public final Throwable throwable;
+ }
+
+ public static final class PagingSource.LoadResult.Invalid<Key, Value> extends androidx.paging.PagingSource.LoadResult<Key,Value> {
+ ctor public PagingSource.LoadResult.Invalid();
+ }
+
+ public static final class PagingSource.LoadResult.Page<Key, Value> extends androidx.paging.PagingSource.LoadResult<Key,Value> implements java.lang.Iterable<Value> kotlin.jvm.internal.markers.KMappedMarker {
+ ctor public PagingSource.LoadResult.Page(java.util.List<? extends Value> data, Key? prevKey, Key? nextKey);
+ ctor public PagingSource.LoadResult.Page(java.util.List<? extends Value> data, Key? prevKey, Key? nextKey, optional @IntRange(from=androidx.paging.PagingSource.LoadResult.Page.COUNT_UNDEFINED.toLong()) int itemsBefore, optional @IntRange(from=androidx.paging.PagingSource.LoadResult.Page.COUNT_UNDEFINED.toLong()) int itemsAfter);
+ method public java.util.List<Value> component1();
+ method public Key? component2();
+ method public Key? component3();
+ method public int component4();
+ method public int component5();
+ method public androidx.paging.PagingSource.LoadResult.Page<Key,Value> copy(java.util.List<? extends Value> data, Key? prevKey, Key? nextKey, @IntRange(from=-2147483648L) int itemsBefore, @IntRange(from=-2147483648L) int itemsAfter);
+ method public java.util.List<Value> getData();
+ method public int getItemsAfter();
+ method public int getItemsBefore();
+ method public Key? getNextKey();
+ method public Key? getPrevKey();
+ method public java.util.Iterator<Value> iterator();
+ property public final java.util.List<Value> data;
+ property public final int itemsAfter;
+ property public final int itemsBefore;
+ property public final Key? nextKey;
+ property public final Key? prevKey;
+ field public static final int COUNT_UNDEFINED = -2147483648; // 0x80000000
+ field public static final androidx.paging.PagingSource.LoadResult.Page.Companion Companion;
+ }
+
+ public static final class PagingSource.LoadResult.Page.Companion {
+ }
+
+ public fun interface PagingSourceFactory<Key, Value> extends kotlin.jvm.functions.Function0<androidx.paging.PagingSource<Key,Value>> {
+ method public operator androidx.paging.PagingSource<Key,Value> invoke();
+ }
+
+ public final class PagingState<Key, Value> {
+ ctor public PagingState(java.util.List<androidx.paging.PagingSource.LoadResult.Page<Key,Value>> pages, Integer? anchorPosition, androidx.paging.PagingConfig config, @IntRange(from=0L) int leadingPlaceholderCount);
+ method public Value? closestItemToPosition(int anchorPosition);
+ method public androidx.paging.PagingSource.LoadResult.Page<Key,Value>? closestPageToPosition(int anchorPosition);
+ method public Value? firstItemOrNull();
+ method public Integer? getAnchorPosition();
+ method public androidx.paging.PagingConfig getConfig();
+ method public java.util.List<androidx.paging.PagingSource.LoadResult.Page<Key,Value>> getPages();
+ method public boolean isEmpty();
+ method public Value? lastItemOrNull();
+ property public final Integer? anchorPosition;
+ property public final androidx.paging.PagingConfig config;
+ property public final java.util.List<androidx.paging.PagingSource.LoadResult.Page<Key,Value>> pages;
+ }
+
+ @Deprecated public abstract class PositionalDataSource<T> extends androidx.paging.DataSource<java.lang.Integer,T> {
+ ctor @Deprecated public PositionalDataSource();
+ method @Deprecated public static final int computeInitialLoadPosition(androidx.paging.PositionalDataSource.LoadInitialParams params, int totalCount);
+ method @Deprecated public static final int computeInitialLoadSize(androidx.paging.PositionalDataSource.LoadInitialParams params, int initialLoadPosition, int totalCount);
+ method @Deprecated @WorkerThread public abstract void loadInitial(androidx.paging.PositionalDataSource.LoadInitialParams params, androidx.paging.PositionalDataSource.LoadInitialCallback<T> callback);
+ method @Deprecated @WorkerThread public abstract void loadRange(androidx.paging.PositionalDataSource.LoadRangeParams params, androidx.paging.PositionalDataSource.LoadRangeCallback<T> callback);
+ method @Deprecated public final <V> androidx.paging.PositionalDataSource<V> map(androidx.arch.core.util.Function<T,V> function);
+ method @Deprecated public final <V> androidx.paging.PositionalDataSource<V> map(kotlin.jvm.functions.Function1<? super T,? extends V> function);
+ method @Deprecated public final <V> androidx.paging.PositionalDataSource<V> mapByPage(androidx.arch.core.util.Function<java.util.List<T>,java.util.List<V>> function);
+ method @Deprecated public final <V> androidx.paging.PositionalDataSource<V> mapByPage(kotlin.jvm.functions.Function1<? super java.util.List<? extends T>,? extends java.util.List<? extends V>> function);
+ }
+
+ @Deprecated public abstract static class PositionalDataSource.LoadInitialCallback<T> {
+ ctor @Deprecated public PositionalDataSource.LoadInitialCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends T> data, int position);
+ method @Deprecated public abstract void onResult(java.util.List<? extends T> data, int position, int totalCount);
+ }
+
+ @Deprecated public static class PositionalDataSource.LoadInitialParams {
+ ctor @Deprecated public PositionalDataSource.LoadInitialParams(int requestedStartPosition, int requestedLoadSize, int pageSize, boolean placeholdersEnabled);
+ field @Deprecated public final int pageSize;
+ field @Deprecated public final boolean placeholdersEnabled;
+ field @Deprecated public final int requestedLoadSize;
+ field @Deprecated public final int requestedStartPosition;
+ }
+
+ @Deprecated public abstract static class PositionalDataSource.LoadRangeCallback<T> {
+ ctor @Deprecated public PositionalDataSource.LoadRangeCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends T> data);
+ }
+
+ @Deprecated public static class PositionalDataSource.LoadRangeParams {
+ ctor @Deprecated public PositionalDataSource.LoadRangeParams(int startPosition, int loadSize);
+ field @Deprecated public final int loadSize;
+ field @Deprecated public final int startPosition;
+ }
+
+ @androidx.paging.ExperimentalPagingApi public abstract class RemoteMediator<Key, Value> {
+ ctor public RemoteMediator();
+ method public suspend Object? initialize(kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.InitializeAction>);
+ method public abstract suspend Object? load(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state, kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.MediatorResult>);
+ }
+
+ public enum RemoteMediator.InitializeAction {
+ method public static androidx.paging.RemoteMediator.InitializeAction valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.paging.RemoteMediator.InitializeAction[] values();
+ enum_constant public static final androidx.paging.RemoteMediator.InitializeAction LAUNCH_INITIAL_REFRESH;
+ enum_constant public static final androidx.paging.RemoteMediator.InitializeAction SKIP_INITIAL_REFRESH;
+ }
+
+ public abstract static sealed class RemoteMediator.MediatorResult {
+ }
+
+ public static final class RemoteMediator.MediatorResult.Error extends androidx.paging.RemoteMediator.MediatorResult {
+ ctor public RemoteMediator.MediatorResult.Error(Throwable throwable);
+ method public Throwable getThrowable();
+ property public final Throwable throwable;
+ }
+
+ public static final class RemoteMediator.MediatorResult.Success extends androidx.paging.RemoteMediator.MediatorResult {
+ ctor public RemoteMediator.MediatorResult.Success(boolean endOfPaginationReached);
+ method public boolean getEndOfPaginationReached();
+ property public final boolean endOfPaginationReached;
+ }
+
+ public enum TerminalSeparatorType {
+ method public static androidx.paging.TerminalSeparatorType valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.paging.TerminalSeparatorType[] values();
+ enum_constant public static final androidx.paging.TerminalSeparatorType FULLY_COMPLETE;
+ enum_constant public static final androidx.paging.TerminalSeparatorType SOURCE_COMPLETE;
+ }
+
+}
+
diff --git a/paging/paging-common/api/restricted_3.2.0-beta01.txt b/paging/paging-common/api/restricted_3.2.0-beta01.txt
new file mode 100644
index 0000000..a9a0517
--- /dev/null
+++ b/paging/paging-common/api/restricted_3.2.0-beta01.txt
@@ -0,0 +1,510 @@
+// Signature format: 4.0
+package androidx.paging {
+
+ public final class CachedPagingDataKt {
+ method @CheckResult public static <T> kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<T>> cachedIn(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ }
+
+ public final class CombinedLoadStates {
+ ctor public CombinedLoadStates(androidx.paging.LoadState refresh, androidx.paging.LoadState prepend, androidx.paging.LoadState append, androidx.paging.LoadStates source, optional androidx.paging.LoadStates? mediator);
+ method public androidx.paging.LoadState getAppend();
+ method public androidx.paging.LoadStates? getMediator();
+ method public androidx.paging.LoadState getPrepend();
+ method public androidx.paging.LoadState getRefresh();
+ method public androidx.paging.LoadStates getSource();
+ property public final androidx.paging.LoadState append;
+ property public final androidx.paging.LoadStates? mediator;
+ property public final androidx.paging.LoadState prepend;
+ property public final androidx.paging.LoadState refresh;
+ property public final androidx.paging.LoadStates source;
+ }
+
+ public abstract class DataSource<Key, Value> {
+ method @AnyThread public void addInvalidatedCallback(androidx.paging.DataSource.InvalidatedCallback onInvalidatedCallback);
+ method @AnyThread public void invalidate();
+ method @WorkerThread public boolean isInvalid();
+ method public <ToValue> androidx.paging.DataSource<Key,ToValue> map(androidx.arch.core.util.Function<Value,ToValue> function);
+ method @kotlin.jvm.JvmSynthetic public <ToValue> androidx.paging.DataSource<Key,ToValue> map(kotlin.jvm.functions.Function1<? super Value,? extends ToValue> function);
+ method public <ToValue> androidx.paging.DataSource<Key,ToValue> mapByPage(androidx.arch.core.util.Function<java.util.List<Value>,java.util.List<ToValue>> function);
+ method @kotlin.jvm.JvmSynthetic public <ToValue> androidx.paging.DataSource<Key,ToValue> mapByPage(kotlin.jvm.functions.Function1<? super java.util.List<? extends Value>,? extends java.util.List<? extends ToValue>> function);
+ method @AnyThread public void removeInvalidatedCallback(androidx.paging.DataSource.InvalidatedCallback onInvalidatedCallback);
+ property @WorkerThread public boolean isInvalid;
+ }
+
+ public abstract static class DataSource.Factory<Key, Value> {
+ ctor public DataSource.Factory();
+ method public final kotlin.jvm.functions.Function0<androidx.paging.PagingSource<Key,Value>> asPagingSourceFactory();
+ method public final kotlin.jvm.functions.Function0<androidx.paging.PagingSource<Key,Value>> asPagingSourceFactory(optional kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ method public abstract androidx.paging.DataSource<Key,Value> create();
+ method public <ToValue> androidx.paging.DataSource.Factory<Key,ToValue> map(androidx.arch.core.util.Function<Value,ToValue> function);
+ method @kotlin.jvm.JvmSynthetic public <ToValue> androidx.paging.DataSource.Factory<Key,ToValue> map(kotlin.jvm.functions.Function1<? super Value,? extends ToValue> function);
+ method public <ToValue> androidx.paging.DataSource.Factory<Key,ToValue> mapByPage(androidx.arch.core.util.Function<java.util.List<Value>,java.util.List<ToValue>> function);
+ method @kotlin.jvm.JvmSynthetic public <ToValue> androidx.paging.DataSource.Factory<Key,ToValue> mapByPage(kotlin.jvm.functions.Function1<? super java.util.List<? extends Value>,? extends java.util.List<? extends ToValue>> function);
+ }
+
+ public static fun interface DataSource.InvalidatedCallback {
+ method @AnyThread public void onInvalidated();
+ }
+
+ @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalPagingApi {
+ }
+
+ public final class InvalidatingPagingSourceFactory<Key, Value> implements androidx.paging.PagingSourceFactory<Key,Value> {
+ ctor public InvalidatingPagingSourceFactory(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory);
+ method public void invalidate();
+ method public androidx.paging.PagingSource<Key,Value> invoke();
+ }
+
+ @Deprecated public abstract class ItemKeyedDataSource<Key, Value> extends androidx.paging.DataSource<Key,Value> {
+ ctor @Deprecated public ItemKeyedDataSource();
+ method @Deprecated public abstract Key getKey(Value item);
+ method @Deprecated public abstract void loadAfter(androidx.paging.ItemKeyedDataSource.LoadParams<Key> params, androidx.paging.ItemKeyedDataSource.LoadCallback<Value> callback);
+ method @Deprecated public abstract void loadBefore(androidx.paging.ItemKeyedDataSource.LoadParams<Key> params, androidx.paging.ItemKeyedDataSource.LoadCallback<Value> callback);
+ method @Deprecated public abstract void loadInitial(androidx.paging.ItemKeyedDataSource.LoadInitialParams<Key> params, androidx.paging.ItemKeyedDataSource.LoadInitialCallback<Value> callback);
+ method @Deprecated public final <ToValue> androidx.paging.ItemKeyedDataSource<Key,ToValue> map(androidx.arch.core.util.Function<Value,ToValue> function);
+ method @Deprecated public final <ToValue> androidx.paging.ItemKeyedDataSource<Key,ToValue> map(kotlin.jvm.functions.Function1<? super Value,? extends ToValue> function);
+ method @Deprecated public final <ToValue> androidx.paging.ItemKeyedDataSource<Key,ToValue> mapByPage(androidx.arch.core.util.Function<java.util.List<Value>,java.util.List<ToValue>> function);
+ method @Deprecated public final <ToValue> androidx.paging.ItemKeyedDataSource<Key,ToValue> mapByPage(kotlin.jvm.functions.Function1<? super java.util.List<? extends Value>,? extends java.util.List<? extends ToValue>> function);
+ }
+
+ @Deprecated public abstract static class ItemKeyedDataSource.LoadCallback<Value> {
+ ctor @Deprecated public ItemKeyedDataSource.LoadCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends Value> data);
+ }
+
+ @Deprecated public abstract static class ItemKeyedDataSource.LoadInitialCallback<Value> extends androidx.paging.ItemKeyedDataSource.LoadCallback<Value> {
+ ctor @Deprecated public ItemKeyedDataSource.LoadInitialCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends Value> data, int position, int totalCount);
+ }
+
+ @Deprecated public static class ItemKeyedDataSource.LoadInitialParams<Key> {
+ ctor @Deprecated public ItemKeyedDataSource.LoadInitialParams(Key? requestedInitialKey, int requestedLoadSize, boolean placeholdersEnabled);
+ field @Deprecated public final boolean placeholdersEnabled;
+ field @Deprecated public final Key? requestedInitialKey;
+ field @Deprecated public final int requestedLoadSize;
+ }
+
+ @Deprecated public static class ItemKeyedDataSource.LoadParams<Key> {
+ ctor @Deprecated public ItemKeyedDataSource.LoadParams(Key key, int requestedLoadSize);
+ field @Deprecated public final Key key;
+ field @Deprecated public final int requestedLoadSize;
+ }
+
+ public final class ItemSnapshotList<T> extends kotlin.collections.AbstractList<T> {
+ ctor public ItemSnapshotList(@IntRange(from=0L) int placeholdersBefore, @IntRange(from=0L) int placeholdersAfter, java.util.List<? extends T> items);
+ method public T? get(int index);
+ method public java.util.List<T> getItems();
+ method public int getPlaceholdersAfter();
+ method public int getPlaceholdersBefore();
+ method public int getSize();
+ property public final java.util.List<T> items;
+ property public final int placeholdersAfter;
+ property public final int placeholdersBefore;
+ property public int size;
+ }
+
+ public abstract sealed class LoadState {
+ method public final boolean getEndOfPaginationReached();
+ property public final boolean endOfPaginationReached;
+ }
+
+ public static final class LoadState.Error extends androidx.paging.LoadState {
+ ctor public LoadState.Error(Throwable error);
+ method public Throwable getError();
+ property public final Throwable error;
+ }
+
+ public static final class LoadState.Loading extends androidx.paging.LoadState {
+ field public static final androidx.paging.LoadState.Loading INSTANCE;
+ }
+
+ public static final class LoadState.NotLoading extends androidx.paging.LoadState {
+ ctor public LoadState.NotLoading(boolean endOfPaginationReached);
+ }
+
+ public final class LoadStates {
+ ctor public LoadStates(androidx.paging.LoadState refresh, androidx.paging.LoadState prepend, androidx.paging.LoadState append);
+ method public androidx.paging.LoadState component1();
+ method public androidx.paging.LoadState component2();
+ method public androidx.paging.LoadState component3();
+ method public androidx.paging.LoadStates copy(androidx.paging.LoadState refresh, androidx.paging.LoadState prepend, androidx.paging.LoadState append);
+ method public androidx.paging.LoadState getAppend();
+ method public androidx.paging.LoadState getPrepend();
+ method public androidx.paging.LoadState getRefresh();
+ property public final androidx.paging.LoadState append;
+ property public final androidx.paging.LoadState prepend;
+ property public final androidx.paging.LoadState refresh;
+ }
+
+ public enum LoadType {
+ method public static androidx.paging.LoadType valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.paging.LoadType[] values();
+ enum_constant public static final androidx.paging.LoadType APPEND;
+ enum_constant public static final androidx.paging.LoadType PREPEND;
+ enum_constant public static final androidx.paging.LoadType REFRESH;
+ }
+
+ @kotlin.jvm.JvmDefaultWithCompatibility public interface Logger {
+ method public boolean isLoggable(int level);
+ method public void log(int level, String message, optional Throwable? tr);
+ }
+
+ @Deprecated public abstract class PageKeyedDataSource<Key, Value> extends androidx.paging.DataSource<Key,Value> {
+ ctor @Deprecated public PageKeyedDataSource();
+ method @Deprecated public abstract void loadAfter(androidx.paging.PageKeyedDataSource.LoadParams<Key> params, androidx.paging.PageKeyedDataSource.LoadCallback<Key,Value> callback);
+ method @Deprecated public abstract void loadBefore(androidx.paging.PageKeyedDataSource.LoadParams<Key> params, androidx.paging.PageKeyedDataSource.LoadCallback<Key,Value> callback);
+ method @Deprecated public abstract void loadInitial(androidx.paging.PageKeyedDataSource.LoadInitialParams<Key> params, androidx.paging.PageKeyedDataSource.LoadInitialCallback<Key,Value> callback);
+ method @Deprecated public final <ToValue> androidx.paging.PageKeyedDataSource<Key,ToValue> map(androidx.arch.core.util.Function<Value,ToValue> function);
+ method @Deprecated public final <ToValue> androidx.paging.PageKeyedDataSource<Key,ToValue> map(kotlin.jvm.functions.Function1<? super Value,? extends ToValue> function);
+ method @Deprecated public final <ToValue> androidx.paging.PageKeyedDataSource<Key,ToValue> mapByPage(androidx.arch.core.util.Function<java.util.List<Value>,java.util.List<ToValue>> function);
+ method @Deprecated public final <ToValue> androidx.paging.PageKeyedDataSource<Key,ToValue> mapByPage(kotlin.jvm.functions.Function1<? super java.util.List<? extends Value>,? extends java.util.List<? extends ToValue>> function);
+ }
+
+ @Deprecated public abstract static class PageKeyedDataSource.LoadCallback<Key, Value> {
+ ctor @Deprecated public PageKeyedDataSource.LoadCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends Value> data, Key? adjacentPageKey);
+ }
+
+ @Deprecated public abstract static class PageKeyedDataSource.LoadInitialCallback<Key, Value> {
+ ctor @Deprecated public PageKeyedDataSource.LoadInitialCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends Value> data, int position, int totalCount, Key? previousPageKey, Key? nextPageKey);
+ method @Deprecated public abstract void onResult(java.util.List<? extends Value> data, Key? previousPageKey, Key? nextPageKey);
+ }
+
+ @Deprecated public static class PageKeyedDataSource.LoadInitialParams<Key> {
+ ctor @Deprecated public PageKeyedDataSource.LoadInitialParams(int requestedLoadSize, boolean placeholdersEnabled);
+ field @Deprecated public final boolean placeholdersEnabled;
+ field @Deprecated public final int requestedLoadSize;
+ }
+
+ @Deprecated public static class PageKeyedDataSource.LoadParams<Key> {
+ ctor @Deprecated public PageKeyedDataSource.LoadParams(Key key, int requestedLoadSize);
+ field @Deprecated public final Key key;
+ field @Deprecated public final int requestedLoadSize;
+ }
+
+ @Deprecated public abstract class PagedList<T> extends java.util.AbstractList<T> {
+ method @Deprecated public final void addWeakCallback(androidx.paging.PagedList.Callback callback);
+ method @Deprecated public final void addWeakCallback(java.util.List<? extends T>? previousSnapshot, androidx.paging.PagedList.Callback callback);
+ method @Deprecated public final void addWeakLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public abstract void detach();
+ method @Deprecated public T? get(int index);
+ method @Deprecated public final androidx.paging.PagedList.Config getConfig();
+ method @Deprecated public final androidx.paging.DataSource<?,T> getDataSource();
+ method @Deprecated public abstract Object? getLastKey();
+ method @Deprecated public final int getLoadedCount();
+ method @Deprecated public final int getPositionOffset();
+ method @Deprecated public int getSize();
+ method @Deprecated public abstract boolean isDetached();
+ method @Deprecated public boolean isImmutable();
+ method @Deprecated public final void loadAround(int index);
+ method @Deprecated public final void removeWeakCallback(androidx.paging.PagedList.Callback callback);
+ method @Deprecated public final void removeWeakLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public void retry();
+ method @Deprecated public final java.util.List<T> snapshot();
+ property @Deprecated public final androidx.paging.PagedList.Config config;
+ property @Deprecated public final androidx.paging.DataSource<?,T> dataSource;
+ property @Deprecated public abstract boolean isDetached;
+ property @Deprecated public boolean isImmutable;
+ property @Deprecated public abstract Object? lastKey;
+ property @Deprecated public final int loadedCount;
+ property @Deprecated public final int positionOffset;
+ property @Deprecated public int size;
+ }
+
+ @Deprecated @MainThread public abstract static class PagedList.BoundaryCallback<T> {
+ ctor @Deprecated public PagedList.BoundaryCallback();
+ method @Deprecated public void onItemAtEndLoaded(T itemAtEnd);
+ method @Deprecated public void onItemAtFrontLoaded(T itemAtFront);
+ method @Deprecated public void onZeroItemsLoaded();
+ }
+
+ @Deprecated public static final class PagedList.Builder<Key, Value> {
+ ctor @Deprecated public PagedList.Builder(androidx.paging.DataSource<Key,Value> dataSource, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public PagedList.Builder(androidx.paging.DataSource<Key,Value> dataSource, int pageSize);
+ ctor @Deprecated public PagedList.Builder(androidx.paging.PagingSource<Key,Value> pagingSource, androidx.paging.PagingSource.LoadResult.Page<Key,Value> initialPage, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public PagedList.Builder(androidx.paging.PagingSource<Key,Value> pagingSource, androidx.paging.PagingSource.LoadResult.Page<Key,Value> initialPage, int pageSize);
+ method @Deprecated public androidx.paging.PagedList<Value> build();
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setCoroutineScope(kotlinx.coroutines.CoroutineScope coroutineScope);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setFetchDispatcher(kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setInitialKey(Key? initialKey);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setNotifyDispatcher(kotlinx.coroutines.CoroutineDispatcher notifyDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setNotifyExecutor(java.util.concurrent.Executor notifyExecutor);
+ }
+
+ @Deprecated public abstract static class PagedList.Callback {
+ ctor @Deprecated public PagedList.Callback();
+ method @Deprecated public abstract void onChanged(int position, int count);
+ method @Deprecated public abstract void onInserted(int position, int count);
+ method @Deprecated public abstract void onRemoved(int position, int count);
+ }
+
+ @Deprecated public static final class PagedList.Config {
+ field @Deprecated public static final int MAX_SIZE_UNBOUNDED = 2147483647; // 0x7fffffff
+ field @Deprecated public final boolean enablePlaceholders;
+ field @Deprecated public final int initialLoadSizeHint;
+ field @Deprecated public final int maxSize;
+ field @Deprecated public final int pageSize;
+ field @Deprecated public final int prefetchDistance;
+ }
+
+ @Deprecated public static final class PagedList.Config.Builder {
+ ctor @Deprecated public PagedList.Config.Builder();
+ method @Deprecated public androidx.paging.PagedList.Config build();
+ method @Deprecated public androidx.paging.PagedList.Config.Builder setEnablePlaceholders(boolean enablePlaceholders);
+ method @Deprecated public androidx.paging.PagedList.Config.Builder setInitialLoadSizeHint(@IntRange(from=1L) int initialLoadSizeHint);
+ method @Deprecated public androidx.paging.PagedList.Config.Builder setMaxSize(@IntRange(from=2L) int maxSize);
+ method @Deprecated public androidx.paging.PagedList.Config.Builder setPageSize(@IntRange(from=1L) int pageSize);
+ method @Deprecated public androidx.paging.PagedList.Config.Builder setPrefetchDistance(@IntRange(from=0L) int prefetchDistance);
+ }
+
+ public final class PagedListConfigKt {
+ method @kotlin.jvm.JvmSynthetic public static androidx.paging.PagedList.Config Config(int pageSize, optional int prefetchDistance, optional boolean enablePlaceholders, optional int initialLoadSizeHint, optional int maxSize);
+ }
+
+ public final class PagedListKt {
+ method @Deprecated @kotlin.jvm.JvmSynthetic public static <Key extends java.lang.Object, Value> androidx.paging.PagedList<Value> PagedList(androidx.paging.DataSource<Key,Value> dataSource, androidx.paging.PagedList.Config config, java.util.concurrent.Executor notifyExecutor, java.util.concurrent.Executor fetchExecutor, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional Key? initialKey);
+ }
+
+ public final class Pager<Key, Value> {
+ ctor @androidx.paging.ExperimentalPagingApi public Pager(androidx.paging.PagingConfig config, optional Key? initialKey, androidx.paging.RemoteMediator<Key,Value>? remoteMediator, kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory);
+ ctor public Pager(androidx.paging.PagingConfig config, optional Key? initialKey, kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory);
+ ctor public Pager(androidx.paging.PagingConfig config, kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory);
+ method public kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>> getFlow();
+ property public final kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>> flow;
+ }
+
+ public final class PagingConfig {
+ ctor public PagingConfig(int pageSize);
+ ctor public PagingConfig(int pageSize, optional @IntRange(from=0L) int prefetchDistance);
+ ctor public PagingConfig(int pageSize, optional @IntRange(from=0L) int prefetchDistance, optional boolean enablePlaceholders);
+ ctor public PagingConfig(int pageSize, optional @IntRange(from=0L) int prefetchDistance, optional boolean enablePlaceholders, optional @IntRange(from=1L) int initialLoadSize);
+ ctor public PagingConfig(int pageSize, optional @IntRange(from=0L) int prefetchDistance, optional boolean enablePlaceholders, optional @IntRange(from=1L) int initialLoadSize, optional @IntRange(from=2L) int maxSize);
+ ctor public PagingConfig(int pageSize, optional @IntRange(from=0L) int prefetchDistance, optional boolean enablePlaceholders, optional @IntRange(from=1L) int initialLoadSize, optional @IntRange(from=2L) int maxSize, optional int jumpThreshold);
+ field public static final androidx.paging.PagingConfig.Companion Companion;
+ field public static final int MAX_SIZE_UNBOUNDED = 2147483647; // 0x7fffffff
+ field public final boolean enablePlaceholders;
+ field public final int initialLoadSize;
+ field public final int jumpThreshold;
+ field public final int maxSize;
+ field public final int pageSize;
+ field public final int prefetchDistance;
+ }
+
+ public static final class PagingConfig.Companion {
+ }
+
+ public final class PagingData<T> {
+ method public static <T> androidx.paging.PagingData<T> empty();
+ method public static <T> androidx.paging.PagingData<T> empty(androidx.paging.LoadStates sourceLoadStates);
+ method public static <T> androidx.paging.PagingData<T> empty(androidx.paging.LoadStates sourceLoadStates, optional androidx.paging.LoadStates? mediatorLoadStates);
+ method public static <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data);
+ method public static <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data, androidx.paging.LoadStates sourceLoadStates);
+ method public static <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data, androidx.paging.LoadStates sourceLoadStates, optional androidx.paging.LoadStates? mediatorLoadStates);
+ field public static final androidx.paging.PagingData.Companion Companion;
+ }
+
+ public static final class PagingData.Companion {
+ method public <T> androidx.paging.PagingData<T> empty();
+ method public <T> androidx.paging.PagingData<T> empty(androidx.paging.LoadStates sourceLoadStates);
+ method public <T> androidx.paging.PagingData<T> empty(androidx.paging.LoadStates sourceLoadStates, optional androidx.paging.LoadStates? mediatorLoadStates);
+ method public <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data);
+ method public <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data, androidx.paging.LoadStates sourceLoadStates);
+ method public <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data, androidx.paging.LoadStates sourceLoadStates, optional androidx.paging.LoadStates? mediatorLoadStates);
+ }
+
+ public final class PagingDataTransforms {
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> predicate);
+ method @CheckResult @kotlin.jvm.JvmSynthetic public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super java.lang.Boolean>,?> predicate);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,? extends java.lang.Iterable<? extends R>> transform);
+ method @CheckResult @kotlin.jvm.JvmSynthetic public static <T extends java.lang.Object, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super java.lang.Iterable<? extends R>>,?> transform);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertFooterItem(androidx.paging.PagingData<T>, optional androidx.paging.TerminalSeparatorType terminalSeparatorType, T item);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertFooterItem(androidx.paging.PagingData<T>, T item);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertHeaderItem(androidx.paging.PagingData<T>, optional androidx.paging.TerminalSeparatorType terminalSeparatorType, T item);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertHeaderItem(androidx.paging.PagingData<T>, T item);
+ method @CheckResult public static <R, T extends R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, optional androidx.paging.TerminalSeparatorType terminalSeparatorType, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
+ method @CheckResult @kotlin.jvm.JvmSynthetic public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, optional androidx.paging.TerminalSeparatorType terminalSeparatorType, kotlin.jvm.functions.Function3<? super T,? super T,? super kotlin.coroutines.Continuation<? super R>,?> generator);
+ method @CheckResult public static <R, T extends R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,? extends R> transform);
+ method @CheckResult @kotlin.jvm.JvmSynthetic public static <T extends java.lang.Object, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super R>,?> transform);
+ }
+
+ public abstract class PagingSource<Key, Value> {
+ ctor public PagingSource();
+ method public final boolean getInvalid();
+ method public boolean getJumpingSupported();
+ method public boolean getKeyReuseSupported();
+ method public abstract Key? getRefreshKey(androidx.paging.PagingState<Key,Value> state);
+ method public final void invalidate();
+ method public abstract suspend Object? load(androidx.paging.PagingSource.LoadParams<Key> params, kotlin.coroutines.Continuation<? super androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public final void registerInvalidatedCallback(kotlin.jvm.functions.Function0<kotlin.Unit> onInvalidatedCallback);
+ method public final void unregisterInvalidatedCallback(kotlin.jvm.functions.Function0<kotlin.Unit> onInvalidatedCallback);
+ property public final boolean invalid;
+ property public boolean jumpingSupported;
+ property public boolean keyReuseSupported;
+ }
+
+ public abstract static sealed class PagingSource.LoadParams<Key> {
+ method public abstract Key? getKey();
+ method public final int getLoadSize();
+ method public final boolean getPlaceholdersEnabled();
+ property public abstract Key? key;
+ property public final int loadSize;
+ property public final boolean placeholdersEnabled;
+ }
+
+ public static final class PagingSource.LoadParams.Append<Key> extends androidx.paging.PagingSource.LoadParams<Key> {
+ ctor public PagingSource.LoadParams.Append(Key key, int loadSize, boolean placeholdersEnabled);
+ method public Key getKey();
+ property public Key key;
+ }
+
+ public static final class PagingSource.LoadParams.Prepend<Key> extends androidx.paging.PagingSource.LoadParams<Key> {
+ ctor public PagingSource.LoadParams.Prepend(Key key, int loadSize, boolean placeholdersEnabled);
+ method public Key getKey();
+ property public Key key;
+ }
+
+ public static final class PagingSource.LoadParams.Refresh<Key> extends androidx.paging.PagingSource.LoadParams<Key> {
+ ctor public PagingSource.LoadParams.Refresh(Key? key, int loadSize, boolean placeholdersEnabled);
+ method public Key? getKey();
+ property public Key? key;
+ }
+
+ public abstract static sealed class PagingSource.LoadResult<Key, Value> {
+ }
+
+ public static final class PagingSource.LoadResult.Error<Key, Value> extends androidx.paging.PagingSource.LoadResult<Key,Value> {
+ ctor public PagingSource.LoadResult.Error(Throwable throwable);
+ method public Throwable component1();
+ method public androidx.paging.PagingSource.LoadResult.Error<Key,Value> copy(Throwable throwable);
+ method public Throwable getThrowable();
+ property public final Throwable throwable;
+ }
+
+ public static final class PagingSource.LoadResult.Invalid<Key, Value> extends androidx.paging.PagingSource.LoadResult<Key,Value> {
+ ctor public PagingSource.LoadResult.Invalid();
+ }
+
+ public static final class PagingSource.LoadResult.Page<Key, Value> extends androidx.paging.PagingSource.LoadResult<Key,Value> implements java.lang.Iterable<Value> kotlin.jvm.internal.markers.KMappedMarker {
+ ctor public PagingSource.LoadResult.Page(java.util.List<? extends Value> data, Key? prevKey, Key? nextKey);
+ ctor public PagingSource.LoadResult.Page(java.util.List<? extends Value> data, Key? prevKey, Key? nextKey, optional @IntRange(from=androidx.paging.PagingSource.LoadResult.Page.COUNT_UNDEFINED.toLong()) int itemsBefore, optional @IntRange(from=androidx.paging.PagingSource.LoadResult.Page.COUNT_UNDEFINED.toLong()) int itemsAfter);
+ method public java.util.List<Value> component1();
+ method public Key? component2();
+ method public Key? component3();
+ method public int component4();
+ method public int component5();
+ method public androidx.paging.PagingSource.LoadResult.Page<Key,Value> copy(java.util.List<? extends Value> data, Key? prevKey, Key? nextKey, @IntRange(from=-2147483648L) int itemsBefore, @IntRange(from=-2147483648L) int itemsAfter);
+ method public java.util.List<Value> getData();
+ method public int getItemsAfter();
+ method public int getItemsBefore();
+ method public Key? getNextKey();
+ method public Key? getPrevKey();
+ method public java.util.Iterator<Value> iterator();
+ property public final java.util.List<Value> data;
+ property public final int itemsAfter;
+ property public final int itemsBefore;
+ property public final Key? nextKey;
+ property public final Key? prevKey;
+ field public static final int COUNT_UNDEFINED = -2147483648; // 0x80000000
+ field public static final androidx.paging.PagingSource.LoadResult.Page.Companion Companion;
+ }
+
+ public static final class PagingSource.LoadResult.Page.Companion {
+ }
+
+ public fun interface PagingSourceFactory<Key, Value> extends kotlin.jvm.functions.Function0<androidx.paging.PagingSource<Key,Value>> {
+ method public operator androidx.paging.PagingSource<Key,Value> invoke();
+ }
+
+ public final class PagingState<Key, Value> {
+ ctor public PagingState(java.util.List<androidx.paging.PagingSource.LoadResult.Page<Key,Value>> pages, Integer? anchorPosition, androidx.paging.PagingConfig config, @IntRange(from=0L) int leadingPlaceholderCount);
+ method public Value? closestItemToPosition(int anchorPosition);
+ method public androidx.paging.PagingSource.LoadResult.Page<Key,Value>? closestPageToPosition(int anchorPosition);
+ method public Value? firstItemOrNull();
+ method public Integer? getAnchorPosition();
+ method public androidx.paging.PagingConfig getConfig();
+ method public java.util.List<androidx.paging.PagingSource.LoadResult.Page<Key,Value>> getPages();
+ method public boolean isEmpty();
+ method public Value? lastItemOrNull();
+ property public final Integer? anchorPosition;
+ property public final androidx.paging.PagingConfig config;
+ property public final java.util.List<androidx.paging.PagingSource.LoadResult.Page<Key,Value>> pages;
+ }
+
+ @Deprecated public abstract class PositionalDataSource<T> extends androidx.paging.DataSource<java.lang.Integer,T> {
+ ctor @Deprecated public PositionalDataSource();
+ method @Deprecated public static final int computeInitialLoadPosition(androidx.paging.PositionalDataSource.LoadInitialParams params, int totalCount);
+ method @Deprecated public static final int computeInitialLoadSize(androidx.paging.PositionalDataSource.LoadInitialParams params, int initialLoadPosition, int totalCount);
+ method @Deprecated @WorkerThread public abstract void loadInitial(androidx.paging.PositionalDataSource.LoadInitialParams params, androidx.paging.PositionalDataSource.LoadInitialCallback<T> callback);
+ method @Deprecated @WorkerThread public abstract void loadRange(androidx.paging.PositionalDataSource.LoadRangeParams params, androidx.paging.PositionalDataSource.LoadRangeCallback<T> callback);
+ method @Deprecated public final <V> androidx.paging.PositionalDataSource<V> map(androidx.arch.core.util.Function<T,V> function);
+ method @Deprecated public final <V> androidx.paging.PositionalDataSource<V> map(kotlin.jvm.functions.Function1<? super T,? extends V> function);
+ method @Deprecated public final <V> androidx.paging.PositionalDataSource<V> mapByPage(androidx.arch.core.util.Function<java.util.List<T>,java.util.List<V>> function);
+ method @Deprecated public final <V> androidx.paging.PositionalDataSource<V> mapByPage(kotlin.jvm.functions.Function1<? super java.util.List<? extends T>,? extends java.util.List<? extends V>> function);
+ }
+
+ @Deprecated public abstract static class PositionalDataSource.LoadInitialCallback<T> {
+ ctor @Deprecated public PositionalDataSource.LoadInitialCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends T> data, int position);
+ method @Deprecated public abstract void onResult(java.util.List<? extends T> data, int position, int totalCount);
+ }
+
+ @Deprecated public static class PositionalDataSource.LoadInitialParams {
+ ctor @Deprecated public PositionalDataSource.LoadInitialParams(int requestedStartPosition, int requestedLoadSize, int pageSize, boolean placeholdersEnabled);
+ field @Deprecated public final int pageSize;
+ field @Deprecated public final boolean placeholdersEnabled;
+ field @Deprecated public final int requestedLoadSize;
+ field @Deprecated public final int requestedStartPosition;
+ }
+
+ @Deprecated public abstract static class PositionalDataSource.LoadRangeCallback<T> {
+ ctor @Deprecated public PositionalDataSource.LoadRangeCallback();
+ method @Deprecated public abstract void onResult(java.util.List<? extends T> data);
+ }
+
+ @Deprecated public static class PositionalDataSource.LoadRangeParams {
+ ctor @Deprecated public PositionalDataSource.LoadRangeParams(int startPosition, int loadSize);
+ field @Deprecated public final int loadSize;
+ field @Deprecated public final int startPosition;
+ }
+
+ @androidx.paging.ExperimentalPagingApi public abstract class RemoteMediator<Key, Value> {
+ ctor public RemoteMediator();
+ method public suspend Object? initialize(kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.InitializeAction>);
+ method public abstract suspend Object? load(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state, kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.MediatorResult>);
+ }
+
+ public enum RemoteMediator.InitializeAction {
+ method public static androidx.paging.RemoteMediator.InitializeAction valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.paging.RemoteMediator.InitializeAction[] values();
+ enum_constant public static final androidx.paging.RemoteMediator.InitializeAction LAUNCH_INITIAL_REFRESH;
+ enum_constant public static final androidx.paging.RemoteMediator.InitializeAction SKIP_INITIAL_REFRESH;
+ }
+
+ public abstract static sealed class RemoteMediator.MediatorResult {
+ }
+
+ public static final class RemoteMediator.MediatorResult.Error extends androidx.paging.RemoteMediator.MediatorResult {
+ ctor public RemoteMediator.MediatorResult.Error(Throwable throwable);
+ method public Throwable getThrowable();
+ property public final Throwable throwable;
+ }
+
+ public static final class RemoteMediator.MediatorResult.Success extends androidx.paging.RemoteMediator.MediatorResult {
+ ctor public RemoteMediator.MediatorResult.Success(boolean endOfPaginationReached);
+ method public boolean getEndOfPaginationReached();
+ property public final boolean endOfPaginationReached;
+ }
+
+ public enum TerminalSeparatorType {
+ method public static androidx.paging.TerminalSeparatorType valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.paging.TerminalSeparatorType[] values();
+ enum_constant public static final androidx.paging.TerminalSeparatorType FULLY_COMPLETE;
+ enum_constant public static final androidx.paging.TerminalSeparatorType SOURCE_COMPLETE;
+ }
+
+}
+
diff --git a/paging/paging-common/build.gradle b/paging/paging-common/build.gradle
index bbc62bf..462a7f2 100644
--- a/paging/paging-common/build.gradle
+++ b/paging/paging-common/build.gradle
@@ -29,7 +29,7 @@
// syntax is temp workaround to allow project dependency on cross-project-set
// i.e. COMPOSE + MAIN project sets
// update syntax when b/239979823 is fixed
- implementation("androidx.paging:paging-compose:${androidx.LibraryVersions.PAGING_COMPOSE}")
+ implementation("androidx.paging:paging-compose:${androidx.LibraryVersions.PAGING}")
}
api("androidx.annotation:annotation:1.3.0")
diff --git a/paging/paging-compose/api/3.2.0-beta01.txt b/paging/paging-compose/api/3.2.0-beta01.txt
new file mode 100644
index 0000000..173f509
--- /dev/null
+++ b/paging/paging-compose/api/3.2.0-beta01.txt
@@ -0,0 +1,27 @@
+// Signature format: 4.0
+package androidx.paging.compose {
+
+ public final class LazyFoundationExtensionsKt {
+ method public static <T> kotlin.jvm.functions.Function1<java.lang.Integer,java.lang.Object> itemContentType(androidx.paging.compose.LazyPagingItems<T>, optional kotlin.jvm.functions.Function1<T,?>? contentType);
+ method public static <T> kotlin.jvm.functions.Function1<java.lang.Integer,java.lang.Object> itemKey(androidx.paging.compose.LazyPagingItems<T>, optional kotlin.jvm.functions.Function1<T,?>? key);
+ }
+
+ public final class LazyPagingItems<T> {
+ method public operator T? get(int index);
+ method public int getItemCount();
+ method public androidx.paging.ItemSnapshotList<T> getItemSnapshotList();
+ method public androidx.paging.CombinedLoadStates getLoadState();
+ method public T? peek(int index);
+ method public void refresh();
+ method public void retry();
+ property public final int itemCount;
+ property public final androidx.paging.ItemSnapshotList<T> itemSnapshotList;
+ property public final androidx.paging.CombinedLoadStates loadState;
+ }
+
+ public final class LazyPagingItemsKt {
+ method @androidx.compose.runtime.Composable public static <T> androidx.paging.compose.LazyPagingItems<T> collectAsLazyPagingItems(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<T>>, optional kotlin.coroutines.CoroutineContext context);
+ }
+
+}
+
diff --git a/paging/paging-compose/api/current.txt b/paging/paging-compose/api/current.txt
index 79638bd..173f509 100644
--- a/paging/paging-compose/api/current.txt
+++ b/paging/paging-compose/api/current.txt
@@ -21,8 +21,6 @@
public final class LazyPagingItemsKt {
method @androidx.compose.runtime.Composable public static <T> androidx.paging.compose.LazyPagingItems<T> collectAsLazyPagingItems(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<T>>, optional kotlin.coroutines.CoroutineContext context);
- method @Deprecated public static <T> void items(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, optional kotlin.jvm.functions.Function1<? super T,?>? contentType, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
- method @Deprecated public static <T> void itemsIndexed(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? contentType, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.LazyItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
}
}
diff --git a/paging/paging-compose/api/res-3.2.0-beta01.txt b/paging/paging-compose/api/res-3.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/paging/paging-compose/api/res-3.2.0-beta01.txt
diff --git a/paging/paging-compose/api/restricted_3.2.0-beta01.txt b/paging/paging-compose/api/restricted_3.2.0-beta01.txt
new file mode 100644
index 0000000..173f509
--- /dev/null
+++ b/paging/paging-compose/api/restricted_3.2.0-beta01.txt
@@ -0,0 +1,27 @@
+// Signature format: 4.0
+package androidx.paging.compose {
+
+ public final class LazyFoundationExtensionsKt {
+ method public static <T> kotlin.jvm.functions.Function1<java.lang.Integer,java.lang.Object> itemContentType(androidx.paging.compose.LazyPagingItems<T>, optional kotlin.jvm.functions.Function1<T,?>? contentType);
+ method public static <T> kotlin.jvm.functions.Function1<java.lang.Integer,java.lang.Object> itemKey(androidx.paging.compose.LazyPagingItems<T>, optional kotlin.jvm.functions.Function1<T,?>? key);
+ }
+
+ public final class LazyPagingItems<T> {
+ method public operator T? get(int index);
+ method public int getItemCount();
+ method public androidx.paging.ItemSnapshotList<T> getItemSnapshotList();
+ method public androidx.paging.CombinedLoadStates getLoadState();
+ method public T? peek(int index);
+ method public void refresh();
+ method public void retry();
+ property public final int itemCount;
+ property public final androidx.paging.ItemSnapshotList<T> itemSnapshotList;
+ property public final androidx.paging.CombinedLoadStates loadState;
+ }
+
+ public final class LazyPagingItemsKt {
+ method @androidx.compose.runtime.Composable public static <T> androidx.paging.compose.LazyPagingItems<T> collectAsLazyPagingItems(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<T>>, optional kotlin.coroutines.CoroutineContext context);
+ }
+
+}
+
diff --git a/paging/paging-compose/api/restricted_current.txt b/paging/paging-compose/api/restricted_current.txt
index 79638bd..173f509 100644
--- a/paging/paging-compose/api/restricted_current.txt
+++ b/paging/paging-compose/api/restricted_current.txt
@@ -21,8 +21,6 @@
public final class LazyPagingItemsKt {
method @androidx.compose.runtime.Composable public static <T> androidx.paging.compose.LazyPagingItems<T> collectAsLazyPagingItems(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<T>>, optional kotlin.coroutines.CoroutineContext context);
- method @Deprecated public static <T> void items(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, optional kotlin.jvm.functions.Function1<? super T,?>? contentType, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
- method @Deprecated public static <T> void itemsIndexed(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? contentType, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.LazyItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
}
}
diff --git a/paging/paging-compose/build.gradle b/paging/paging-compose/build.gradle
index 8affe5a..b08c7ea 100644
--- a/paging/paging-compose/build.gradle
+++ b/paging/paging-compose/build.gradle
@@ -45,7 +45,6 @@
androidx {
name = "Paging-Compose"
publish = Publish.SNAPSHOT_AND_RELEASE
- mavenVersion = LibraryVersions.PAGING_COMPOSE
inceptionYear = "2020"
description = "Compose integration with Paging"
runApiTasks = new RunApiTasks.Yes()
diff --git a/paging/paging-compose/integration-tests/paging-demos/build.gradle b/paging/paging-compose/integration-tests/paging-demos/build.gradle
index e34ca03..c417575 100644
--- a/paging/paging-compose/integration-tests/paging-demos/build.gradle
+++ b/paging/paging-compose/integration-tests/paging-demos/build.gradle
@@ -26,6 +26,9 @@
dependencies {
implementation(libs.kotlinStdlib)
+ // workaround for https://github.com/gradle/gradle/issues/8489
+ implementation("androidx.activity:activity:1.7.1")
+ implementation("androidx.lifecycle:lifecycle-common:2.6.1")
implementation(projectOrArtifact(":compose:integration-tests:demos:common"))
implementation(projectOrArtifact(":compose:foundation:foundation"))
diff --git a/paging/paging-compose/samples/build.gradle b/paging/paging-compose/samples/build.gradle
index 753063b..0e561d0 100644
--- a/paging/paging-compose/samples/build.gradle
+++ b/paging/paging-compose/samples/build.gradle
@@ -36,7 +36,6 @@
androidx {
name = "Paging Compose Samples"
type = LibraryType.SAMPLES
- mavenVersion = LibraryVersions.PAGING_COMPOSE
inceptionYear = "2020"
description = "Contains the sample code for the Androidx Paging library compose interop"
}
diff --git a/paging/paging-compose/samples/src/main/java/androidx/paging/compose/samples/PagingSample.kt b/paging/paging-compose/samples/src/main/java/androidx/paging/compose/samples/PagingSample.kt
index 26c90ad..382badfc 100644
--- a/paging/paging-compose/samples/src/main/java/androidx/paging/compose/samples/PagingSample.kt
+++ b/paging/paging-compose/samples/src/main/java/androidx/paging/compose/samples/PagingSample.kt
@@ -81,7 +81,6 @@
}
}
-@Sampled
@Composable
fun ItemsDemo(flow: Flow<PagingData<String>>) {
val lazyPagingItems = flow.collectAsLazyPagingItems()
@@ -96,7 +95,6 @@
}
}
-@Sampled
@Composable
fun ItemsIndexedDemo(flow: Flow<PagingData<String>>) {
val lazyPagingItems = flow.collectAsLazyPagingItems()
diff --git a/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt b/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt
index f112c3f..f98b422 100644
--- a/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt
+++ b/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt
@@ -58,7 +58,6 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import org.junit.Assert.assertFalse
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -202,37 +201,6 @@
.assertDoesNotExist()
}
- @Suppress("DEPRECATION")
- @Test
- fun lazyPagingColumnShowsIndexedItems() {
- val pager = createPager()
- rule.setContent {
- val lazyPagingItems = pager.flow.collectAsLazyPagingItems()
- LazyColumn(Modifier.height(200.dp)) {
- itemsIndexed(lazyPagingItems) { index, item ->
- Spacer(
- Modifier.height(101.dp).fillParentMaxWidth()
- .testTag("$index-$item")
- )
- }
- }
- }
-
- rule.waitForIdle()
-
- rule.onNodeWithTag("0-1")
- .assertIsDisplayed()
-
- rule.onNodeWithTag("1-2")
- .assertIsDisplayed()
-
- rule.onNodeWithTag("2-3")
- .assertDoesNotExist()
-
- rule.onNodeWithTag("3-4")
- .assertDoesNotExist()
- }
-
@Test
fun lazyPagingRowShowsItems() {
val pager = createPager()
@@ -261,37 +229,6 @@
.assertDoesNotExist()
}
- @Suppress("DEPRECATION")
- @Test
- fun lazyPagingRowShowsIndexedItems() {
- val pager = createPager()
- rule.setContent {
- val lazyPagingItems = pager.flow.collectAsLazyPagingItems()
- LazyRow(Modifier.width(200.dp)) {
- itemsIndexed(lazyPagingItems) { index, item ->
- Spacer(
- Modifier.width(101.dp).fillParentMaxHeight()
- .testTag("$index-$item")
- )
- }
- }
- }
-
- rule.waitForIdle()
-
- rule.onNodeWithTag("0-1")
- .assertIsDisplayed()
-
- rule.onNodeWithTag("1-2")
- .assertIsDisplayed()
-
- rule.onNodeWithTag("2-3")
- .assertDoesNotExist()
-
- rule.onNodeWithTag("3-4")
- .assertDoesNotExist()
- }
-
@Test
fun differentContentTypes() {
val pager = createPagerWithPlaceholders()
@@ -775,7 +712,6 @@
.assertTopPositionInRootIsEqualTo(itemSize * 2)
}
- @Ignore // b/229089541
@Test
fun removingItem() {
val items = mutableListOf(1, 2, 3)
@@ -797,7 +733,10 @@
rule.setContent {
lazyPagingItems = pager.flow.collectAsLazyPagingItems()
LazyColumn(Modifier.height(itemSize * 3)) {
- items(count = lazyPagingItems.itemCount) { index ->
+ items(
+ count = lazyPagingItems.itemCount,
+ key = lazyPagingItems.itemKey { it }
+ ) { index ->
val item = lazyPagingItems[index]
Spacer(Modifier.height(itemSize).fillParentMaxWidth().testTag("$item"))
}
@@ -817,7 +756,7 @@
.assertTopPositionInRootIsEqualTo(itemSize)
rule.onNodeWithTag("1")
- .assertDoesNotExist()
+ .assertIsNotDisplayed()
}
@Test
@@ -857,39 +796,6 @@
.assertExists()
}
- @Suppress("DEPRECATION")
- @Test
- fun stateIsMovedWithItemWithCustomKey_itemsIndexed() {
- val items = mutableListOf(1)
- val pager = createPager {
- TestPagingSource(items = items, loadDelay = 0)
- }
-
- lateinit var lazyPagingItems: LazyPagingItems<Int>
- rule.setContent {
- lazyPagingItems = pager.flow.collectAsLazyPagingItems()
- LazyColumn {
- itemsIndexed(lazyPagingItems, key = { _, item -> item }) { index, item ->
- BasicText(
- "Item=$item. index=$index. remembered index=${remember { index }}"
- )
- }
- }
- }
-
- rule.runOnIdle {
- items.clear()
- items.addAll(listOf(0, 1))
- lazyPagingItems.refresh()
- }
-
- rule.onNodeWithText("Item=0. index=0. remembered index=0")
- .assertExists()
-
- rule.onNodeWithText("Item=1. index=1. remembered index=0")
- .assertExists()
- }
-
@Test
fun collectOnDefaultThread() {
val items = mutableListOf(1, 2, 3)
diff --git a/paging/paging-compose/src/main/java/androidx/paging/compose/LazyPagingItems.kt b/paging/paging-compose/src/main/java/androidx/paging/compose/LazyPagingItems.kt
index 0c0082d..bef33c6 100644
--- a/paging/paging-compose/src/main/java/androidx/paging/compose/LazyPagingItems.kt
+++ b/paging/paging-compose/src/main/java/androidx/paging/compose/LazyPagingItems.kt
@@ -17,7 +17,6 @@
package androidx.paging.compose
import android.util.Log
-import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -291,128 +290,3 @@
return lazyPagingItems
}
-
-/**
- * Adds the [LazyPagingItems] and their content to the scope. The range from 0 (inclusive) to
- * [LazyPagingItems.itemCount] (exclusive) always represents the full range of presentable items,
- * because every event from [PagingDataDiffer] will trigger a recomposition.
- *
- * @sample androidx.paging.compose.samples.ItemsDemo
- *
- * @param items the items received from a [Flow] of [PagingData].
- * @param key a factory of stable and unique keys representing the item. Using the same key
- * for multiple items in the list is not allowed. Type of the key should be saveable
- * via Bundle on Android. If null is passed the position in the list will represent the key.
- * When you specify the key the scroll position will be maintained based on the key, which
- * means if you add/remove items before the current visible item the item with the given key
- * will be kept as the first visible one.
- * @param contentType a factory of the content types for the item. The item compositions of the
- * same type could be reused more efficiently. Note that null is a valid type and items of such
- * type will be considered compatible.
- * @param itemContent the content displayed by a single item. In case the item is `null`, the
- * [itemContent] method should handle the logic of displaying a placeholder instead of the main
- * content displayed by an item which is not `null`.
- *
- * @deprecated Call [LazyListScope.items] directly with LazyPagingItems [itemKey] and
- * [itemContentType] helper functions.
- */
-@Deprecated(
- message = "Call LazyListScope.items directly with LazyPagingItems #itemKey and " +
- "#itemContentType helper functions.",
- replaceWith = ReplaceWith(
- expression = """items(
- count = items.itemCount,
- key = items.itemKey(key),
- contentType = items.itemContentType(
- contentType
- )
- ) { index ->
- val item = items[index]
- itemContent(item)
- }""",
- )
-)
-public fun <T : Any> LazyListScope.items(
- items: LazyPagingItems<T>,
- key: ((item: T) -> Any)? = null,
- contentType: ((item: T) -> Any?)? = null,
- itemContent: @Composable LazyItemScope.(value: T?) -> Unit
-) {
- items(
- count = items.itemCount,
- key = items.itemKey(key),
- contentType = items.itemContentType(contentType)
- ) { index ->
- itemContent(items[index])
- }
-}
-
-/**
- * Adds the [LazyPagingItems] and their content to the scope where the content of an item is
- * aware of its local index. The range from 0 (inclusive) to [LazyPagingItems.itemCount] (exclusive)
- * always represents the full range of presentable items, because every event from
- * [PagingDataDiffer] will trigger a recomposition.
- *
- * @sample androidx.paging.compose.samples.ItemsIndexedDemo
- *
- * @param items the items received from a [Flow] of [PagingData].
- * @param key a factory of stable and unique keys representing the item. Using the same key
- * for multiple items in the list is not allowed. Type of the key should be saveable
- * via Bundle on Android. If null is passed the position in the list will represent the key.
- * When you specify the key the scroll position will be maintained based on the key, which
- * means if you add/remove items before the current visible item the item with the given key
- * will be kept as the first visible one.
- * @param contentType a factory of the content types for the item. The item compositions of the
- * same type could be reused more efficiently. Note that null is a valid type and items of such
- * type will be considered compatible.
- * @param itemContent the content displayed by a single item. In case the item is `null`, the
- * [itemContent] method should handle the logic of displaying a placeholder instead of the main
- * content displayed by an item which is not `null`.
- *
- * @deprecated Deprecating support for indexed keys on non-null items as it is susceptible to
- * errors when items indices shift due to prepends. Call LazyListScope.items directly
- * with LazyPagingItems #itemKey and #itemContentType helper functions.
- */
-@Deprecated(
- message = "Deprecating support for indexed keys on non-null items as it is susceptible to " +
- "errors when items indices shift due to prepends. Call LazyListScope.items directly " +
- "with LazyPagingItems #itemKey and #itemContentType helper functions.",
- replaceWith = ReplaceWith(
- expression = """items(
- count = items.itemCount,
- key = items.itemKey(key),
- contentType = items.itemContentType(
- contentType
- )
- ) { index ->
- val item = items[index]
- itemContent(item)
- }""",
- )
-)
-public fun <T : Any> LazyListScope.itemsIndexed(
- items: LazyPagingItems<T>,
- key: ((index: Int, item: T) -> Any)? = null,
- contentType: ((index: Int, item: T) -> Any?)? = null,
- itemContent: @Composable LazyItemScope.(index: Int, value: T?) -> Unit
-) {
- items(
- count = items.itemCount,
- key = if (key == null) null else { index ->
- val item = items.peek(index)
- if (item == null) {
- PagingPlaceholderKey(index)
- } else {
- key(index, item)
- }
- },
- contentType = { index ->
- if (contentType == null) null else {
- val item = items.peek(index)
- if (item == null) null else contentType(index, item)
- }
- }
- ) { index ->
- itemContent(index, items[index])
- }
-}
diff --git a/paging/paging-guava/api/3.2.0-beta01.txt b/paging/paging-guava/api/3.2.0-beta01.txt
new file mode 100644
index 0000000..7a925fd
--- /dev/null
+++ b/paging/paging-guava/api/3.2.0-beta01.txt
@@ -0,0 +1,37 @@
+// Signature format: 4.0
+package androidx.paging {
+
+ public final class AdjacentItems<T> {
+ ctor public AdjacentItems(T? before, T? after);
+ method public T? component1();
+ method public T? component2();
+ method public androidx.paging.AdjacentItems<T> copy(T? before, T? after);
+ method public T? getAfter();
+ method public T? getBefore();
+ property public final T? after;
+ property public final T? before;
+ }
+
+ public abstract class ListenableFuturePagingSource<Key, Value> extends androidx.paging.PagingSource<Key,Value> {
+ ctor public ListenableFuturePagingSource();
+ method public suspend Object? load(androidx.paging.PagingSource.LoadParams<Key> params, kotlin.coroutines.Continuation<? super androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.paging.PagingSource.LoadResult<Key,Value>> loadFuture(androidx.paging.PagingSource.LoadParams<Key> params);
+ }
+
+ @androidx.paging.ExperimentalPagingApi public abstract class ListenableFutureRemoteMediator<Key, Value> extends androidx.paging.RemoteMediator<Key,Value> {
+ ctor public ListenableFutureRemoteMediator();
+ method public final suspend Object? initialize(kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.InitializeAction>);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.paging.RemoteMediator.InitializeAction> initializeFuture();
+ method public final suspend Object? load(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state, kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.MediatorResult>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.paging.RemoteMediator.MediatorResult> loadFuture(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state);
+ }
+
+ public final class PagingDataFutures {
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform, java.util.concurrent.Executor executor);
+ }
+
+}
+
diff --git a/paging/paging-guava/api/res-3.2.0-beta01.txt b/paging/paging-guava/api/res-3.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/paging/paging-guava/api/res-3.2.0-beta01.txt
diff --git a/paging/paging-guava/api/restricted_3.2.0-beta01.txt b/paging/paging-guava/api/restricted_3.2.0-beta01.txt
new file mode 100644
index 0000000..7a925fd
--- /dev/null
+++ b/paging/paging-guava/api/restricted_3.2.0-beta01.txt
@@ -0,0 +1,37 @@
+// Signature format: 4.0
+package androidx.paging {
+
+ public final class AdjacentItems<T> {
+ ctor public AdjacentItems(T? before, T? after);
+ method public T? component1();
+ method public T? component2();
+ method public androidx.paging.AdjacentItems<T> copy(T? before, T? after);
+ method public T? getAfter();
+ method public T? getBefore();
+ property public final T? after;
+ property public final T? before;
+ }
+
+ public abstract class ListenableFuturePagingSource<Key, Value> extends androidx.paging.PagingSource<Key,Value> {
+ ctor public ListenableFuturePagingSource();
+ method public suspend Object? load(androidx.paging.PagingSource.LoadParams<Key> params, kotlin.coroutines.Continuation<? super androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.paging.PagingSource.LoadResult<Key,Value>> loadFuture(androidx.paging.PagingSource.LoadParams<Key> params);
+ }
+
+ @androidx.paging.ExperimentalPagingApi public abstract class ListenableFutureRemoteMediator<Key, Value> extends androidx.paging.RemoteMediator<Key,Value> {
+ ctor public ListenableFutureRemoteMediator();
+ method public final suspend Object? initialize(kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.InitializeAction>);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.paging.RemoteMediator.InitializeAction> initializeFuture();
+ method public final suspend Object? load(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state, kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.MediatorResult>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.paging.RemoteMediator.MediatorResult> loadFuture(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state);
+ }
+
+ public final class PagingDataFutures {
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform, java.util.concurrent.Executor executor);
+ }
+
+}
+
diff --git a/paging/paging-runtime-ktx/api/3.2.0-beta01.txt b/paging/paging-runtime-ktx/api/3.2.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/paging/paging-runtime-ktx/api/3.2.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/paging/paging-runtime-ktx/api/res-3.2.0-beta01.txt b/paging/paging-runtime-ktx/api/res-3.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/paging/paging-runtime-ktx/api/res-3.2.0-beta01.txt
diff --git a/paging/paging-runtime-ktx/api/restricted_3.2.0-beta01.txt b/paging/paging-runtime-ktx/api/restricted_3.2.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/paging/paging-runtime-ktx/api/restricted_3.2.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/paging/paging-runtime/api/3.2.0-beta01.txt b/paging/paging-runtime/api/3.2.0-beta01.txt
new file mode 100644
index 0000000..ab368d2
--- /dev/null
+++ b/paging/paging-runtime/api/3.2.0-beta01.txt
@@ -0,0 +1,140 @@
+// Signature format: 4.0
+package androidx.paging {
+
+ @Deprecated public class AsyncPagedListDiffer<T> {
+ ctor @Deprecated public AsyncPagedListDiffer(androidx.recyclerview.widget.ListUpdateCallback listUpdateCallback, androidx.recyclerview.widget.AsyncDifferConfig<T> config);
+ ctor @Deprecated public AsyncPagedListDiffer(androidx.recyclerview.widget.RecyclerView.Adapter<?> adapter, androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
+ method @Deprecated public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public void addPagedListListener(androidx.paging.AsyncPagedListDiffer.PagedListListener<T> listener);
+ method @Deprecated public final void addPagedListListener(kotlin.jvm.functions.Function2<? super androidx.paging.PagedList<T>,? super androidx.paging.PagedList<T>,kotlin.Unit> callback);
+ method @Deprecated public androidx.paging.PagedList<T>? getCurrentList();
+ method @Deprecated public T? getItem(int index);
+ method @Deprecated public int getItemCount();
+ method @Deprecated public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public void removePagedListListener(androidx.paging.AsyncPagedListDiffer.PagedListListener<T> listener);
+ method @Deprecated public final void removePagedListListener(kotlin.jvm.functions.Function2<? super androidx.paging.PagedList<T>,? super androidx.paging.PagedList<T>,kotlin.Unit> callback);
+ method @Deprecated public void submitList(androidx.paging.PagedList<T>? pagedList);
+ method @Deprecated public void submitList(androidx.paging.PagedList<T>? pagedList, Runnable? commitCallback);
+ property @Deprecated public androidx.paging.PagedList<T>? currentList;
+ property @Deprecated public int itemCount;
+ }
+
+ @Deprecated public static interface AsyncPagedListDiffer.PagedListListener<T> {
+ method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? previousList, androidx.paging.PagedList<T>? currentList);
+ }
+
+ public final class AsyncPagingDataDiffer<T> {
+ ctor public AsyncPagingDataDiffer(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, androidx.recyclerview.widget.ListUpdateCallback updateCallback);
+ ctor public AsyncPagingDataDiffer(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, androidx.recyclerview.widget.ListUpdateCallback updateCallback, optional kotlin.coroutines.CoroutineContext mainDispatcher);
+ ctor public AsyncPagingDataDiffer(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, androidx.recyclerview.widget.ListUpdateCallback updateCallback, optional kotlin.coroutines.CoroutineContext mainDispatcher, optional kotlin.coroutines.CoroutineContext workerDispatcher);
+ ctor @Deprecated public AsyncPagingDataDiffer(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, androidx.recyclerview.widget.ListUpdateCallback updateCallback, optional kotlinx.coroutines.CoroutineDispatcher mainDispatcher);
+ ctor @Deprecated public AsyncPagingDataDiffer(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, androidx.recyclerview.widget.ListUpdateCallback updateCallback, optional kotlinx.coroutines.CoroutineDispatcher mainDispatcher, optional kotlinx.coroutines.CoroutineDispatcher workerDispatcher);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function1<? super androidx.paging.CombinedLoadStates,kotlin.Unit> listener);
+ method public void addOnPagesUpdatedListener(kotlin.jvm.functions.Function0<kotlin.Unit> listener);
+ method @MainThread public T? getItem(@IntRange(from=0L) int index);
+ method public int getItemCount();
+ method public kotlinx.coroutines.flow.Flow<androidx.paging.CombinedLoadStates> getLoadStateFlow();
+ method public kotlinx.coroutines.flow.Flow<kotlin.Unit> getOnPagesUpdatedFlow();
+ method @MainThread public T? peek(@IntRange(from=0L) int index);
+ method public void refresh();
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function1<? super androidx.paging.CombinedLoadStates,kotlin.Unit> listener);
+ method public void removeOnPagesUpdatedListener(kotlin.jvm.functions.Function0<kotlin.Unit> listener);
+ method public void retry();
+ method public androidx.paging.ItemSnapshotList<T> snapshot();
+ method public void submitData(androidx.lifecycle.Lifecycle lifecycle, androidx.paging.PagingData<T> pagingData);
+ method public suspend Object? submitData(androidx.paging.PagingData<T> pagingData, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final int itemCount;
+ property public final kotlinx.coroutines.flow.Flow<androidx.paging.CombinedLoadStates> loadStateFlow;
+ property public final kotlinx.coroutines.flow.Flow<kotlin.Unit> onPagesUpdatedFlow;
+ }
+
+ @Deprecated public final class LivePagedListBuilder<Key, Value> {
+ ctor @Deprecated public LivePagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public LivePagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, int pageSize);
+ ctor @Deprecated public LivePagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public LivePagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, int pageSize);
+ method @Deprecated public androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> build();
+ method @Deprecated public androidx.paging.LivePagedListBuilder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
+ method @Deprecated public androidx.paging.LivePagedListBuilder<Key,Value> setCoroutineScope(kotlinx.coroutines.CoroutineScope coroutineScope);
+ method @Deprecated public androidx.paging.LivePagedListBuilder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
+ method @Deprecated public androidx.paging.LivePagedListBuilder<Key,Value> setInitialLoadKey(Key? key);
+ }
+
+ public final class LivePagedListKt {
+ method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional java.util.concurrent.Executor fetchExecutor);
+ method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional java.util.concurrent.Executor fetchExecutor);
+ method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional kotlinx.coroutines.CoroutineScope coroutineScope, optional kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional kotlinx.coroutines.CoroutineScope coroutineScope, optional kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ }
+
+ public abstract class LoadStateAdapter<VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
+ ctor public LoadStateAdapter();
+ method public boolean displayLoadStateAsItem(androidx.paging.LoadState loadState);
+ method public final int getItemCount();
+ method public final int getItemViewType(int position);
+ method public final androidx.paging.LoadState getLoadState();
+ method public int getStateViewType(androidx.paging.LoadState loadState);
+ method public abstract void onBindViewHolder(VH holder, androidx.paging.LoadState loadState);
+ method public final void onBindViewHolder(VH holder, int position);
+ method public abstract VH onCreateViewHolder(android.view.ViewGroup parent, androidx.paging.LoadState loadState);
+ method public final VH onCreateViewHolder(android.view.ViewGroup parent, int viewType);
+ method public final void setLoadState(androidx.paging.LoadState);
+ property public final androidx.paging.LoadState loadState;
+ }
+
+ @Deprecated public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
+ ctor @Deprecated protected PagedListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T> config);
+ ctor @Deprecated protected PagedListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
+ method @Deprecated public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public androidx.paging.PagedList<T>? getCurrentList();
+ method @Deprecated protected T? getItem(int position);
+ method @Deprecated public int getItemCount();
+ method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? currentList);
+ method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? previousList, androidx.paging.PagedList<T>? currentList);
+ method @Deprecated public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public void submitList(androidx.paging.PagedList<T>? pagedList);
+ method @Deprecated public void submitList(androidx.paging.PagedList<T>? pagedList, Runnable? commitCallback);
+ method @Deprecated public final androidx.recyclerview.widget.ConcatAdapter withLoadStateFooter(androidx.paging.LoadStateAdapter<?> footer);
+ method @Deprecated public final androidx.recyclerview.widget.ConcatAdapter withLoadStateHeader(androidx.paging.LoadStateAdapter<?> header);
+ method @Deprecated public final androidx.recyclerview.widget.ConcatAdapter withLoadStateHeaderAndFooter(androidx.paging.LoadStateAdapter<?> header, androidx.paging.LoadStateAdapter<?> footer);
+ property @Deprecated public androidx.paging.PagedList<T>? currentList;
+ }
+
+ public abstract class PagingDataAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
+ ctor public PagingDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
+ ctor public PagingDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, optional kotlin.coroutines.CoroutineContext mainDispatcher);
+ ctor public PagingDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, optional kotlin.coroutines.CoroutineContext mainDispatcher, optional kotlin.coroutines.CoroutineContext workerDispatcher);
+ ctor @Deprecated public PagingDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, optional kotlinx.coroutines.CoroutineDispatcher mainDispatcher);
+ ctor @Deprecated public PagingDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, optional kotlinx.coroutines.CoroutineDispatcher mainDispatcher, optional kotlinx.coroutines.CoroutineDispatcher workerDispatcher);
+ method public final void addLoadStateListener(kotlin.jvm.functions.Function1<? super androidx.paging.CombinedLoadStates,kotlin.Unit> listener);
+ method public final void addOnPagesUpdatedListener(kotlin.jvm.functions.Function0<kotlin.Unit> listener);
+ method @MainThread protected final T? getItem(@IntRange(from=0L) int position);
+ method public int getItemCount();
+ method public final long getItemId(int position);
+ method public final kotlinx.coroutines.flow.Flow<androidx.paging.CombinedLoadStates> getLoadStateFlow();
+ method public final kotlinx.coroutines.flow.Flow<kotlin.Unit> getOnPagesUpdatedFlow();
+ method @MainThread public final T? peek(@IntRange(from=0L) int index);
+ method public final void refresh();
+ method public final void removeLoadStateListener(kotlin.jvm.functions.Function1<? super androidx.paging.CombinedLoadStates,kotlin.Unit> listener);
+ method public final void removeOnPagesUpdatedListener(kotlin.jvm.functions.Function0<kotlin.Unit> listener);
+ method public final void retry();
+ method public final void setHasStableIds(boolean hasStableIds);
+ method public final androidx.paging.ItemSnapshotList<T> snapshot();
+ method public final void submitData(androidx.lifecycle.Lifecycle lifecycle, androidx.paging.PagingData<T> pagingData);
+ method public final suspend Object? submitData(androidx.paging.PagingData<T> pagingData, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public final androidx.recyclerview.widget.ConcatAdapter withLoadStateFooter(androidx.paging.LoadStateAdapter<?> footer);
+ method public final androidx.recyclerview.widget.ConcatAdapter withLoadStateHeader(androidx.paging.LoadStateAdapter<?> header);
+ method public final androidx.recyclerview.widget.ConcatAdapter withLoadStateHeaderAndFooter(androidx.paging.LoadStateAdapter<?> header, androidx.paging.LoadStateAdapter<?> footer);
+ property public final kotlinx.coroutines.flow.Flow<androidx.paging.CombinedLoadStates> loadStateFlow;
+ property public final kotlinx.coroutines.flow.Flow<kotlin.Unit> onPagesUpdatedFlow;
+ }
+
+ public final class PagingLiveData {
+ method public static <T> androidx.lifecycle.LiveData<androidx.paging.PagingData<T>> cachedIn(androidx.lifecycle.LiveData<androidx.paging.PagingData<T>>, androidx.lifecycle.Lifecycle lifecycle);
+ method public static <T> androidx.lifecycle.LiveData<androidx.paging.PagingData<T>> cachedIn(androidx.lifecycle.LiveData<androidx.paging.PagingData<T>>, androidx.lifecycle.ViewModel viewModel);
+ method public static <T> androidx.lifecycle.LiveData<androidx.paging.PagingData<T>> cachedIn(androidx.lifecycle.LiveData<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagingData<Value>> getLiveData(androidx.paging.Pager<Key,Value>);
+ }
+
+}
+
diff --git a/paging/paging-runtime/api/res-3.2.0-beta01.txt b/paging/paging-runtime/api/res-3.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/paging/paging-runtime/api/res-3.2.0-beta01.txt
diff --git a/paging/paging-runtime/api/restricted_3.2.0-beta01.txt b/paging/paging-runtime/api/restricted_3.2.0-beta01.txt
new file mode 100644
index 0000000..ab368d2
--- /dev/null
+++ b/paging/paging-runtime/api/restricted_3.2.0-beta01.txt
@@ -0,0 +1,140 @@
+// Signature format: 4.0
+package androidx.paging {
+
+ @Deprecated public class AsyncPagedListDiffer<T> {
+ ctor @Deprecated public AsyncPagedListDiffer(androidx.recyclerview.widget.ListUpdateCallback listUpdateCallback, androidx.recyclerview.widget.AsyncDifferConfig<T> config);
+ ctor @Deprecated public AsyncPagedListDiffer(androidx.recyclerview.widget.RecyclerView.Adapter<?> adapter, androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
+ method @Deprecated public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public void addPagedListListener(androidx.paging.AsyncPagedListDiffer.PagedListListener<T> listener);
+ method @Deprecated public final void addPagedListListener(kotlin.jvm.functions.Function2<? super androidx.paging.PagedList<T>,? super androidx.paging.PagedList<T>,kotlin.Unit> callback);
+ method @Deprecated public androidx.paging.PagedList<T>? getCurrentList();
+ method @Deprecated public T? getItem(int index);
+ method @Deprecated public int getItemCount();
+ method @Deprecated public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public void removePagedListListener(androidx.paging.AsyncPagedListDiffer.PagedListListener<T> listener);
+ method @Deprecated public final void removePagedListListener(kotlin.jvm.functions.Function2<? super androidx.paging.PagedList<T>,? super androidx.paging.PagedList<T>,kotlin.Unit> callback);
+ method @Deprecated public void submitList(androidx.paging.PagedList<T>? pagedList);
+ method @Deprecated public void submitList(androidx.paging.PagedList<T>? pagedList, Runnable? commitCallback);
+ property @Deprecated public androidx.paging.PagedList<T>? currentList;
+ property @Deprecated public int itemCount;
+ }
+
+ @Deprecated public static interface AsyncPagedListDiffer.PagedListListener<T> {
+ method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? previousList, androidx.paging.PagedList<T>? currentList);
+ }
+
+ public final class AsyncPagingDataDiffer<T> {
+ ctor public AsyncPagingDataDiffer(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, androidx.recyclerview.widget.ListUpdateCallback updateCallback);
+ ctor public AsyncPagingDataDiffer(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, androidx.recyclerview.widget.ListUpdateCallback updateCallback, optional kotlin.coroutines.CoroutineContext mainDispatcher);
+ ctor public AsyncPagingDataDiffer(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, androidx.recyclerview.widget.ListUpdateCallback updateCallback, optional kotlin.coroutines.CoroutineContext mainDispatcher, optional kotlin.coroutines.CoroutineContext workerDispatcher);
+ ctor @Deprecated public AsyncPagingDataDiffer(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, androidx.recyclerview.widget.ListUpdateCallback updateCallback, optional kotlinx.coroutines.CoroutineDispatcher mainDispatcher);
+ ctor @Deprecated public AsyncPagingDataDiffer(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, androidx.recyclerview.widget.ListUpdateCallback updateCallback, optional kotlinx.coroutines.CoroutineDispatcher mainDispatcher, optional kotlinx.coroutines.CoroutineDispatcher workerDispatcher);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function1<? super androidx.paging.CombinedLoadStates,kotlin.Unit> listener);
+ method public void addOnPagesUpdatedListener(kotlin.jvm.functions.Function0<kotlin.Unit> listener);
+ method @MainThread public T? getItem(@IntRange(from=0L) int index);
+ method public int getItemCount();
+ method public kotlinx.coroutines.flow.Flow<androidx.paging.CombinedLoadStates> getLoadStateFlow();
+ method public kotlinx.coroutines.flow.Flow<kotlin.Unit> getOnPagesUpdatedFlow();
+ method @MainThread public T? peek(@IntRange(from=0L) int index);
+ method public void refresh();
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function1<? super androidx.paging.CombinedLoadStates,kotlin.Unit> listener);
+ method public void removeOnPagesUpdatedListener(kotlin.jvm.functions.Function0<kotlin.Unit> listener);
+ method public void retry();
+ method public androidx.paging.ItemSnapshotList<T> snapshot();
+ method public void submitData(androidx.lifecycle.Lifecycle lifecycle, androidx.paging.PagingData<T> pagingData);
+ method public suspend Object? submitData(androidx.paging.PagingData<T> pagingData, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final int itemCount;
+ property public final kotlinx.coroutines.flow.Flow<androidx.paging.CombinedLoadStates> loadStateFlow;
+ property public final kotlinx.coroutines.flow.Flow<kotlin.Unit> onPagesUpdatedFlow;
+ }
+
+ @Deprecated public final class LivePagedListBuilder<Key, Value> {
+ ctor @Deprecated public LivePagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public LivePagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, int pageSize);
+ ctor @Deprecated public LivePagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public LivePagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, int pageSize);
+ method @Deprecated public androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> build();
+ method @Deprecated public androidx.paging.LivePagedListBuilder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
+ method @Deprecated public androidx.paging.LivePagedListBuilder<Key,Value> setCoroutineScope(kotlinx.coroutines.CoroutineScope coroutineScope);
+ method @Deprecated public androidx.paging.LivePagedListBuilder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
+ method @Deprecated public androidx.paging.LivePagedListBuilder<Key,Value> setInitialLoadKey(Key? key);
+ }
+
+ public final class LivePagedListKt {
+ method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional java.util.concurrent.Executor fetchExecutor);
+ method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional java.util.concurrent.Executor fetchExecutor);
+ method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional kotlinx.coroutines.CoroutineScope coroutineScope, optional kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional kotlinx.coroutines.CoroutineScope coroutineScope, optional kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ }
+
+ public abstract class LoadStateAdapter<VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
+ ctor public LoadStateAdapter();
+ method public boolean displayLoadStateAsItem(androidx.paging.LoadState loadState);
+ method public final int getItemCount();
+ method public final int getItemViewType(int position);
+ method public final androidx.paging.LoadState getLoadState();
+ method public int getStateViewType(androidx.paging.LoadState loadState);
+ method public abstract void onBindViewHolder(VH holder, androidx.paging.LoadState loadState);
+ method public final void onBindViewHolder(VH holder, int position);
+ method public abstract VH onCreateViewHolder(android.view.ViewGroup parent, androidx.paging.LoadState loadState);
+ method public final VH onCreateViewHolder(android.view.ViewGroup parent, int viewType);
+ method public final void setLoadState(androidx.paging.LoadState);
+ property public final androidx.paging.LoadState loadState;
+ }
+
+ @Deprecated public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
+ ctor @Deprecated protected PagedListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T> config);
+ ctor @Deprecated protected PagedListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
+ method @Deprecated public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public androidx.paging.PagedList<T>? getCurrentList();
+ method @Deprecated protected T? getItem(int position);
+ method @Deprecated public int getItemCount();
+ method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? currentList);
+ method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? previousList, androidx.paging.PagedList<T>? currentList);
+ method @Deprecated public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
+ method @Deprecated public void submitList(androidx.paging.PagedList<T>? pagedList);
+ method @Deprecated public void submitList(androidx.paging.PagedList<T>? pagedList, Runnable? commitCallback);
+ method @Deprecated public final androidx.recyclerview.widget.ConcatAdapter withLoadStateFooter(androidx.paging.LoadStateAdapter<?> footer);
+ method @Deprecated public final androidx.recyclerview.widget.ConcatAdapter withLoadStateHeader(androidx.paging.LoadStateAdapter<?> header);
+ method @Deprecated public final androidx.recyclerview.widget.ConcatAdapter withLoadStateHeaderAndFooter(androidx.paging.LoadStateAdapter<?> header, androidx.paging.LoadStateAdapter<?> footer);
+ property @Deprecated public androidx.paging.PagedList<T>? currentList;
+ }
+
+ public abstract class PagingDataAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
+ ctor public PagingDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
+ ctor public PagingDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, optional kotlin.coroutines.CoroutineContext mainDispatcher);
+ ctor public PagingDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, optional kotlin.coroutines.CoroutineContext mainDispatcher, optional kotlin.coroutines.CoroutineContext workerDispatcher);
+ ctor @Deprecated public PagingDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, optional kotlinx.coroutines.CoroutineDispatcher mainDispatcher);
+ ctor @Deprecated public PagingDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, optional kotlinx.coroutines.CoroutineDispatcher mainDispatcher, optional kotlinx.coroutines.CoroutineDispatcher workerDispatcher);
+ method public final void addLoadStateListener(kotlin.jvm.functions.Function1<? super androidx.paging.CombinedLoadStates,kotlin.Unit> listener);
+ method public final void addOnPagesUpdatedListener(kotlin.jvm.functions.Function0<kotlin.Unit> listener);
+ method @MainThread protected final T? getItem(@IntRange(from=0L) int position);
+ method public int getItemCount();
+ method public final long getItemId(int position);
+ method public final kotlinx.coroutines.flow.Flow<androidx.paging.CombinedLoadStates> getLoadStateFlow();
+ method public final kotlinx.coroutines.flow.Flow<kotlin.Unit> getOnPagesUpdatedFlow();
+ method @MainThread public final T? peek(@IntRange(from=0L) int index);
+ method public final void refresh();
+ method public final void removeLoadStateListener(kotlin.jvm.functions.Function1<? super androidx.paging.CombinedLoadStates,kotlin.Unit> listener);
+ method public final void removeOnPagesUpdatedListener(kotlin.jvm.functions.Function0<kotlin.Unit> listener);
+ method public final void retry();
+ method public final void setHasStableIds(boolean hasStableIds);
+ method public final androidx.paging.ItemSnapshotList<T> snapshot();
+ method public final void submitData(androidx.lifecycle.Lifecycle lifecycle, androidx.paging.PagingData<T> pagingData);
+ method public final suspend Object? submitData(androidx.paging.PagingData<T> pagingData, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public final androidx.recyclerview.widget.ConcatAdapter withLoadStateFooter(androidx.paging.LoadStateAdapter<?> footer);
+ method public final androidx.recyclerview.widget.ConcatAdapter withLoadStateHeader(androidx.paging.LoadStateAdapter<?> header);
+ method public final androidx.recyclerview.widget.ConcatAdapter withLoadStateHeaderAndFooter(androidx.paging.LoadStateAdapter<?> header, androidx.paging.LoadStateAdapter<?> footer);
+ property public final kotlinx.coroutines.flow.Flow<androidx.paging.CombinedLoadStates> loadStateFlow;
+ property public final kotlinx.coroutines.flow.Flow<kotlin.Unit> onPagesUpdatedFlow;
+ }
+
+ public final class PagingLiveData {
+ method public static <T> androidx.lifecycle.LiveData<androidx.paging.PagingData<T>> cachedIn(androidx.lifecycle.LiveData<androidx.paging.PagingData<T>>, androidx.lifecycle.Lifecycle lifecycle);
+ method public static <T> androidx.lifecycle.LiveData<androidx.paging.PagingData<T>> cachedIn(androidx.lifecycle.LiveData<androidx.paging.PagingData<T>>, androidx.lifecycle.ViewModel viewModel);
+ method public static <T> androidx.lifecycle.LiveData<androidx.paging.PagingData<T>> cachedIn(androidx.lifecycle.LiveData<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagingData<Value>> getLiveData(androidx.paging.Pager<Key,Value>);
+ }
+
+}
+
diff --git a/paging/paging-rxjava2-ktx/api/3.2.0-beta01.txt b/paging/paging-rxjava2-ktx/api/3.2.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/paging/paging-rxjava2-ktx/api/3.2.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/paging/paging-rxjava2-ktx/api/res-3.2.0-beta01.txt b/paging/paging-rxjava2-ktx/api/res-3.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/paging/paging-rxjava2-ktx/api/res-3.2.0-beta01.txt
diff --git a/paging/paging-rxjava2-ktx/api/restricted_3.2.0-beta01.txt b/paging/paging-rxjava2-ktx/api/restricted_3.2.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/paging/paging-rxjava2-ktx/api/restricted_3.2.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/paging/paging-rxjava2/api/3.2.0-beta01.txt b/paging/paging-rxjava2/api/3.2.0-beta01.txt
new file mode 100644
index 0000000..fb51a13
--- /dev/null
+++ b/paging/paging-rxjava2/api/3.2.0-beta01.txt
@@ -0,0 +1,58 @@
+// Signature format: 4.0
+package androidx.paging {
+
+ @Deprecated public final class RxPagedListBuilder<Key, Value> {
+ ctor @Deprecated public RxPagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public RxPagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, int pageSize);
+ ctor @Deprecated public RxPagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public RxPagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, int pageSize);
+ method @Deprecated public io.reactivex.Flowable<androidx.paging.PagedList<Value>> buildFlowable(io.reactivex.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public io.reactivex.Observable<androidx.paging.PagedList<Value>> buildObservable();
+ method @Deprecated public androidx.paging.RxPagedListBuilder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
+ method @Deprecated public androidx.paging.RxPagedListBuilder<Key,Value> setFetchScheduler(io.reactivex.Scheduler scheduler);
+ method @Deprecated public androidx.paging.RxPagedListBuilder<Key,Value> setInitialLoadKey(Key? key);
+ method @Deprecated public androidx.paging.RxPagedListBuilder<Key,Value> setNotifyScheduler(io.reactivex.Scheduler scheduler);
+ }
+
+ public final class RxPagedListKt {
+ method @Deprecated public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagedList<Value>> toFlowable(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler, optional io.reactivex.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagedList<Value>> toFlowable(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler, optional io.reactivex.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagedList<Value>> toFlowable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler, optional io.reactivex.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagedList<Value>> toFlowable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler, optional io.reactivex.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.Observable<androidx.paging.PagedList<Value>> toObservable(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.Observable<androidx.paging.PagedList<Value>> toObservable(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.Observable<androidx.paging.PagedList<Value>> toObservable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.Observable<androidx.paging.PagedList<Value>> toObservable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler);
+ }
+
+}
+
+package androidx.paging.rxjava2 {
+
+ public final class PagingRx {
+ method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.Flowable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.Flowable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.Observable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.Observable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+ method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
+ }
+
+ public abstract class RxPagingSource<Key, Value> extends androidx.paging.PagingSource<Key,Value> {
+ ctor public RxPagingSource();
+ method public final suspend Object? load(androidx.paging.PagingSource.LoadParams<Key> params, kotlin.coroutines.Continuation<? super androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public abstract io.reactivex.Single<androidx.paging.PagingSource.LoadResult<Key,Value>> loadSingle(androidx.paging.PagingSource.LoadParams<Key> params);
+ }
+
+ @androidx.paging.ExperimentalPagingApi public abstract class RxRemoteMediator<Key, Value> extends androidx.paging.RemoteMediator<Key,Value> {
+ ctor public RxRemoteMediator();
+ method public final suspend Object? initialize(kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.InitializeAction>);
+ method public io.reactivex.Single<androidx.paging.RemoteMediator.InitializeAction> initializeSingle();
+ method public final suspend Object? load(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state, kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.MediatorResult>);
+ method public abstract io.reactivex.Single<androidx.paging.RemoteMediator.MediatorResult> loadSingle(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state);
+ }
+
+}
+
diff --git a/paging/paging-rxjava2/api/res-3.2.0-beta01.txt b/paging/paging-rxjava2/api/res-3.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/paging/paging-rxjava2/api/res-3.2.0-beta01.txt
diff --git a/paging/paging-rxjava2/api/restricted_3.2.0-beta01.txt b/paging/paging-rxjava2/api/restricted_3.2.0-beta01.txt
new file mode 100644
index 0000000..fb51a13
--- /dev/null
+++ b/paging/paging-rxjava2/api/restricted_3.2.0-beta01.txt
@@ -0,0 +1,58 @@
+// Signature format: 4.0
+package androidx.paging {
+
+ @Deprecated public final class RxPagedListBuilder<Key, Value> {
+ ctor @Deprecated public RxPagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public RxPagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, int pageSize);
+ ctor @Deprecated public RxPagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public RxPagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, int pageSize);
+ method @Deprecated public io.reactivex.Flowable<androidx.paging.PagedList<Value>> buildFlowable(io.reactivex.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public io.reactivex.Observable<androidx.paging.PagedList<Value>> buildObservable();
+ method @Deprecated public androidx.paging.RxPagedListBuilder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
+ method @Deprecated public androidx.paging.RxPagedListBuilder<Key,Value> setFetchScheduler(io.reactivex.Scheduler scheduler);
+ method @Deprecated public androidx.paging.RxPagedListBuilder<Key,Value> setInitialLoadKey(Key? key);
+ method @Deprecated public androidx.paging.RxPagedListBuilder<Key,Value> setNotifyScheduler(io.reactivex.Scheduler scheduler);
+ }
+
+ public final class RxPagedListKt {
+ method @Deprecated public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagedList<Value>> toFlowable(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler, optional io.reactivex.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagedList<Value>> toFlowable(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler, optional io.reactivex.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagedList<Value>> toFlowable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler, optional io.reactivex.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagedList<Value>> toFlowable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler, optional io.reactivex.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.Observable<androidx.paging.PagedList<Value>> toObservable(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.Observable<androidx.paging.PagedList<Value>> toObservable(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.Observable<androidx.paging.PagedList<Value>> toObservable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.Observable<androidx.paging.PagedList<Value>> toObservable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.Scheduler? fetchScheduler, optional io.reactivex.Scheduler? notifyScheduler);
+ }
+
+}
+
+package androidx.paging.rxjava2 {
+
+ public final class PagingRx {
+ method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.Flowable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.Flowable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.Observable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.Observable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+ method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
+ }
+
+ public abstract class RxPagingSource<Key, Value> extends androidx.paging.PagingSource<Key,Value> {
+ ctor public RxPagingSource();
+ method public final suspend Object? load(androidx.paging.PagingSource.LoadParams<Key> params, kotlin.coroutines.Continuation<? super androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public abstract io.reactivex.Single<androidx.paging.PagingSource.LoadResult<Key,Value>> loadSingle(androidx.paging.PagingSource.LoadParams<Key> params);
+ }
+
+ @androidx.paging.ExperimentalPagingApi public abstract class RxRemoteMediator<Key, Value> extends androidx.paging.RemoteMediator<Key,Value> {
+ ctor public RxRemoteMediator();
+ method public final suspend Object? initialize(kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.InitializeAction>);
+ method public io.reactivex.Single<androidx.paging.RemoteMediator.InitializeAction> initializeSingle();
+ method public final suspend Object? load(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state, kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.MediatorResult>);
+ method public abstract io.reactivex.Single<androidx.paging.RemoteMediator.MediatorResult> loadSingle(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state);
+ }
+
+}
+
diff --git a/paging/paging-rxjava3/api/3.2.0-beta01.txt b/paging/paging-rxjava3/api/3.2.0-beta01.txt
new file mode 100644
index 0000000..e75fc6d
--- /dev/null
+++ b/paging/paging-rxjava3/api/3.2.0-beta01.txt
@@ -0,0 +1,54 @@
+// Signature format: 4.0
+package androidx.paging.rxjava3 {
+
+ public final class PagingRx {
+ method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Boolean>> predicate);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+ method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.rxjava3.core.Maybe<R>> generator);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<R>> transform);
+ }
+
+ @Deprecated public final class RxPagedListBuilder<Key, Value> {
+ ctor @Deprecated public RxPagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public RxPagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, int pageSize);
+ ctor @Deprecated public RxPagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public RxPagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, int pageSize);
+ method @Deprecated public io.reactivex.rxjava3.core.Flowable<androidx.paging.PagedList<Value>> buildFlowable(io.reactivex.rxjava3.core.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public io.reactivex.rxjava3.core.Observable<androidx.paging.PagedList<Value>> buildObservable();
+ method @Deprecated public androidx.paging.rxjava3.RxPagedListBuilder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
+ method @Deprecated public androidx.paging.rxjava3.RxPagedListBuilder<Key,Value> setFetchScheduler(io.reactivex.rxjava3.core.Scheduler scheduler);
+ method @Deprecated public androidx.paging.rxjava3.RxPagedListBuilder<Key,Value> setInitialLoadKey(Key? key);
+ method @Deprecated public androidx.paging.rxjava3.RxPagedListBuilder<Key,Value> setNotifyScheduler(io.reactivex.rxjava3.core.Scheduler scheduler);
+ }
+
+ public final class RxPagedListKt {
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagedList<Value>> toFlowable(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler, optional io.reactivex.rxjava3.core.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagedList<Value>> toFlowable(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler, optional io.reactivex.rxjava3.core.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagedList<Value>> toFlowable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler, optional io.reactivex.rxjava3.core.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagedList<Value>> toFlowable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler, optional io.reactivex.rxjava3.core.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagedList<Value>> toObservable(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagedList<Value>> toObservable(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagedList<Value>> toObservable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagedList<Value>> toObservable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler);
+ }
+
+ public abstract class RxPagingSource<Key, Value> extends androidx.paging.PagingSource<Key,Value> {
+ ctor public RxPagingSource();
+ method public final suspend Object? load(androidx.paging.PagingSource.LoadParams<Key> params, kotlin.coroutines.Continuation<? super androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public abstract io.reactivex.rxjava3.core.Single<androidx.paging.PagingSource.LoadResult<Key,Value>> loadSingle(androidx.paging.PagingSource.LoadParams<Key> params);
+ }
+
+ @androidx.paging.ExperimentalPagingApi public abstract class RxRemoteMediator<Key, Value> extends androidx.paging.RemoteMediator<Key,Value> {
+ ctor public RxRemoteMediator();
+ method public final suspend Object? initialize(kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.InitializeAction>);
+ method public io.reactivex.rxjava3.core.Single<androidx.paging.RemoteMediator.InitializeAction> initializeSingle();
+ method public final suspend Object? load(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state, kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.MediatorResult>);
+ method public abstract io.reactivex.rxjava3.core.Single<androidx.paging.RemoteMediator.MediatorResult> loadSingle(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state);
+ }
+
+}
+
diff --git a/paging/paging-rxjava3/api/res-3.2.0-beta01.txt b/paging/paging-rxjava3/api/res-3.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/paging/paging-rxjava3/api/res-3.2.0-beta01.txt
diff --git a/paging/paging-rxjava3/api/restricted_3.2.0-beta01.txt b/paging/paging-rxjava3/api/restricted_3.2.0-beta01.txt
new file mode 100644
index 0000000..e75fc6d
--- /dev/null
+++ b/paging/paging-rxjava3/api/restricted_3.2.0-beta01.txt
@@ -0,0 +1,54 @@
+// Signature format: 4.0
+package androidx.paging.rxjava3 {
+
+ public final class PagingRx {
+ method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Boolean>> predicate);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<java.lang.Iterable<R>>> transform);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+ method public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+ method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.rxjava3.core.Maybe<R>> generator);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.rxjava3.core.Single<R>> transform);
+ }
+
+ @Deprecated public final class RxPagedListBuilder<Key, Value> {
+ ctor @Deprecated public RxPagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public RxPagedListBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, int pageSize);
+ ctor @Deprecated public RxPagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, androidx.paging.PagedList.Config config);
+ ctor @Deprecated public RxPagedListBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>> pagingSourceFactory, int pageSize);
+ method @Deprecated public io.reactivex.rxjava3.core.Flowable<androidx.paging.PagedList<Value>> buildFlowable(io.reactivex.rxjava3.core.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public io.reactivex.rxjava3.core.Observable<androidx.paging.PagedList<Value>> buildObservable();
+ method @Deprecated public androidx.paging.rxjava3.RxPagedListBuilder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
+ method @Deprecated public androidx.paging.rxjava3.RxPagedListBuilder<Key,Value> setFetchScheduler(io.reactivex.rxjava3.core.Scheduler scheduler);
+ method @Deprecated public androidx.paging.rxjava3.RxPagedListBuilder<Key,Value> setInitialLoadKey(Key? key);
+ method @Deprecated public androidx.paging.rxjava3.RxPagedListBuilder<Key,Value> setNotifyScheduler(io.reactivex.rxjava3.core.Scheduler scheduler);
+ }
+
+ public final class RxPagedListKt {
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagedList<Value>> toFlowable(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler, optional io.reactivex.rxjava3.core.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagedList<Value>> toFlowable(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler, optional io.reactivex.rxjava3.core.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagedList<Value>> toFlowable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler, optional io.reactivex.rxjava3.core.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Flowable<androidx.paging.PagedList<Value>> toFlowable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler, optional io.reactivex.rxjava3.core.BackpressureStrategy backpressureStrategy);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagedList<Value>> toObservable(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagedList<Value>> toObservable(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagedList<Value>> toObservable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, androidx.paging.PagedList.Config config, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler);
+ method @Deprecated public static <Key, Value> io.reactivex.rxjava3.core.Observable<androidx.paging.PagedList<Value>> toObservable(kotlin.jvm.functions.Function0<? extends androidx.paging.PagingSource<Key,Value>>, int pageSize, optional Key? initialLoadKey, optional androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback, optional io.reactivex.rxjava3.core.Scheduler? fetchScheduler, optional io.reactivex.rxjava3.core.Scheduler? notifyScheduler);
+ }
+
+ public abstract class RxPagingSource<Key, Value> extends androidx.paging.PagingSource<Key,Value> {
+ ctor public RxPagingSource();
+ method public final suspend Object? load(androidx.paging.PagingSource.LoadParams<Key> params, kotlin.coroutines.Continuation<? super androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public abstract io.reactivex.rxjava3.core.Single<androidx.paging.PagingSource.LoadResult<Key,Value>> loadSingle(androidx.paging.PagingSource.LoadParams<Key> params);
+ }
+
+ @androidx.paging.ExperimentalPagingApi public abstract class RxRemoteMediator<Key, Value> extends androidx.paging.RemoteMediator<Key,Value> {
+ ctor public RxRemoteMediator();
+ method public final suspend Object? initialize(kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.InitializeAction>);
+ method public io.reactivex.rxjava3.core.Single<androidx.paging.RemoteMediator.InitializeAction> initializeSingle();
+ method public final suspend Object? load(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state, kotlin.coroutines.Continuation<? super androidx.paging.RemoteMediator.MediatorResult>);
+ method public abstract io.reactivex.rxjava3.core.Single<androidx.paging.RemoteMediator.MediatorResult> loadSingle(androidx.paging.LoadType loadType, androidx.paging.PagingState<Key,Value> state);
+ }
+
+}
+
diff --git a/paging/paging-testing/api/3.2.0-beta01.txt b/paging/paging-testing/api/3.2.0-beta01.txt
new file mode 100644
index 0000000..3ff4756
--- /dev/null
+++ b/paging/paging-testing/api/3.2.0-beta01.txt
@@ -0,0 +1,45 @@
+// Signature format: 4.0
+package androidx.paging.testing {
+
+ @VisibleForTesting public enum ErrorRecovery {
+ method public static androidx.paging.testing.ErrorRecovery valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.paging.testing.ErrorRecovery[] values();
+ enum_constant public static final androidx.paging.testing.ErrorRecovery RETRY;
+ enum_constant public static final androidx.paging.testing.ErrorRecovery RETURN_CURRENT_SNAPSHOT;
+ enum_constant public static final androidx.paging.testing.ErrorRecovery THROW;
+ }
+
+ @VisibleForTesting public fun interface LoadErrorHandler {
+ method public androidx.paging.testing.ErrorRecovery onError(androidx.paging.CombinedLoadStates combinedLoadStates);
+ }
+
+ public final class PagerFlowSnapshotKt {
+ method @VisibleForTesting public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, optional androidx.paging.testing.LoadErrorHandler onError, optional kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, optional kotlin.coroutines.Continuation<java.util.List<Value>>);
+ }
+
+ @VisibleForTesting public final class SnapshotLoader<Value> {
+ method public suspend Object? appendScrollWhile(kotlin.jvm.functions.Function1<Value,java.lang.Boolean> predicate, kotlin.coroutines.Continuation<kotlin.Unit>);
+ method public suspend Object? flingTo(int index, kotlin.coroutines.Continuation<kotlin.Unit>);
+ method public suspend Object? prependScrollWhile(kotlin.jvm.functions.Function1<Value,java.lang.Boolean> predicate, kotlin.coroutines.Continuation<kotlin.Unit>);
+ method public suspend Object? refresh(kotlin.coroutines.Continuation<kotlin.Unit>);
+ method public suspend Object? scrollTo(int index, kotlin.coroutines.Continuation<kotlin.Unit>);
+ }
+
+ public final class StaticListPagingSourceFactoryKt {
+ method @VisibleForTesting public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(java.util.List<? extends Value>);
+ method @VisibleForTesting public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(kotlinx.coroutines.flow.Flow<java.util.List<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope);
+ }
+
+ @VisibleForTesting public final class TestPager<Key, Value> {
+ ctor public TestPager(androidx.paging.PagingConfig config, androidx.paging.PagingSource<Key,Value> pagingSource);
+ method public suspend Object? append(kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public suspend Object? getLastLoadedPage(kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult.Page<Key,Value>>);
+ method public suspend Object? getPages(kotlin.coroutines.Continuation<java.util.List<androidx.paging.PagingSource.LoadResult.Page<Key,Value>>>);
+ method public suspend Object? getPagingState(int anchorPosition, kotlin.coroutines.Continuation<androidx.paging.PagingState<Key,Value>>);
+ method public suspend Object? getPagingState(kotlin.jvm.functions.Function1<Value,java.lang.Boolean> anchorPositionLookup, kotlin.coroutines.Continuation<androidx.paging.PagingState<Key,Value>>);
+ method public suspend Object? prepend(kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public suspend Object? refresh(optional Key? initialKey, optional kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ }
+
+}
+
diff --git a/paging/paging-testing/api/current.txt b/paging/paging-testing/api/current.txt
index 586efd3..3ff4756 100644
--- a/paging/paging-testing/api/current.txt
+++ b/paging/paging-testing/api/current.txt
@@ -1,7 +1,7 @@
// Signature format: 4.0
package androidx.paging.testing {
- public enum ErrorRecovery {
+ @VisibleForTesting public enum ErrorRecovery {
method public static androidx.paging.testing.ErrorRecovery valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
method public static androidx.paging.testing.ErrorRecovery[] values();
enum_constant public static final androidx.paging.testing.ErrorRecovery RETRY;
@@ -9,15 +9,15 @@
enum_constant public static final androidx.paging.testing.ErrorRecovery THROW;
}
- public fun interface LoadErrorHandler {
+ @VisibleForTesting public fun interface LoadErrorHandler {
method public androidx.paging.testing.ErrorRecovery onError(androidx.paging.CombinedLoadStates combinedLoadStates);
}
public final class PagerFlowSnapshotKt {
- method public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, optional androidx.paging.testing.LoadErrorHandler onError, optional kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, optional kotlin.coroutines.Continuation<java.util.List<Value>>);
+ method @VisibleForTesting public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, optional androidx.paging.testing.LoadErrorHandler onError, optional kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, optional kotlin.coroutines.Continuation<java.util.List<Value>>);
}
- public final class SnapshotLoader<Value> {
+ @VisibleForTesting public final class SnapshotLoader<Value> {
method public suspend Object? appendScrollWhile(kotlin.jvm.functions.Function1<Value,java.lang.Boolean> predicate, kotlin.coroutines.Continuation<kotlin.Unit>);
method public suspend Object? flingTo(int index, kotlin.coroutines.Continuation<kotlin.Unit>);
method public suspend Object? prependScrollWhile(kotlin.jvm.functions.Function1<Value,java.lang.Boolean> predicate, kotlin.coroutines.Continuation<kotlin.Unit>);
@@ -26,11 +26,11 @@
}
public final class StaticListPagingSourceFactoryKt {
- method public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(java.util.List<? extends Value>);
- method public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(kotlinx.coroutines.flow.Flow<java.util.List<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope);
+ method @VisibleForTesting public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(java.util.List<? extends Value>);
+ method @VisibleForTesting public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(kotlinx.coroutines.flow.Flow<java.util.List<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope);
}
- public final class TestPager<Key, Value> {
+ @VisibleForTesting public final class TestPager<Key, Value> {
ctor public TestPager(androidx.paging.PagingConfig config, androidx.paging.PagingSource<Key,Value> pagingSource);
method public suspend Object? append(kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult<Key,Value>>);
method public suspend Object? getLastLoadedPage(kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult.Page<Key,Value>>);
diff --git a/paging/paging-testing/api/res-3.2.0-beta01.txt b/paging/paging-testing/api/res-3.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/paging/paging-testing/api/res-3.2.0-beta01.txt
diff --git a/paging/paging-testing/api/restricted_3.2.0-beta01.txt b/paging/paging-testing/api/restricted_3.2.0-beta01.txt
new file mode 100644
index 0000000..3ff4756
--- /dev/null
+++ b/paging/paging-testing/api/restricted_3.2.0-beta01.txt
@@ -0,0 +1,45 @@
+// Signature format: 4.0
+package androidx.paging.testing {
+
+ @VisibleForTesting public enum ErrorRecovery {
+ method public static androidx.paging.testing.ErrorRecovery valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.paging.testing.ErrorRecovery[] values();
+ enum_constant public static final androidx.paging.testing.ErrorRecovery RETRY;
+ enum_constant public static final androidx.paging.testing.ErrorRecovery RETURN_CURRENT_SNAPSHOT;
+ enum_constant public static final androidx.paging.testing.ErrorRecovery THROW;
+ }
+
+ @VisibleForTesting public fun interface LoadErrorHandler {
+ method public androidx.paging.testing.ErrorRecovery onError(androidx.paging.CombinedLoadStates combinedLoadStates);
+ }
+
+ public final class PagerFlowSnapshotKt {
+ method @VisibleForTesting public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, optional androidx.paging.testing.LoadErrorHandler onError, optional kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, optional kotlin.coroutines.Continuation<java.util.List<Value>>);
+ }
+
+ @VisibleForTesting public final class SnapshotLoader<Value> {
+ method public suspend Object? appendScrollWhile(kotlin.jvm.functions.Function1<Value,java.lang.Boolean> predicate, kotlin.coroutines.Continuation<kotlin.Unit>);
+ method public suspend Object? flingTo(int index, kotlin.coroutines.Continuation<kotlin.Unit>);
+ method public suspend Object? prependScrollWhile(kotlin.jvm.functions.Function1<Value,java.lang.Boolean> predicate, kotlin.coroutines.Continuation<kotlin.Unit>);
+ method public suspend Object? refresh(kotlin.coroutines.Continuation<kotlin.Unit>);
+ method public suspend Object? scrollTo(int index, kotlin.coroutines.Continuation<kotlin.Unit>);
+ }
+
+ public final class StaticListPagingSourceFactoryKt {
+ method @VisibleForTesting public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(java.util.List<? extends Value>);
+ method @VisibleForTesting public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(kotlinx.coroutines.flow.Flow<java.util.List<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope);
+ }
+
+ @VisibleForTesting public final class TestPager<Key, Value> {
+ ctor public TestPager(androidx.paging.PagingConfig config, androidx.paging.PagingSource<Key,Value> pagingSource);
+ method public suspend Object? append(kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public suspend Object? getLastLoadedPage(kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult.Page<Key,Value>>);
+ method public suspend Object? getPages(kotlin.coroutines.Continuation<java.util.List<androidx.paging.PagingSource.LoadResult.Page<Key,Value>>>);
+ method public suspend Object? getPagingState(int anchorPosition, kotlin.coroutines.Continuation<androidx.paging.PagingState<Key,Value>>);
+ method public suspend Object? getPagingState(kotlin.jvm.functions.Function1<Value,java.lang.Boolean> anchorPositionLookup, kotlin.coroutines.Continuation<androidx.paging.PagingState<Key,Value>>);
+ method public suspend Object? prepend(kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ method public suspend Object? refresh(optional Key? initialKey, optional kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult<Key,Value>>);
+ }
+
+}
+
diff --git a/paging/paging-testing/api/restricted_current.txt b/paging/paging-testing/api/restricted_current.txt
index 586efd3..3ff4756 100644
--- a/paging/paging-testing/api/restricted_current.txt
+++ b/paging/paging-testing/api/restricted_current.txt
@@ -1,7 +1,7 @@
// Signature format: 4.0
package androidx.paging.testing {
- public enum ErrorRecovery {
+ @VisibleForTesting public enum ErrorRecovery {
method public static androidx.paging.testing.ErrorRecovery valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
method public static androidx.paging.testing.ErrorRecovery[] values();
enum_constant public static final androidx.paging.testing.ErrorRecovery RETRY;
@@ -9,15 +9,15 @@
enum_constant public static final androidx.paging.testing.ErrorRecovery THROW;
}
- public fun interface LoadErrorHandler {
+ @VisibleForTesting public fun interface LoadErrorHandler {
method public androidx.paging.testing.ErrorRecovery onError(androidx.paging.CombinedLoadStates combinedLoadStates);
}
public final class PagerFlowSnapshotKt {
- method public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, optional androidx.paging.testing.LoadErrorHandler onError, optional kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, optional kotlin.coroutines.Continuation<java.util.List<Value>>);
+ method @VisibleForTesting public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, optional androidx.paging.testing.LoadErrorHandler onError, optional kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, optional kotlin.coroutines.Continuation<java.util.List<Value>>);
}
- public final class SnapshotLoader<Value> {
+ @VisibleForTesting public final class SnapshotLoader<Value> {
method public suspend Object? appendScrollWhile(kotlin.jvm.functions.Function1<Value,java.lang.Boolean> predicate, kotlin.coroutines.Continuation<kotlin.Unit>);
method public suspend Object? flingTo(int index, kotlin.coroutines.Continuation<kotlin.Unit>);
method public suspend Object? prependScrollWhile(kotlin.jvm.functions.Function1<Value,java.lang.Boolean> predicate, kotlin.coroutines.Continuation<kotlin.Unit>);
@@ -26,11 +26,11 @@
}
public final class StaticListPagingSourceFactoryKt {
- method public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(java.util.List<? extends Value>);
- method public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(kotlinx.coroutines.flow.Flow<java.util.List<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope);
+ method @VisibleForTesting public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(java.util.List<? extends Value>);
+ method @VisibleForTesting public static <Value> androidx.paging.PagingSourceFactory<java.lang.Integer,Value> asPagingSourceFactory(kotlinx.coroutines.flow.Flow<java.util.List<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope);
}
- public final class TestPager<Key, Value> {
+ @VisibleForTesting public final class TestPager<Key, Value> {
ctor public TestPager(androidx.paging.PagingConfig config, androidx.paging.PagingSource<Key,Value> pagingSource);
method public suspend Object? append(kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult<Key,Value>>);
method public suspend Object? getLastLoadedPage(kotlin.coroutines.Continuation<androidx.paging.PagingSource.LoadResult.Page<Key,Value>>);
diff --git a/paging/paging-testing/build.gradle b/paging/paging-testing/build.gradle
index 9557e62..c01f6cc 100644
--- a/paging/paging-testing/build.gradle
+++ b/paging/paging-testing/build.gradle
@@ -37,7 +37,7 @@
androidx {
name = "Paging Testing Extensions"
- type = LibraryType.PUBLISHED_LIBRARY
+ type = LibraryType.PUBLISHED_TEST_LIBRARY
inceptionYear = "2022"
description = "Test artifact for Paging implementation"
publish = Publish.SNAPSHOT_AND_RELEASE
diff --git a/paging/paging-testing/src/main/java/androidx/paging/testing/LoadErrorHandler.kt b/paging/paging-testing/src/main/java/androidx/paging/testing/LoadErrorHandler.kt
index 2e8df82..32c7b02 100644
--- a/paging/paging-testing/src/main/java/androidx/paging/testing/LoadErrorHandler.kt
+++ b/paging/paging-testing/src/main/java/androidx/paging/testing/LoadErrorHandler.kt
@@ -16,6 +16,7 @@
package androidx.paging.testing
+import androidx.annotation.VisibleForTesting
import androidx.paging.CombinedLoadStates
import androidx.paging.LoadState
import androidx.paging.PagingDataDiffer
@@ -26,6 +27,7 @@
* An interface to implement the error recovery strategy when [PagingSource]
* returns a [LoadResult.Error].
*/
+@VisibleForTesting
public fun interface LoadErrorHandler {
/**
* The lambda that should return an [ErrorRecovery] given the [CombinedLoadStates]
@@ -48,6 +50,7 @@
* is indicated when [PagingDataDiffer.loadStateFlow] emits a [CombinedLoadStates] where one or
* more of the [LoadState] is [LoadState.Error].
*/
+@VisibleForTesting
public enum class ErrorRecovery {
/**
* Rethrow the original [Throwable][LoadState.Error.error] that was caught when loading from
diff --git a/paging/paging-testing/src/main/java/androidx/paging/testing/PagerFlowSnapshot.kt b/paging/paging-testing/src/main/java/androidx/paging/testing/PagerFlowSnapshot.kt
index 3098cf1..0882b80 100644
--- a/paging/paging-testing/src/main/java/androidx/paging/testing/PagerFlowSnapshot.kt
+++ b/paging/paging-testing/src/main/java/androidx/paging/testing/PagerFlowSnapshot.kt
@@ -16,6 +16,7 @@
package androidx.paging.testing
+import androidx.annotation.VisibleForTesting
import androidx.paging.CombinedLoadStates
import androidx.paging.DifferCallback
import androidx.paging.ItemSnapshotList
@@ -50,6 +51,7 @@
*
* @param loadOperations The block containing [SnapshotLoader] load operations.
*/
+@VisibleForTesting
public suspend fun <Value : Any> Flow<PagingData<Value>>.asSnapshot(
onError: LoadErrorHandler = LoadErrorHandler { THROW },
loadOperations: suspend SnapshotLoader<Value>.() -> @JvmSuppressWildcards Unit = { }
diff --git a/paging/paging-testing/src/main/java/androidx/paging/testing/SnapshotLoader.kt b/paging/paging-testing/src/main/java/androidx/paging/testing/SnapshotLoader.kt
index f58f866..040a7f1 100644
--- a/paging/paging-testing/src/main/java/androidx/paging/testing/SnapshotLoader.kt
+++ b/paging/paging-testing/src/main/java/androidx/paging/testing/SnapshotLoader.kt
@@ -16,6 +16,7 @@
package androidx.paging.testing
+import androidx.annotation.VisibleForTesting
import androidx.paging.DifferCallback
import androidx.paging.LoadType.APPEND
import androidx.paging.LoadType.PREPEND
@@ -38,6 +39,7 @@
* Tracks generational information and provides the listener to [DifferCallback] on
* [PagingDataDiffer] operations.
*/
+@VisibleForTesting
public class SnapshotLoader<Value : Any> internal constructor(
private val differ: PagingDataDiffer<Value>,
private val errorHandler: LoadErrorHandler,
diff --git a/paging/paging-testing/src/main/java/androidx/paging/testing/StaticListPagingSourceFactory.kt b/paging/paging-testing/src/main/java/androidx/paging/testing/StaticListPagingSourceFactory.kt
index 6744b5e..000e2a1 100644
--- a/paging/paging-testing/src/main/java/androidx/paging/testing/StaticListPagingSourceFactory.kt
+++ b/paging/paging-testing/src/main/java/androidx/paging/testing/StaticListPagingSourceFactory.kt
@@ -16,6 +16,7 @@
package androidx.paging.testing
+import androidx.annotation.VisibleForTesting
import androidx.paging.InvalidatingPagingSourceFactory
import androidx.paging.LoadType.REFRESH
import androidx.paging.Pager
@@ -40,6 +41,7 @@
*
* @param coroutineScope the CoroutineScope to collect from the Flow of list.
*/
+@VisibleForTesting
public fun <Value : Any> Flow<@JvmSuppressWildcards List<Value>>.asPagingSourceFactory(
coroutineScope: CoroutineScope
): PagingSourceFactory<Int, Value> {
@@ -74,5 +76,6 @@
* the data source. This means any PagingSources generated by the same factory will load from
* the exact same list of data.
*/
+@VisibleForTesting
public fun <Value : Any> List<Value>.asPagingSourceFactory(): PagingSourceFactory<Int, Value> =
PagingSourceFactory { StaticListPagingSource(this) }
diff --git a/paging/paging-testing/src/main/java/androidx/paging/testing/TestPager.kt b/paging/paging-testing/src/main/java/androidx/paging/testing/TestPager.kt
index bcd13ec..bcecbead 100644
--- a/paging/paging-testing/src/main/java/androidx/paging/testing/TestPager.kt
+++ b/paging/paging-testing/src/main/java/androidx/paging/testing/TestPager.kt
@@ -16,6 +16,7 @@
package androidx.paging.testing
+import androidx.annotation.VisibleForTesting
import androidx.paging.LoadType
import androidx.paging.LoadType.APPEND
import androidx.paging.LoadType.PREPEND
@@ -44,6 +45,7 @@
* @param config the [PagingConfig] to configure this TestPager's loading behavior.
* @param pagingSource the [PagingSource] to load data from.
*/
+@VisibleForTesting
public class TestPager<Key : Any, Value : Any>(
private val config: PagingConfig,
private val pagingSource: PagingSource<Key, Value>,
diff --git a/playground-common/androidx-shared.properties b/playground-common/androidx-shared.properties
index 3866038..b791be0 100644
--- a/playground-common/androidx-shared.properties
+++ b/playground-common/androidx-shared.properties
@@ -35,6 +35,7 @@
org.gradle.unsafe.configuration-cache-problems=warn
org.gradle.unsafe.configuration-cache.max-problems=4000
+android.lint.printStackTrace=true
android.uniquePackageNames=false
android.enableAdditionalTestOutput=true
android.useAndroidX=true
@@ -76,7 +77,7 @@
# Disallow resolving dependencies at configuration time, which is a slight performance problem
android.dependencyResolutionAtConfigurationTime.disallow=true
-android.suppressUnsupportedOptionWarnings=android.suppressUnsupportedOptionWarnings,android.dependencyResolutionAtConfigurationTime.disallow,android.experimental.lint.missingBaselineIsEmptyBaseline,android.experimental.lint.version
+android.suppressUnsupportedOptionWarnings=android.suppressUnsupportedOptionWarnings,android.dependencyResolutionAtConfigurationTime.disallow,android.experimental.lint.missingBaselineIsEmptyBaseline,android.experimental.lint.version,android.lint.printStackTrace
# Workaround for b/162074215
android.includeDependencyInfoInApks=false
diff --git a/playground-common/playground.properties b/playground-common/playground.properties
index 25e89d5..642ccfb 100644
--- a/playground-common/playground.properties
+++ b/playground-common/playground.properties
@@ -25,6 +25,6 @@
kotlin.code.style=official
# Disable docs
androidx.enableDocumentation=false
-androidx.playground.snapshotBuildId=10059712
+androidx.playground.snapshotBuildId=10178688
androidx.playground.metalavaBuildId=10129644
androidx.studio.type=playground
diff --git a/privacysandbox/ads/ads-adservices-java/build.gradle b/privacysandbox/ads/ads-adservices-java/build.gradle
index 5915e9c..d4734a0 100644
--- a/privacysandbox/ads/ads-adservices-java/build.gradle
+++ b/privacysandbox/ads/ads-adservices-java/build.gradle
@@ -24,7 +24,7 @@
dependencies {
api(libs.kotlinStdlib)
- api(libs.kotlinCoroutinesCore)
+ api(libs.kotlinCoroutinesCore171)
implementation("androidx.core:core-ktx:1.8.0")
api("androidx.annotation:annotation:1.2.0")
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/FledgeCtsDebuggableTest.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/FledgeCtsDebuggableTest.java
index de51a6e..7925188 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/FledgeCtsDebuggableTest.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/FledgeCtsDebuggableTest.java
@@ -67,7 +67,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-@SdkSuppress(minSdkVersion = 26)
+@SdkSuppress(minSdkVersion = 28) // API 28 is the lowest level supporting device_config used by this test
public class FledgeCtsDebuggableTest {
protected static final Context sContext = ApplicationProvider.getApplicationContext();
private static final String TAG = "FledgeCtsDebuggableTest";
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/adid/AdIdManagerTest.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/adid/AdIdManagerTest.java
index 4b6e6bc..c35cb46 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/adid/AdIdManagerTest.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/adid/AdIdManagerTest.java
@@ -23,6 +23,7 @@
import androidx.privacysandbox.ads.adservices.java.adid.AdIdManagerFutures;
import androidx.privacysandbox.ads.adservices.java.endtoend.TestUtil;
import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SdkSuppress;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.After;
@@ -34,6 +35,7 @@
@RunWith(JUnit4.class)
+@SdkSuppress(minSdkVersion = 28) // API 28 required for device_config used by this test
public class AdIdManagerTest {
private static final String TAG = "AdIdManagerTest";
private TestUtil mTestUtil = new TestUtil(InstrumentationRegistry.getInstrumentation(),
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/appsetid/AppSetIdManagerTest.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/appsetid/AppSetIdManagerTest.java
index 8bbe063..ecebc1e 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/appsetid/AppSetIdManagerTest.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/appsetid/AppSetIdManagerTest.java
@@ -23,6 +23,7 @@
import androidx.privacysandbox.ads.adservices.java.appsetid.AppSetIdManagerFutures;
import androidx.privacysandbox.ads.adservices.java.endtoend.TestUtil;
import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SdkSuppress;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.After;
@@ -33,6 +34,7 @@
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
+@SdkSuppress(minSdkVersion = 28) // API 28 required for device_config used by this test
// TODO: Consider refactoring so that we're not duplicating code.
public class AppSetIdManagerTest {
private static final String TAG = "AppSetIdManagerTest";
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/measurement/MeasurementManagerTest.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/measurement/MeasurementManagerTest.java
index fb8e44d..6a657ad4 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/measurement/MeasurementManagerTest.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/measurement/MeasurementManagerTest.java
@@ -47,6 +47,7 @@
import java.util.concurrent.TimeUnit;
@RunWith(JUnit4.class)
+@SdkSuppress(minSdkVersion = 28) // API 28 required for device_config used by this test
// TODO: Consider refactoring so that we're not duplicating code.
public class MeasurementManagerTest {
private static final String TAG = "MeasurementManagerTest";
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/topics/TopicsManagerTest.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/topics/TopicsManagerTest.java
index b6155a8..3b9abab 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/topics/TopicsManagerTest.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/topics/TopicsManagerTest.java
@@ -25,6 +25,7 @@
import androidx.privacysandbox.ads.adservices.topics.GetTopicsResponse;
import androidx.privacysandbox.ads.adservices.topics.Topic;
import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SdkSuppress;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.After;
@@ -37,6 +38,7 @@
import java.util.Arrays;
@RunWith(JUnit4.class)
+@SdkSuppress(minSdkVersion = 28) // API 28 required for device_config used by this test
// TODO: Consider refactoring so that we're not duplicating code.
public class TopicsManagerTest {
private static final String TAG = "TopicsManagerTest";
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/topics/TopicsManagerFuturesTest.kt b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/topics/TopicsManagerFuturesTest.kt
index cd306fb..c4c3be1 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/topics/TopicsManagerFuturesTest.kt
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/topics/TopicsManagerFuturesTest.kt
@@ -96,11 +96,11 @@
@Test
@SuppressWarnings("NewApi")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+ @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testTopicsAsyncPreviewSupported() {
val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
val topicsManager = mockTopicsManager(mContext)
setupTopicsResponse(topicsManager)
val managerCompat = from(mContext)
@@ -159,9 +159,6 @@
android.adservices.topics.GetTopicsRequest.Builder().setAdsSdkName(mSdkName).build()
Assert.assertEquals(expectedRequest.adsSdkName, topicsRequest.adsSdkName)
- Assert.assertEquals(
- expectedRequest.shouldRecordObservation(), topicsRequest.shouldRecordObservation()
- )
}
@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
diff --git a/privacysandbox/ads/ads-adservices/build.gradle b/privacysandbox/ads/ads-adservices/build.gradle
index 13284aa..e7fdf07 100644
--- a/privacysandbox/ads/ads-adservices/build.gradle
+++ b/privacysandbox/ads/ads-adservices/build.gradle
@@ -26,7 +26,7 @@
dependencies {
api(libs.kotlinStdlib)
- api(libs.kotlinCoroutinesCore)
+ api(libs.kotlinCoroutinesCore171)
implementation("androidx.core:core-ktx:1.8.0")
api("androidx.annotation:annotation:1.6.0")
diff --git a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerTest.kt b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerTest.kt
index dc6acedd..20736fb 100644
--- a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerTest.kt
+++ b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerTest.kt
@@ -95,11 +95,11 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+ @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testTopicsAsyncPreviewSupported() {
val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
val topicsManager = mockTopicsManager(mContext)
setupTopicsResponse(topicsManager)
val managerCompat = obtain(mContext)
@@ -156,8 +156,9 @@
private fun verifyRequest(topicsRequest: android.adservices.topics.GetTopicsRequest) {
// Set up the request that we expect the compat code to invoke.
val expectedRequest =
- android.adservices.topics.GetTopicsRequest.Builder().setAdsSdkName(mSdkName)
- .setShouldRecordObservation(true).build()
+ android.adservices.topics.GetTopicsRequest.Builder()
+ .setAdsSdkName(mSdkName)
+ .build()
Assert.assertEquals(expectedRequest.adsSdkName, topicsRequest.adsSdkName)
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/AndroidManifest.xml b/privacysandbox/ads/ads-adservices/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..272870f
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?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>
+ <uses-library android:name="android.ext.adservices" android:required="false"/>
+ </application>
+</manifest>
\ No newline at end of file
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManager.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManager.kt
index 2a60ca8..4bccf85 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManager.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManager.kt
@@ -20,13 +20,8 @@
import android.annotation.SuppressLint
import android.content.Context
import android.os.LimitExceededException
-import android.os.ext.SdkExtensions
-import androidx.annotation.DoNotInline
-import androidx.annotation.RequiresExtension
import androidx.annotation.RequiresPermission
-import androidx.core.os.asOutcomeReceiver
import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
-import kotlinx.coroutines.suspendCancellableCoroutine
/**
* TopicsManager provides APIs for App and Ad-Sdks to get the user interest topics in a privacy
@@ -45,55 +40,6 @@
@RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_TOPICS)
abstract suspend fun getTopics(request: GetTopicsRequest): GetTopicsResponse
- @SuppressLint("NewApi", "ClassVerificationFailure")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
- private class Api33Ext4Impl(
- private val mTopicsManager: android.adservices.topics.TopicsManager
- ) : TopicsManager() {
- constructor(context: Context) : this(
- context.getSystemService<android.adservices.topics.TopicsManager>(
- android.adservices.topics.TopicsManager::class.java
- )
- )
-
- @DoNotInline
- @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_TOPICS)
- override suspend fun getTopics(request: GetTopicsRequest): GetTopicsResponse {
- return convertResponse(getTopicsAsyncInternal(convertRequest(request)))
- }
-
- @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_TOPICS)
- private suspend fun getTopicsAsyncInternal(
- getTopicsRequest: android.adservices.topics.GetTopicsRequest
- ): android.adservices.topics.GetTopicsResponse = suspendCancellableCoroutine { continuation
- ->
- mTopicsManager.getTopics(
- getTopicsRequest,
- Runnable::run,
- continuation.asOutcomeReceiver()
- )
- }
-
- private fun convertRequest(
- request: GetTopicsRequest
- ): android.adservices.topics.GetTopicsRequest {
- return android.adservices.topics.GetTopicsRequest.Builder()
- .setAdsSdkName(request.adsSdkName)
- .setShouldRecordObservation(request.shouldRecordObservation)
- .build()
- }
-
- internal fun convertResponse(
- response: android.adservices.topics.GetTopicsResponse
- ): GetTopicsResponse {
- var topics = mutableListOf<Topic>()
- for (topic in response.topics) {
- topics.add(Topic(topic.taxonomyVersion, topic.modelVersion, topic.topicId))
- }
- return GetTopicsResponse(topics)
- }
- }
-
companion object {
/**
* Creates [TopicsManager].
@@ -104,8 +50,10 @@
@JvmStatic
@SuppressLint("NewApi", "ClassVerificationFailure")
fun obtain(context: Context): TopicsManager? {
- return if (AdServicesInfo.version() >= 4) {
- Api33Ext4Impl(context)
+ return if (AdServicesInfo.version() >= 5) {
+ TopicsManagerApi33Ext5Impl(context)
+ } else if (AdServicesInfo.version() == 4) {
+ TopicsManagerApi33Ext4Impl(context)
} else {
null
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerApi33Ext4Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerApi33Ext4Impl.kt
new file mode 100644
index 0000000..4820da3
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerApi33Ext4Impl.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.ads.adservices.topics
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.ext.SdkExtensions
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+class TopicsManagerApi33Ext4Impl(context: Context) : TopicsManagerImplCommon(
+ context.getSystemService(android.adservices.topics.TopicsManager::class.java))
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerApi33Ext5Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerApi33Ext5Impl.kt
new file mode 100644
index 0000000..681042d
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerApi33Ext5Impl.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.privacysandbox.ads.adservices.topics
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.ext.SdkExtensions
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
+class TopicsManagerApi33Ext5Impl(context: Context) : TopicsManagerImplCommon(
+ context.getSystemService(android.adservices.topics.TopicsManager::class.java)) {
+
+ override fun convertRequest(
+ request: GetTopicsRequest
+ ): android.adservices.topics.GetTopicsRequest {
+ return android.adservices.topics.GetTopicsRequest.Builder()
+ .setAdsSdkName(request.adsSdkName)
+ .setShouldRecordObservation(request.shouldRecordObservation)
+ .build()
+ }
+}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerImplCommon.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerImplCommon.kt
new file mode 100644
index 0000000..5632655
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerImplCommon.kt
@@ -0,0 +1,54 @@
+package androidx.privacysandbox.ads.adservices.topics
+
+import android.adservices.common.AdServicesPermissions
+import android.annotation.SuppressLint
+import android.os.ext.SdkExtensions
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RequiresPermission
+import androidx.annotation.RestrictTo
+import androidx.core.os.asOutcomeReceiver
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+open class TopicsManagerImplCommon(
+ private val mTopicsManager: android.adservices.topics.TopicsManager
+) : TopicsManager() {
+ @DoNotInline
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_TOPICS)
+ override suspend fun getTopics(request: GetTopicsRequest): GetTopicsResponse {
+ return convertResponse(getTopicsAsyncInternal(convertRequest(request)))
+ }
+
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_TOPICS)
+ private suspend fun getTopicsAsyncInternal(
+ getTopicsRequest: android.adservices.topics.GetTopicsRequest
+ ): android.adservices.topics.GetTopicsResponse = suspendCancellableCoroutine { continuation
+ ->
+ mTopicsManager.getTopics(
+ getTopicsRequest,
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+
+ internal open fun convertRequest(
+ request: GetTopicsRequest
+ ): android.adservices.topics.GetTopicsRequest {
+ return android.adservices.topics.GetTopicsRequest.Builder()
+ .setAdsSdkName(request.adsSdkName)
+ .build()
+ }
+
+ internal fun convertResponse(
+ response: android.adservices.topics.GetTopicsResponse
+ ): GetTopicsResponse {
+ val topics = mutableListOf<Topic>()
+ for (topic in response.topics) {
+ topics.add(Topic(topic.taxonomyVersion, topic.modelVersion, topic.topicId))
+ }
+ return GetTopicsResponse(topics)
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/MySdkStubDelegate.kt b/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/MySdkStubDelegate.kt
index 5e9c140..b1f2995 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/MySdkStubDelegate.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/MySdkStubDelegate.kt
@@ -186,7 +186,7 @@
val job = coroutineScope.launch {
try {
val result = delegate.returnSdkActivityLauncher()
- transactionCallback.onSuccess((result as SdkActivityLauncherAndBinderWrapper).launcherInfo)
+ transactionCallback.onSuccess(SdkActivityLauncherAndBinderWrapper.getLauncherInfo(result))
}
catch (t: Throwable) {
transactionCallback.onFailure(toThrowableParcel(t))
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/RequestConverter.kt b/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/RequestConverter.kt
index d4621af..1070100 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/RequestConverter.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/RequestConverter.kt
@@ -31,8 +31,8 @@
parcelable.myUiInterface =
IMyUiInterfaceCoreLibInfoAndBinderWrapperConverter.toParcelable(annotatedValue.myUiInterface.toCoreLibInfo(context),
MyUiInterfaceStubDelegate(annotatedValue.myUiInterface, context))
- parcelable.activityLauncher = (annotatedValue.activityLauncher as
- SdkActivityLauncherAndBinderWrapper).launcherInfo
+ parcelable.activityLauncher =
+ SdkActivityLauncherAndBinderWrapper.getLauncherInfo(annotatedValue.activityLauncher)
return parcelable
}
}
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/SdkActivityLauncherAndBinderWrapper.kt b/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/SdkActivityLauncherAndBinderWrapper.kt
index 8ef1af5..45f4a43 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/SdkActivityLauncherAndBinderWrapper.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/SdkActivityLauncherAndBinderWrapper.kt
@@ -10,4 +10,13 @@
) : SdkActivityLauncher by delegate {
public constructor(launcherInfo: Bundle) :
this(SdkActivityLauncherFactory.fromLauncherInfo(launcherInfo), launcherInfo)
+
+ public companion object {
+ public fun getLauncherInfo(launcher: SdkActivityLauncher): Bundle {
+ if (launcher is SdkActivityLauncherAndBinderWrapper) {
+ return launcher.launcherInfo
+ }
+ throw IllegalStateException("Invalid SdkActivityLauncher instance cannot be bundled. SdkActivityLaunchers may only be created by apps.")
+ }
+ }
}
diff --git a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/SdkActivityLauncherWrapperGenerator.kt b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/SdkActivityLauncherWrapperGenerator.kt
index a90a3ef..37aa3da 100644
--- a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/SdkActivityLauncherWrapperGenerator.kt
+++ b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/SdkActivityLauncherWrapperGenerator.kt
@@ -51,20 +51,9 @@
),
KModifier.PRIVATE,
)
- addFunction(
- FunSpec.constructorBuilder()
- .addParameter("launcherInfo", SpecNames.bundleClass)
- .callThisConstructor(
- CodeBlock.of(
- "%T.fromLauncherInfo(launcherInfo)",
- ClassName(
- "androidx.privacysandbox.ui.provider",
- "SdkActivityLauncherFactory"
- ),
- ),
- CodeBlock.of("launcherInfo"),
- ).build()
- )
+
+ addFunction(fromLauncherInfo())
+ addType(companionObject())
}
return FileSpec.builder(basePackageName, className).build {
@@ -72,4 +61,34 @@
addType(classSpec)
}
}
+
+ private fun fromLauncherInfo() = FunSpec.constructorBuilder()
+ .addParameter("launcherInfo", SpecNames.bundleClass)
+ .callThisConstructor(
+ CodeBlock.of(
+ "%T.fromLauncherInfo(launcherInfo)",
+ ClassName(
+ "androidx.privacysandbox.ui.provider",
+ "SdkActivityLauncherFactory"
+ ),
+ ),
+ CodeBlock.of("launcherInfo"),
+ ).build()
+
+ private fun companionObject() = TypeSpec.companionObjectBuilder().addFunction(
+ FunSpec.builder("getLauncherInfo").build {
+ addParameter("launcher", Types.sdkActivityLauncher.poetClassName())
+ returns(SpecNames.bundleClass)
+ addCode {
+ addControlFlow("if (launcher is %N)", className) {
+ addStatement("return launcher.launcherInfo")
+ }
+ addStatement(
+ "throw·IllegalStateException(%S)",
+ "Invalid SdkActivityLauncher instance cannot be bundled. " +
+ "SdkActivityLaunchers may only be created by apps."
+ )
+ }
+ }
+ ).build()
}
diff --git a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ServerBinderCodeConverter.kt b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ServerBinderCodeConverter.kt
index 2eb9f88..27eb1e3 100644
--- a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ServerBinderCodeConverter.kt
+++ b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ServerBinderCodeConverter.kt
@@ -109,9 +109,9 @@
override fun convertToActivityLauncherBinderCode(expression: String): CodeBlock =
CodeBlock.of(
- "(%L as %T).launcherInfo",
- expression,
+ "%T.getLauncherInfo(%L)",
activityLauncherWrapperClass,
+ expression,
)
override fun convertToActivityLauncherModelCode(expression: String): CodeBlock =
diff --git a/recyclerview/recyclerview/api/current.txt b/recyclerview/recyclerview/api/current.txt
index 0e9b27d..51b18d2 100644
--- a/recyclerview/recyclerview/api/current.txt
+++ b/recyclerview/recyclerview/api/current.txt
@@ -722,6 +722,7 @@
method public boolean isFocused();
method public final boolean isItemPrefetchEnabled();
method public boolean isLayoutHierarchical(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+ method public boolean isLayoutReversed();
method public boolean isMeasurementCacheEnabled();
method public boolean isSmoothScrolling();
method public boolean isViewPartiallyVisible(android.view.View, boolean, boolean);
diff --git a/recyclerview/recyclerview/api/restricted_current.txt b/recyclerview/recyclerview/api/restricted_current.txt
index 8d25f96..e3a2ab0 100644
--- a/recyclerview/recyclerview/api/restricted_current.txt
+++ b/recyclerview/recyclerview/api/restricted_current.txt
@@ -722,6 +722,7 @@
method public boolean isFocused();
method public final boolean isItemPrefetchEnabled();
method public boolean isLayoutHierarchical(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+ method public boolean isLayoutReversed();
method public boolean isMeasurementCacheEnabled();
method public boolean isSmoothScrolling();
method public boolean isViewPartiallyVisible(android.view.View, boolean, boolean);
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewKeyEventTest.kt b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewKeyEventTest.kt
new file mode 100644
index 0000000..45cc5f8
--- /dev/null
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewKeyEventTest.kt
@@ -0,0 +1,283 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.recyclerview.widget
+
+import android.view.KeyEvent
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import org.hamcrest.CoreMatchers
+import org.hamcrest.MatcherAssert
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class RecyclerViewKeyEventTest {
+
+ @Suppress("DEPRECATION")
+ @get:Rule
+ val mActivityTestRule = androidx.test.rule.ActivityTestRule(TestContentViewActivity::class.java)
+
+ private val viewHeight = 1024
+ private val viewWidth = 1024
+ private val context = mActivityTestRule.activity
+ private val testItemCount = 10
+
+ enum class InitialPosition { FIRST, LAST }
+
+ private fun setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight: Int,
+ initialPosition: InitialPosition,
+ keyEvent: Int,
+ layoutManager: RecyclerView.LayoutManager
+ ): Pair<Int, Int> {
+ val context = mActivityTestRule.activity
+ val recyclerView = RecyclerView(context)
+
+ recyclerView.layoutParams = ViewGroup.LayoutParams(viewWidth, viewHeight)
+ recyclerView.layoutManager = layoutManager
+ recyclerView.adapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
+ override fun onCreateViewHolder(
+ parent: ViewGroup,
+ viewType: Int
+ ) = object : RecyclerView.ViewHolder(
+ TextView(parent.context).apply {
+ minWidth = 1024
+ minHeight = 256
+ }
+ ) {}
+
+ override fun getItemCount() = testItemCount
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {}
+ }
+ val scrollPos = when (initialPosition) {
+ InitialPosition.FIRST -> 0
+ InitialPosition.LAST -> testItemCount - 1
+ }
+ recyclerView.scrollToPosition(scrollPos)
+
+ val testContentView = mActivityTestRule.activity.contentView
+ testContentView.expectLayouts(1)
+ mActivityTestRule.runOnUiThread { testContentView.addView(recyclerView) }
+ testContentView.awaitLayouts(2)
+
+ // Arrange
+ val latch = CountDownLatch(1)
+ var scrollHeight = 0
+ var scrollWidth = 0
+
+ recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+ override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
+ if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+ latch.countDown()
+ }
+ }
+
+ override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+ scrollWidth += dx
+ scrollHeight += dy
+ }
+ })
+
+ // Act
+ mActivityTestRule.runOnUiThread {
+ recyclerView.dispatchKeyEvent(
+ KeyEvent(KeyEvent.ACTION_DOWN, keyEvent)
+ )
+ recyclerView.dispatchKeyEvent(
+ KeyEvent(KeyEvent.ACTION_UP, keyEvent)
+ )
+ }
+
+ MatcherAssert.assertThat(latch.await(2, TimeUnit.SECONDS), CoreMatchers.`is`(true))
+ return Pair(scrollWidth, scrollHeight)
+ }
+
+ @Test
+ fun vertical_pageDown() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.FIRST, KeyEvent.KEYCODE_PAGE_DOWN, layoutManager)
+ // PageUp should scroll down one-page i.e. view height.
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(viewHeight))
+ }
+
+ @Test
+ fun vertical_pageUp() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.LAST, KeyEvent.KEYCODE_PAGE_UP, layoutManager)
+ // PageUp should scroll up one-page i.e. view height.
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(-viewHeight))
+ }
+
+ @Test
+ fun horizontal_pageUp() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.LAST, KeyEvent.KEYCODE_PAGE_UP, layoutManager)
+ // No scroll for horizontal layout.
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(-viewWidth))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(0))
+ }
+
+ @Test
+ fun horizontal_pageDown() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.FIRST, KeyEvent.KEYCODE_PAGE_DOWN, layoutManager)
+ // No scroll for horizontal layout.
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(viewWidth))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(0))
+ }
+
+ @Test
+ fun vertical_home() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.LAST, KeyEvent.KEYCODE_MOVE_HOME, layoutManager)
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.not(0))
+ MatcherAssert.assertThat(layoutManager.findFirstCompletelyVisibleItemPosition(),
+ CoreMatchers.`is`(0))
+ }
+
+ @Test
+ fun vertical_end() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.FIRST, KeyEvent.KEYCODE_MOVE_END, layoutManager)
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.not(0))
+ MatcherAssert.assertThat(layoutManager.findLastCompletelyVisibleItemPosition(),
+ CoreMatchers.`is`(testItemCount - 1))
+ }
+
+ @Test
+ fun horizontal_home() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.LAST, KeyEvent.KEYCODE_MOVE_HOME, layoutManager)
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.not(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(layoutManager.findFirstCompletelyVisibleItemPosition(),
+ CoreMatchers.`is`(0))
+ }
+
+ @Test
+ fun horizontal_end() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.FIRST, KeyEvent.KEYCODE_MOVE_END, layoutManager)
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.not(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(layoutManager.findLastCompletelyVisibleItemPosition(),
+ CoreMatchers.`is`(testItemCount - 1))
+ }
+
+ @Test
+ fun vertical_pageDown_reversed() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, true)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.LAST, KeyEvent.KEYCODE_PAGE_DOWN, layoutManager)
+ // PageUp should scroll down one-page i.e. view height.
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(viewHeight))
+ }
+
+ @Test
+ fun vertical_pageUp_reversed() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, true)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.FIRST, KeyEvent.KEYCODE_PAGE_UP, layoutManager)
+ // PageUp should scroll up one-page i.e. view height.
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(-viewHeight))
+ }
+
+ @Test
+ fun horizontal_pageUp_reversed() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, true)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.FIRST, KeyEvent.KEYCODE_PAGE_UP, layoutManager)
+ // No scroll for horizontal layout.
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(-viewWidth))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(0))
+ }
+
+ @Test
+ fun horizontal_pageDown_reversed() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, true)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.LAST, KeyEvent.KEYCODE_PAGE_DOWN, layoutManager)
+ // No scroll for horizontal layout.
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(viewWidth))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(0))
+ }
+
+ @Test
+ fun vertical_home_reversed() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, true)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.FIRST, KeyEvent.KEYCODE_MOVE_HOME, layoutManager)
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.not(0))
+ MatcherAssert.assertThat(layoutManager.findLastCompletelyVisibleItemPosition(),
+ CoreMatchers.`is`(testItemCount - 1))
+ }
+
+ @Test
+ fun vertical_end_reversed() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, true)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.LAST, KeyEvent.KEYCODE_MOVE_END, layoutManager)
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.not(0))
+ MatcherAssert.assertThat(layoutManager.findFirstCompletelyVisibleItemPosition(),
+ CoreMatchers.`is`(0))
+ }
+
+ @Test
+ fun horizontal_home_reversed() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, true)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.FIRST, KeyEvent.KEYCODE_MOVE_HOME, layoutManager)
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.not(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(layoutManager.findFirstCompletelyVisibleItemPosition(),
+ CoreMatchers.`is`(testItemCount - 1))
+ }
+
+ @Test
+ fun horizontal_end_reversed() {
+ val layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, true)
+ val (scrollWidth, scrollHeight) = setupRecyclerViewAndScrollByKeyEvent(
+ viewHeight, InitialPosition.LAST, KeyEvent.KEYCODE_MOVE_END, layoutManager)
+ MatcherAssert.assertThat(scrollWidth, CoreMatchers.not(0))
+ MatcherAssert.assertThat(scrollHeight, CoreMatchers.`is`(0))
+ MatcherAssert.assertThat(layoutManager.findFirstCompletelyVisibleItemPosition(),
+ CoreMatchers.`is`(0))
+ }
+}
\ No newline at end of file
diff --git a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/LinearLayoutManager.java b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/LinearLayoutManager.java
index e0cd21b..b5dca5d 100644
--- a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/LinearLayoutManager.java
+++ b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/LinearLayoutManager.java
@@ -376,6 +376,11 @@
return mOrientation == VERTICAL;
}
+ @Override
+ public boolean isLayoutReversed() {
+ return mReverseLayout;
+ }
+
/**
* Compatibility support for {@link android.widget.AbsListView#setStackFromBottom(boolean)}
*/
diff --git a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
index db5526b..b908dc3 100644
--- a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
+++ b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
@@ -48,6 +48,7 @@
import android.view.Display;
import android.view.FocusFinder;
import android.view.InputDevice;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -1957,6 +1958,72 @@
}
@Override
+ public boolean dispatchKeyEvent(@Nullable KeyEvent event) {
+ // Let child to dispatch first, then handle ours if child didn't do it.
+ if (super.dispatchKeyEvent(event)) {
+ return true;
+ }
+
+ if (getLayoutManager().canScrollVertically()) {
+ final int keyCode = event.getKeyCode();
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_PAGE_DOWN:
+ case KeyEvent.KEYCODE_PAGE_UP:
+ int height = getMeasuredHeight();
+ if (keyCode == KeyEvent.KEYCODE_PAGE_DOWN) {
+ smoothScrollBy(0, height, null, UNDEFINED_DURATION);
+ } else {
+ smoothScrollBy(0, -height, null, UNDEFINED_DURATION);
+ }
+ return true;
+
+ case KeyEvent.KEYCODE_MOVE_HOME:
+ case KeyEvent.KEYCODE_MOVE_END:
+ final boolean isReversed = getLayoutManager().isLayoutReversed();
+
+ final int targetOffset;
+ if (keyCode == KeyEvent.KEYCODE_MOVE_HOME) {
+ targetOffset = isReversed ? getAdapter().getItemCount() : 0;
+ } else {
+ targetOffset = isReversed ? 0 : getAdapter().getItemCount();
+ }
+
+ smoothScrollToPosition(targetOffset);
+ return true;
+ }
+ } else if (getLayoutManager().canScrollHorizontally()) {
+ final int keyCode = event.getKeyCode();
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_PAGE_DOWN:
+ case KeyEvent.KEYCODE_PAGE_UP:
+ int width = getMeasuredWidth();
+ if (keyCode == KeyEvent.KEYCODE_PAGE_DOWN) {
+ smoothScrollBy(width, 0, null, UNDEFINED_DURATION);
+ } else {
+ smoothScrollBy(-width, 0, null, UNDEFINED_DURATION);
+ }
+ return true;
+
+ case KeyEvent.KEYCODE_MOVE_HOME:
+ case KeyEvent.KEYCODE_MOVE_END:
+ final boolean isReversed = getLayoutManager().isLayoutReversed();
+
+ final int targetOffset;
+ if (keyCode == KeyEvent.KEYCODE_MOVE_HOME) {
+ targetOffset = isReversed ? getAdapter().getItemCount() : 0;
+ } else {
+ targetOffset = isReversed ? 0 : getAdapter().getItemCount();
+ }
+
+ smoothScrollToPosition(targetOffset);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
public void scrollBy(int x, int y) {
if (mLayout == null) {
Log.e(TAG, "Cannot scroll without a LayoutManager set. "
@@ -9353,6 +9420,16 @@
}
/**
+ * Query if the layout is in reverse order. This will affect, for example, keyboard
+ * navigation via page up/page down. The default implementation returns false.
+ *
+ * @return true if this LayoutManager is currently in reverse order.
+ */
+ public boolean isLayoutReversed() {
+ return false;
+ }
+
+ /**
* Ends all animations on the view created by the {@link ItemAnimator}.
*
* @param view The View for which the animations should be ended.
diff --git a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/StaggeredGridLayoutManager.java b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/StaggeredGridLayoutManager.java
index 754ccd3..45911a1 100644
--- a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/StaggeredGridLayoutManager.java
+++ b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/StaggeredGridLayoutManager.java
@@ -2051,6 +2051,11 @@
}
@Override
+ public boolean isLayoutReversed() {
+ return mReverseLayout;
+ }
+
+ @Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
RecyclerView.State state) {
return scrollBy(dx, recycler, state);
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/QueryInterceptorTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/QueryInterceptorTest.kt
index 4f6a445..82a15d5 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/QueryInterceptorTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/QueryInterceptorTest.kt
@@ -82,12 +82,10 @@
ApplicationProvider.getApplicationContext(),
QueryInterceptorTestDatabase::class.java
).setQueryCallback(
- object : RoomDatabase.QueryCallback {
- override fun onQuery(sqlQuery: String, bindArgs: List<Any?>) {
- val argTrace = ArrayList<Any?>()
- argTrace.addAll(bindArgs)
- queryAndArgs.add(Pair(sqlQuery, argTrace))
- }
+ { sqlQuery, bindArgs ->
+ val argTrace = ArrayList<Any?>()
+ argTrace.addAll(bindArgs)
+ queryAndArgs.add(Pair(sqlQuery, argTrace))
},
MoreExecutors.directExecutor()
).build()
@@ -190,12 +188,10 @@
ApplicationProvider.getApplicationContext(),
QueryInterceptorTestDatabase::class.java
).setQueryCallback(
- object : RoomDatabase.QueryCallback {
- override fun onQuery(sqlQuery: String, bindArgs: List<Any?>) {
- val argTrace = ArrayList<Any?>()
- argTrace.addAll(bindArgs)
- queryAndArgs.add(Pair(sqlQuery, argTrace))
- }
+ { sqlQuery, bindArgs ->
+ val argTrace = ArrayList<Any?>()
+ argTrace.addAll(bindArgs)
+ queryAndArgs.add(Pair(sqlQuery, argTrace))
},
MoreExecutors.directExecutor()
)
diff --git a/room/room-common/api/restricted_current.txt b/room/room-common/api/restricted_current.txt
index 139f37e..85cc4ca 100644
--- a/room/room-common/api/restricted_current.txt
+++ b/room/room-common/api/restricted_current.txt
@@ -360,6 +360,7 @@
method public static String createInsertQuery(String hash);
field public static final String CREATE_QUERY = "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)";
field public static final String DEFAULT_ID = "42";
+ field public static final androidx.room.RoomMasterTable INSTANCE;
field public static final String NAME = "room_master_table";
field public static final String READ_QUERY = "SELECT identity_hash FROM room_master_table WHERE id = 42 LIMIT 1";
field public static final String TABLE_NAME = "room_master_table";
diff --git a/room/room-common/lint-baseline.xml b/room/room-common/lint-baseline.xml
deleted file mode 100644
index 1caa6b9..0000000
--- a/room/room-common/lint-baseline.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public object AmbiguousColumnResolver {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/AmbiguousColumnResolver.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public object RoomMasterTable {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomMasterTable.kt"/>
- </issue>
-
-</issues>
diff --git a/room/room-common/src/main/java/androidx/room/AmbiguousColumnResolver.kt b/room/room-common/src/main/java/androidx/room/AmbiguousColumnResolver.kt
index e0576d1..11448f6 100644
--- a/room/room-common/src/main/java/androidx/room/AmbiguousColumnResolver.kt
+++ b/room/room-common/src/main/java/androidx/room/AmbiguousColumnResolver.kt
@@ -46,7 +46,6 @@
* is the current best. The algorithms prefers a solution whose matches ranges don't overlap and
* are continuous.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public object AmbiguousColumnResolver {
diff --git a/room/room-common/src/main/java/androidx/room/RoomMasterTable.kt b/room/room-common/src/main/java/androidx/room/RoomMasterTable.kt
index 0cdd520..4af3272 100644
--- a/room/room-common/src/main/java/androidx/room/RoomMasterTable.kt
+++ b/room/room-common/src/main/java/androidx/room/RoomMasterTable.kt
@@ -22,7 +22,6 @@
/**
* Schema information about Room's master table.
*
- * @hide
*/
@SuppressWarnings("WeakerAccess")
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
diff --git a/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/CompilationResultSubject.kt b/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/CompilationResultSubject.kt
index 83ccfd4..405c5a1 100644
--- a/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/CompilationResultSubject.kt
+++ b/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/CompilationResultSubject.kt
@@ -31,6 +31,7 @@
import com.google.testing.compile.Compilation
import java.util.regex.Pattern
import javax.tools.Diagnostic
+import org.junit.AssumptionViolatedException
/**
* Holds the information about a test compilation result.
@@ -415,6 +416,11 @@
internal fun assertNoProcessorAssertionErrors() {
val processingException = compilationResult.processor.getProcessingException()
if (processingException != null) {
+ // processor has an assumption violation, re-throw so test case does not generate
+ // a failure
+ if (processingException is AssumptionViolatedException) {
+ throw processingException
+ }
// processor has an error which we want to throw but we also want the subject, hence
// we wrap it
throw CompilationAssertionError(
diff --git a/room/room-compiler-processing/build.gradle b/room/room-compiler-processing/build.gradle
index 07001c6..27d6c07 100644
--- a/room/room-compiler-processing/build.gradle
+++ b/room/room-compiler-processing/build.gradle
@@ -98,8 +98,9 @@
}
}
-tasks.withType(Test).configureEach {
- it.systemProperty("androidx.room.compiler.processing.strict", "true")
+tasks.withType(Test).configureEach { test ->
+ test.maxParallelForks(2)
+ test.systemProperty("androidx.room.compiler.processing.strict", "true")
}
androidx {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XHasModifiers.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XHasModifiers.kt
index 5423aab..4750ec2 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XHasModifiers.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XHasModifiers.kt
@@ -41,6 +41,11 @@
fun isAbstract(): Boolean
/**
+ * Returns `true` if this element has private modifier in Kotlin.
+ */
+ fun isKtPrivate(): Boolean = isPrivate()
+
+ /**
* Returns `true` if this element has private modifier.
*/
fun isPrivate(): Boolean
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt
index 7d8bbe1..da08a2f 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt
@@ -132,6 +132,10 @@
return element.modifiers.contains(Modifier.ABSTRACT)
}
+ override fun isKtPrivate(): Boolean {
+ return kotlinMetadata?.flags?.let { Flag.IS_PRIVATE(it) } ?: false
+ }
+
override fun isPrivate(): Boolean {
return element.modifiers.contains(Modifier.PRIVATE)
}
@@ -147,4 +151,4 @@
override fun isFinal(): Boolean {
return element.modifiers.contains(Modifier.FINAL)
}
-}
\ No newline at end of file
+}
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 9e8131c..3a0e081 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
@@ -166,12 +166,23 @@
element
)
}
- // TODO: Support more metadata kind (file facade, synthetic class, etc...)
return when (classMetadata) {
is KotlinClassMetadata.Class -> KmClassContainer(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
+ // could be discovered by processors when inspecting inner classes.
+ is KotlinClassMetadata.SyntheticClass,
+ // Multi file classes are also ignored, the elements contained in these might be
+ // referenced by user code in method bodies but not part of the AST, however it
+ // is possible for a processor to discover them by inspecting elements under a
+ // package.
+ is KotlinClassMetadata.FileFacade,
+ is KotlinClassMetadata.MultiFileClassFacade,
+ is KotlinClassMetadata.MultiFileClassPart -> null
else -> {
env.delegate.messager.printMessage(
- Diagnostic.Kind.WARNING,
+ Diagnostic.Kind.ERROR,
"Unable to read Kotlin metadata due to unsupported metadata " +
"kind: $classMetadata.",
element
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeVarianceResolver.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeVarianceResolver.kt
index 2687c5e..ca11a18 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeVarianceResolver.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeVarianceResolver.kt
@@ -51,7 +51,9 @@
*/
@OptIn(KspExperimental::class)
fun applyTypeVariance(type: KSType, scope: KSTypeVarianceResolverScope?): KSType {
- if (type.isError || scope?.needsWildcardResolution == false) {
+ if (type.isError ||
+ resolver.isJavaRawType(type) ||
+ scope?.needsWildcardResolution == false) {
// There's nothing to resolve in this case, so just return the original type.
return type
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspHasModifiers.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspHasModifiers.kt
index 8e0aae7..749ab3e 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspHasModifiers.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspHasModifiers.kt
@@ -62,6 +62,10 @@
}
}
+ override fun isKtPrivate(): Boolean {
+ return isPrivate()
+ }
+
override fun isPrivate(): Boolean {
return declaration.isPrivate()
}
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 1c503e9..079024d 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
@@ -339,7 +339,7 @@
val result = mutableSetOf<String>()
if (element.isAbstract()) result.add("abstract")
if (element.isFinal()) result.add("final")
- if (element.isPrivate()) result.add("private")
+ if (element.isPrivate() || element.isKtPrivate()) result.add("private")
if (element.isProtected()) result.add("protected")
if (element.isPublic()) result.add("public")
if (element.isKotlinObject()) result.add("object")
@@ -371,14 +371,7 @@
assertThat(getModifiers("Final"))
.containsExactly("final", "public", "class")
assertThat(getModifiers("PrivateClass"))
- .containsExactlyElementsIn(
- if (invocation.isKsp) {
- listOf("private", "final", "class")
- } else {
- // java does not support top level private classes.
- listOf("final", "class")
- }
- )
+ .containsExactly("private", "final", "class")
assertThat(getModifiers("OuterKotlinClass.InnerKotlinClass"))
.containsExactly("final", "public", "class")
assertThat(getModifiers("OuterKotlinClass.NestedKotlinClass"))
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
index 12b61d7..babbadec 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
@@ -67,9 +67,11 @@
package foo.bar;
import java.io.InputStream;
import java.util.Set;
+ import java.util.List;
class Parent<InputStreamType extends InputStream> {
public void wildcardParam(Set<?> param1) {}
- public void rawTypeParam(Set param1) {}
+ public void rawParamType(Set param1) {}
+ public void rawParamTypeArgument(List<Set> param1) {}
}
""".trimIndent()
)
@@ -145,9 +147,42 @@
)
}
}
- type.typeElement!!.getMethodByJvmName("rawTypeParam").let { method ->
- val rawTypeParam = method.parameters.first()
- assertThat(rawTypeParam.type.typeArguments).isEmpty()
+ type.typeElement!!.getMethodByJvmName("rawParamType").let { method ->
+ val rawParamType = method.parameters.first()
+ assertThat(rawParamType.type.typeArguments).isEmpty()
+ assertThat(rawParamType.type.asTypeName().java).isEqualTo(
+ JClassName.get("java.util", "Set")
+ )
+ if (it.isKsp) {
+ assertThat(rawParamType.type.asTypeName().kotlin).isEqualTo(
+ KClassName("kotlin.collections", "MutableSet")
+ )
+ }
+ }
+ type.typeElement!!.getMethodByJvmName("rawParamTypeArgument").let { method ->
+ val rawParamTypeArgument = method.parameters.first()
+ assertThat(rawParamTypeArgument.type.asTypeName().java).isEqualTo(
+ JParameterizedTypeName.get(
+ JClassName.get("java.util", "List"),
+ JClassName.get("java.util", "Set"),
+ )
+ )
+ if (it.isKsp) {
+ assertThat(rawParamTypeArgument.type.asTypeName().kotlin).isEqualTo(
+ KClassName("kotlin.collections", "MutableList").parameterizedBy(
+ KClassName("kotlin.collections", "MutableSet")
+ )
+ )
+ }
+ val rawTypeArgument = rawParamTypeArgument.type.typeArguments.single()
+ assertThat(rawTypeArgument.asTypeName().java).isEqualTo(
+ JClassName.get("java.util", "Set")
+ )
+ if (it.isKsp) {
+ assertThat(rawTypeArgument.asTypeName().kotlin).isEqualTo(
+ KClassName("kotlin.collections", "MutableSet")
+ )
+ }
}
}
}
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 5915327..43c856b 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
@@ -20,6 +20,7 @@
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
import androidx.room.compiler.processing.util.compileFiles
import androidx.room.compiler.processing.util.runJavaProcessorTest
import androidx.room.compiler.processing.util.runKaptTest
@@ -792,6 +793,111 @@
}
}
+ @Test
+ fun ignore_syntheticMetadata_defaultImpls() {
+ val src = Source.kotlin(
+ "Subject.kt",
+ """
+ interface Subject {
+ fun instance(): String = "Hello"
+ }
+ """.trimIndent()
+ )
+ simpleRun(
+ sources = listOf(src),
+ kotlincArgs = listOf("-Xjvm-default=disable")
+ ) {
+ val subjectElement = processingEnv.requireTypeElement("Subject.DefaultImpls")
+ // Call metadata derived API causing it to be read
+ assertThat(subjectElement.isKotlinObject()).isFalse()
+ assertCompilationResult {
+ hasNoWarnings()
+ }
+ }
+ }
+
+ @Test
+ fun ignore_syntheticMetadata_whenMappings() {
+ val src = Source.kotlin(
+ "Subject.kt",
+ """
+ class Subject {
+ enum class Fruit {
+ APPLE,
+ STRAWBERRY
+ }
+
+ fun printName(fruit: Fruit) {
+ println(
+ when(fruit) {
+ Fruit.APPLE -> "manzana"
+ Fruit.STRAWBERRY -> "fresa"
+ }
+ )
+ }
+ }
+ """.trimIndent()
+ )
+ simpleRun(
+ sources = listOf(src),
+ ) {
+ assertThat(processingEnv.findTypeElement("Subject.Fruit")).isNotNull()
+ val subjectElement = processingEnv.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.
+ ?: throw AssumptionViolatedException("No test if WhenMappings is not found")
+ // Call metadata derived API causing it to be read
+ assertThat(subjectElement.isKotlinObject()).isFalse()
+ assertCompilationResult {
+ hasNoWarnings()
+ }
+ }
+ }
+
+ @Test
+ fun ignore_fileFacadeMetadata() {
+ val aSrc = Source.kotlin(
+ "A.kt",
+ """
+ @file:JvmMultifileClass
+ @file:JvmName("Subject")
+
+ fun a() { }
+ """.trimIndent()
+ )
+ val bSrc = Source.kotlin(
+ "B.kt",
+ """
+ @file:JvmMultifileClass
+ @file:JvmName("Subject")
+
+ fun b() { }
+ """.trimIndent()
+ )
+ simpleRun(
+ sources = listOf(aSrc, bSrc),
+ ) {
+ // Find the multi file class facade element
+ val facadeElement = processingEnv.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")
+ ?: throw AssumptionViolatedException("No test if MultiFileClassPart is not found")
+ assertThat(facadePartOne.isKotlinObject()).isFalse()
+ val facadePartTwo = processingEnv.findTypeElement("Subject__BKt")
+ ?: throw AssumptionViolatedException("No test if MultiFileClassPart is not found")
+ assertThat(facadePartTwo.isKotlinObject()).isFalse()
+ assertCompilationResult {
+ hasNoWarnings()
+ }
+ }
+ }
+
private fun TypeElement.getDeclaredMethods() = ElementFilter.methodsIn(enclosedElements)
private fun TypeElement.getDeclaredMethod(name: String) = getDeclaredMethods().first {
@@ -803,19 +909,24 @@
@Suppress("NAME_SHADOWING") // intentional
private fun simpleRun(
sources: List<Source> = emptyList(),
- handler: (ProcessingEnvironment) -> Unit
+ kotlincArgs: List<String> = emptyList(),
+ handler: XTestInvocation.(ProcessingEnvironment) -> Unit
) {
val (sources, classpath) = if (preCompiled) {
emptyList<Source>() to compileFiles(sources)
} else {
sources to emptyList()
}
- runKaptTest(sources = sources, classpath = classpath) {
+ runKaptTest(
+ sources = sources,
+ classpath = classpath,
+ kotlincArguments = kotlincArgs
+ ) {
val processingEnv = it.processingEnv
if (processingEnv !is JavacProcessingEnv) {
throw AssumptionViolatedException("This test only works for java/kapt compilation")
}
- handler(processingEnv.delegate)
+ it.handler(processingEnv.delegate)
}
}
diff --git a/room/room-compiler/build.gradle b/room/room-compiler/build.gradle
index 98470ed..adfed82 100644
--- a/room/room-compiler/build.gradle
+++ b/room/room-compiler/build.gradle
@@ -291,7 +291,7 @@
tasks.withType(Test).configureEach {
it.systemProperty("androidx.room.compiler.processing.strict", "true")
- it.maxParallelForks(3)
+ it.maxParallelForks(5)
if (project.providers.environmentVariable("GITHUB_ACTIONS").present) {
// limit memory usage to avoid running out of memory in the docker container.
it.maxHeapSize("512m")
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
index b32301e..a4c6126 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
@@ -54,6 +54,7 @@
import org.hamcrest.CoreMatchers.notNullValue
import org.hamcrest.CoreMatchers.sameInstance
import org.hamcrest.MatcherAssert.assertThat
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
@@ -340,6 +341,7 @@
}
@Test
+ @Ignore("b/285140651")
fun detectMissingEntityAnnotationInLibraryClass() {
val librarySource = Source.java(
"test.library.MissingEntityAnnotationPojo",
@@ -376,6 +378,7 @@
}
@Test
+ @Ignore("b/285140651")
fun detectMissingDaoAnnotationInLibraryClass() {
val librarySource = Source.java(
"test.library.MissingAnnotationsBaseDao",
diff --git a/room/room-runtime/api/aidlRelease/current/androidx/room/IMultiInstanceInvalidationCallback.aidl b/room/room-runtime/api/aidlRelease/current/androidx/room/IMultiInstanceInvalidationCallback.aidl
index 17586bd..b1b0fe2 100644
--- a/room/room-runtime/api/aidlRelease/current/androidx/room/IMultiInstanceInvalidationCallback.aidl
+++ b/room/room-runtime/api/aidlRelease/current/androidx/room/IMultiInstanceInvalidationCallback.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.room;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IMultiInstanceInvalidationCallback {
oneway void onInvalidation(in String[] tables);
}
diff --git a/room/room-runtime/api/aidlRelease/current/androidx/room/IMultiInstanceInvalidationService.aidl b/room/room-runtime/api/aidlRelease/current/androidx/room/IMultiInstanceInvalidationService.aidl
index 19e8734..92245f1 100644
--- a/room/room-runtime/api/aidlRelease/current/androidx/room/IMultiInstanceInvalidationService.aidl
+++ b/room/room-runtime/api/aidlRelease/current/androidx/room/IMultiInstanceInvalidationService.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package androidx.room;
-/* @hide */
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IMultiInstanceInvalidationService {
int registerCallback(androidx.room.IMultiInstanceInvalidationCallback callback, String name);
void unregisterCallback(androidx.room.IMultiInstanceInvalidationCallback callback, int clientId);
diff --git a/room/room-runtime/api/current.txt b/room/room-runtime/api/current.txt
index 85a503e..2b171d7 100644
--- a/room/room-runtime/api/current.txt
+++ b/room/room-runtime/api/current.txt
@@ -146,7 +146,7 @@
method public void onOpenPrepackagedDatabase(androidx.sqlite.db.SupportSQLiteDatabase db);
}
- public static interface RoomDatabase.QueryCallback {
+ public static fun interface RoomDatabase.QueryCallback {
method public void onQuery(String sqlQuery, java.util.List<?> bindArgs);
}
diff --git a/room/room-runtime/api/restricted_current.txt b/room/room-runtime/api/restricted_current.txt
index 3c93dee..0d2b10b 100644
--- a/room/room-runtime/api/restricted_current.txt
+++ b/room/room-runtime/api/restricted_current.txt
@@ -201,7 +201,7 @@
method public void onOpenPrepackagedDatabase(androidx.sqlite.db.SupportSQLiteDatabase db);
}
- public static interface RoomDatabase.QueryCallback {
+ public static fun interface RoomDatabase.QueryCallback {
method public void onQuery(String sqlQuery, java.util.List<?> bindArgs);
}
diff --git a/room/room-runtime/lint-baseline.xml b/room/room-runtime/lint-baseline.xml
index e72c996..3774d1b 100644
--- a/room/room-runtime/lint-baseline.xml
+++ b/room/room-runtime/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
+<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">
<issue
id="NewApi"
@@ -11,240 +11,6 @@
</issue>
<issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class FtsTableInfo("
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/util/FtsTableInfo.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" constructor(database: RoomDatabase, vararg tableNames: String) :"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/InvalidationTracker.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open fun addWeakObserver(observer: Observer) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/InvalidationTracker.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open fun refreshVersionsSync() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/InvalidationTracker.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" fun notifyObserversByTableNames(vararg tables: String) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/InvalidationTracker.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open fun <T> createLiveData("
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/InvalidationTracker.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open fun <T> createLiveData("
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/InvalidationTracker.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public abstract class LimitOffsetDataSource<T> extends androidx.paging.PositionalDataSource<T> {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/paging/LimitOffsetDataSource.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int countItems() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/paging/LimitOffsetDataSource.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<T> loadRange(int startPosition, int loadCount) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/paging/LimitOffsetDataSource.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected var mCallbacks: List<Callback>? = null"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomDatabase.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected var autoMigrationSpecs: MutableMap<Class<out AutoMigrationSpec>, AutoMigrationSpec> ="
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomDatabase.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" val backingFieldMap: MutableMap<String, Any> = Collections.synchronizedMap(mutableMapOf())"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomDatabase.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open fun getAutoMigrations("
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomDatabase.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open fun getRequiredAutoMigrationSpecs(): Set<Class<out AutoMigrationSpec>> {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomDatabase.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open fun assertNotMainThread() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomDatabase.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open fun assertNotSuspendingTransaction() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomDatabase.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" const val MAX_BIND_PARAMETER_CNT = 999"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomDatabase.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="open class RoomOpenHelper("
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomOpenHelper.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" abstract class Delegate(@JvmField val version: Int) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomOpenHelper.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" open class ValidationResult("
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomOpenHelper.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class RoomSQLiteQuery private constructor("
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/RoomSQLiteQuery.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class TableInfo("
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/util/TableInfo.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" class ForeignKey("
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/room/util/TableInfo.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" class Index("
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/room/util/TableInfo.kt"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class ViewInfo("
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/room/util/ViewInfo.kt"/>
- </issue>
-
- <issue
id="BanThreadSleep"
message="Uses Thread.sleep()"
errorLine1=" Thread.sleep(5)"
@@ -397,22 +163,4 @@
file="src/test/java/androidx/room/TransactionExecutorTest.kt"/>
</issue>
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="interface IMultiInstanceInvalidationCallback {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/room/IMultiInstanceInvalidationCallback.aidl"/>
- </issue>
-
- <issue
- id="RequireUnstableAidlAnnotation"
- message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
- errorLine1="interface IMultiInstanceInvalidationService {"
- errorLine2="^">
- <location
- file="src/main/aidl/androidx/room/IMultiInstanceInvalidationService.aidl"/>
- </issue>
-
</issues>
diff --git a/room/room-runtime/src/androidTest/java/androidx/room/AutoCloserTest.kt b/room/room-runtime/src/androidTest/java/androidx/room/AutoCloserTest.kt
index 6a3fc94..2c72153 100644
--- a/room/room-runtime/src/androidTest/java/androidx/room/AutoCloserTest.kt
+++ b/room/room-runtime/src/androidTest/java/androidx/room/AutoCloserTest.kt
@@ -90,6 +90,7 @@
assertThat(countingTaskExecutorRule.isIdle).isTrue()
}
+ @Ignore("b/283959848")
@Test
public fun refCountsCounted() {
autoCloser.incrementCountAndEnsureDbIsOpen()
diff --git a/room/room-runtime/src/main/java/androidx/room/InvalidationTracker.kt b/room/room-runtime/src/main/java/androidx/room/InvalidationTracker.kt
index 0117214..91b934a 100644
--- a/room/room-runtime/src/main/java/androidx/room/InvalidationTracker.kt
+++ b/room/room-runtime/src/main/java/androidx/room/InvalidationTracker.kt
@@ -111,7 +111,6 @@
/**
* Used by the generated code.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
constructor(database: RoomDatabase, vararg tableNames: String) :
@@ -302,7 +301,6 @@
* when the observer is GC'ed.
*
* @param observer The observer to which InvalidationTracker will keep a weak reference.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
open fun addWeakObserver(observer: Observer) {
@@ -445,7 +443,6 @@
/**
* Check versions for tables, and run observers synchronously if tables have been updated.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@WorkerThread
@@ -463,7 +460,6 @@
* [InvalidationTracker], for example, invalidation from another process.
*
* @param tables The invalidated tables.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
fun notifyObserversByTableNames(vararg tables: String) {
@@ -542,7 +538,6 @@
* @param T The return type
* @return A new LiveData that computes the given function when the given list of tables
* invalidates.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@Deprecated("Use [createLiveData(String[], boolean, Callable)]")
@@ -566,7 +561,6 @@
* @param T The return type
* @return A new LiveData that computes the given function when the given list of tables
* invalidates.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
open fun <T> createLiveData(
diff --git a/room/room-runtime/src/main/java/androidx/room/RoomDatabase.kt b/room/room-runtime/src/main/java/androidx/room/RoomDatabase.kt
index 798a2fbc..bc86569 100644
--- a/room/room-runtime/src/main/java/androidx/room/RoomDatabase.kt
+++ b/room/room-runtime/src/main/java/androidx/room/RoomDatabase.kt
@@ -110,7 +110,6 @@
private var writeAheadLoggingEnabled = false
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@Deprecated("Will be hidden in a future release.")
@@ -120,9 +119,9 @@
/**
* A map of auto migration spec classes to their provided instance.
*
- * @hide
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @set:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
protected var autoMigrationSpecs: MutableMap<Class<out AutoMigrationSpec>, AutoMigrationSpec> =
mutableMapOf()
private val readWriteLock = ReentrantReadWriteLock()
@@ -154,7 +153,6 @@
/**
* Gets the map for storing extension properties of Kotlin type.
*
- * @hide
*/
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
val backingFieldMap: MutableMap<String, Any> = Collections.synchronizedMap(mutableMapOf())
@@ -298,7 +296,6 @@
* @return A list of migration instances each of which is a generated autoMigration
* @param autoMigrationSpecs
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmSuppressWildcards // Suppress wildcards due to generated Java code
@@ -369,7 +366,6 @@
*
* @return Creates a set that will include all required auto migration specs for this database.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
open fun getRequiredAutoMigrationSpecs(): Set<Class<out AutoMigrationSpec>> {
@@ -434,7 +430,6 @@
/**
* Asserts that we are not on the main thread.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
open fun assertNotMainThread() {
@@ -450,7 +445,6 @@
/**
* Asserts that we are not on a suspending transaction.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // used in generated code
open fun assertNotSuspendingTransaction() {
@@ -1532,7 +1526,7 @@
*
* Can be set using [RoomDatabase.Builder.setQueryCallback].
*/
- interface QueryCallback {
+ fun interface QueryCallback {
/**
* Called when a SQL query is executed.
*
@@ -1546,7 +1540,6 @@
/**
* Unfortunately, we cannot read this value so we are only setting it to the SQLite default.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
const val MAX_BIND_PARAMETER_CNT = 999
diff --git a/room/room-runtime/src/main/java/androidx/room/RoomOpenHelper.kt b/room/room-runtime/src/main/java/androidx/room/RoomOpenHelper.kt
index 929dcca..44f7f15 100644
--- a/room/room-runtime/src/main/java/androidx/room/RoomOpenHelper.kt
+++ b/room/room-runtime/src/main/java/androidx/room/RoomOpenHelper.kt
@@ -24,7 +24,6 @@
/**
* An open helper that holds a reference to the configuration until the database is opened.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
open class RoomOpenHelper(
@@ -175,7 +174,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
abstract class Delegate(@JvmField val version: Int) {
@@ -219,7 +217,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
open class ValidationResult(
diff --git a/room/room-runtime/src/main/java/androidx/room/RoomSQLiteQuery.kt b/room/room-runtime/src/main/java/androidx/room/RoomSQLiteQuery.kt
index c13695e..f04d520 100644
--- a/room/room-runtime/src/main/java/androidx/room/RoomSQLiteQuery.kt
+++ b/room/room-runtime/src/main/java/androidx/room/RoomSQLiteQuery.kt
@@ -29,7 +29,6 @@
*
* Because it is relatively a big object, they are pooled and must be released after each use.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
class RoomSQLiteQuery private constructor(
diff --git a/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java b/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java
index 81ba417..2b5c391 100644
--- a/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java
+++ b/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java
@@ -46,7 +46,6 @@
*
* @param <T> Data type returned by the data source.
*
- * @hide
*/
@SuppressWarnings("deprecation")
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@@ -117,8 +116,8 @@
/**
* Count number of rows query can return
*
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
@SuppressWarnings("WeakerAccess")
public int countItems() {
registerObserverIfNecessary();
@@ -194,8 +193,8 @@
/**
* Return the rows from startPos to startPos + loadCount
*
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
@SuppressWarnings("deprecation")
@NonNull
public List<T> loadRange(int startPosition, int loadCount) {
diff --git a/room/room-runtime/src/main/java/androidx/room/util/FtsTableInfo.kt b/room/room-runtime/src/main/java/androidx/room/util/FtsTableInfo.kt
index f6fa32d..e439ee5 100644
--- a/room/room-runtime/src/main/java/androidx/room/util/FtsTableInfo.kt
+++ b/room/room-runtime/src/main/java/androidx/room/util/FtsTableInfo.kt
@@ -24,7 +24,6 @@
/**
* A data class that holds the information about an FTS table.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
class FtsTableInfo(
diff --git a/room/room-runtime/src/main/java/androidx/room/util/TableInfo.kt b/room/room-runtime/src/main/java/androidx/room/util/TableInfo.kt
index 50518c1..246dfdc 100644
--- a/room/room-runtime/src/main/java/androidx/room/util/TableInfo.kt
+++ b/room/room-runtime/src/main/java/androidx/room/util/TableInfo.kt
@@ -36,7 +36,6 @@
*
* Even though SQLite column names are case insensitive, this class uses case sensitive matching.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
// if you change this class, you must change TableInfoValidationWriter.kt
@@ -334,7 +333,6 @@
/**
* Holds the information about an SQLite foreign key
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
class ForeignKey(
@@ -398,7 +396,6 @@
/**
* Holds the information about an SQLite index
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
class Index(
diff --git a/room/room-runtime/src/main/java/androidx/room/util/UUIDUtil.kt b/room/room-runtime/src/main/java/androidx/room/util/UUIDUtil.kt
index e5c9198..4d7810c 100644
--- a/room/room-runtime/src/main/java/androidx/room/util/UUIDUtil.kt
+++ b/room/room-runtime/src/main/java/androidx/room/util/UUIDUtil.kt
@@ -25,7 +25,6 @@
/**
* UUID / byte[] two-way conversion utility for Room
*
- * @hide
*/
/**
diff --git a/room/room-runtime/src/main/java/androidx/room/util/ViewInfo.kt b/room/room-runtime/src/main/java/androidx/room/util/ViewInfo.kt
index 83e7e80..6c664ce 100644
--- a/room/room-runtime/src/main/java/androidx/room/util/ViewInfo.kt
+++ b/room/room-runtime/src/main/java/androidx/room/util/ViewInfo.kt
@@ -27,7 +27,6 @@
*
* Even though SQLite column names are case insensitive, this class uses case sensitive matching.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
class ViewInfo(
diff --git a/room/room-runtime/src/main/stableAidl/androidx/room/IMultiInstanceInvalidationCallback.aidl b/room/room-runtime/src/main/stableAidl/androidx/room/IMultiInstanceInvalidationCallback.aidl
index 7c702ff..bc76559 100644
--- a/room/room-runtime/src/main/stableAidl/androidx/room/IMultiInstanceInvalidationCallback.aidl
+++ b/room/room-runtime/src/main/stableAidl/androidx/room/IMultiInstanceInvalidationCallback.aidl
@@ -18,9 +18,8 @@
/**
* RPC Callbacks for {@link IMultiInstanceInvalidationService}.
- *
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IMultiInstanceInvalidationCallback {
/**
diff --git a/room/room-runtime/src/main/stableAidl/androidx/room/IMultiInstanceInvalidationService.aidl b/room/room-runtime/src/main/stableAidl/androidx/room/IMultiInstanceInvalidationService.aidl
index 3b2c18c..cd8106b 100644
--- a/room/room-runtime/src/main/stableAidl/androidx/room/IMultiInstanceInvalidationService.aidl
+++ b/room/room-runtime/src/main/stableAidl/androidx/room/IMultiInstanceInvalidationService.aidl
@@ -20,9 +20,8 @@
/**
* RPC Service that controls interaction about multi-instance invalidation.
- *
- * @hide
*/
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
interface IMultiInstanceInvalidationService {
/**
diff --git a/samples/SupportEmojiDemos/src/main/java/com/example/android/support/text/emoji/MainFragment.java b/samples/SupportEmojiDemos/src/main/java/com/example/android/support/text/emoji/MainFragment.java
index 5d30bf9..d59a0b6 100644
--- a/samples/SupportEmojiDemos/src/main/java/com/example/android/support/text/emoji/MainFragment.java
+++ b/samples/SupportEmojiDemos/src/main/java/com/example/android/support/text/emoji/MainFragment.java
@@ -20,8 +20,10 @@
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.BackgroundColorSpan;
+import android.text.style.RelativeSizeSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.UnderlineSpan;
import android.view.LayoutInflater;
@@ -75,6 +77,7 @@
private AppCompatRadioButton mAppCompatRadioButton;
AppCompatAutoCompleteTextView mAppCompatAutoCompleteTextView;
AppCompatMultiAutoCompleteTextView mAppCompatMultiAutoCompleteTextView;
+ private TextView mRelative;
final Config.Listener mConfigListener = new Config.Listener() {
@Override
@@ -119,6 +122,8 @@
mAppCompatMultiAutoCompleteTextView =
view.findViewById(R.id.appcompat_multiautocomplete_textview);
+ mRelative = view.findViewById(R.id.relative);
+
final TextView emojiListButton = view.findViewById(R.id.emoji_list_button);
emojiListButton.setOnClickListener(new View.OnClickListener() {
@Override
@@ -197,5 +202,17 @@
}
});
mCustomTextView.setText(getString(R.string.custom_text_view, EMOJI));
+ mRelative.setText(relativeText());
+ mRelative.setTextSize(10);
+ }
+
+ private Spannable relativeText() {
+ SpannableStringBuilder builder = new SpannableStringBuilder();
+ builder.append(EMOJI);
+ RelativeSizeSpan sizeSpan = new RelativeSizeSpan(4F);
+ builder.setSpan(sizeSpan, 0, EMOJI.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ builder.append("<-- Relative Size 4.0 |||| regular size ->");
+ builder.append(EMOJI);
+ return builder;
}
}
diff --git a/samples/SupportEmojiDemos/src/main/res/layout/fragment_main.xml b/samples/SupportEmojiDemos/src/main/res/layout/fragment_main.xml
index fbee47d..dd82305 100644
--- a/samples/SupportEmojiDemos/src/main/res/layout/fragment_main.xml
+++ b/samples/SupportEmojiDemos/src/main/res/layout/fragment_main.xml
@@ -138,6 +138,11 @@
android:textSize="@dimen/text_size"
android:text="Show all emojis"/>
+ <TextView
+ android:id="@+id/relative"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
</LinearLayout>
</ScrollView>
diff --git a/settings.gradle b/settings.gradle
index 0f11a3a..3b8009a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -453,6 +453,7 @@
includeProject(":autofill:autofill", [BuildType.MAIN])
includeProject(":benchmark:benchmark-benchmark", "benchmark/benchmark", [BuildType.MAIN, BuildType.COMPOSE])
includeProject(":benchmark:benchmark-common")
+includeProject(":benchmark:benchmark-internal")
includeProject(":benchmark:benchmark-darwin", [BuildType.INFRAROGUE, BuildType.KMP])
includeProject(":benchmark:benchmark-darwin-core", [BuildType.INFRAROGUE, BuildType.KMP])
includeProject(":benchmark:benchmark-darwin-samples", [BuildType.INFRAROGUE, BuildType.KMP])
@@ -683,6 +684,9 @@
includeProject(":core:core-splashscreen:core-splashscreen-samples", "core/core-splashscreen/samples", [BuildType.MAIN])
includeProject(":core:core-graphics-integration-tests:core-graphics-integration-tests", "core/core-graphics-integration-tests/testapp", [BuildType.MAIN])
includeProject(":core:core-role", [BuildType.MAIN])
+includeProject(":core:haptics:haptics", [BuildType.MAIN])
+includeProject(":core:haptics:haptics-samples", "core/haptics/haptics/samples", [BuildType.MAIN])
+includeProject(":core:haptics:haptics-demos", "core/haptics/haptics/integration-tests/demos", [BuildType.MAIN])
includeProject(":core:uwb:uwb", [BuildType.MAIN])
includeProject(":core:uwb:uwb-rxjava3", [BuildType.MAIN])
includeProject(":credentials:credentials", [BuildType.MAIN])
@@ -1012,11 +1016,13 @@
includeProject(":wear:compose:compose-material3-benchmark", "wear/compose/compose-material3/benchmark", [BuildType.COMPOSE])
includeProject(":wear:compose:compose-material-core", [BuildType.COMPOSE])
includeProject(":wear:compose:compose-material-samples", "wear/compose/compose-material/samples", [BuildType.COMPOSE])
+includeProject(":wear:compose:compose-material3-integration-tests", "wear/compose/compose-material3/integration-tests", [BuildType.COMPOSE])
includeProject(":wear:compose:compose-material3-samples", "wear/compose/compose-material3/samples", [BuildType.COMPOSE])
includeProject(":wear:compose:compose-navigation", [BuildType.COMPOSE])
includeProject(":wear:compose:compose-navigation-samples", "wear/compose/compose-navigation/samples", [BuildType.COMPOSE])
includeProject(":wear:compose:compose-ui-tooling", [BuildType.COMPOSE])
includeProject(":wear:compose:integration-tests:demos", [BuildType.COMPOSE])
+includeProject(":wear:compose:integration-tests:demos:common", [BuildType.COMPOSE])
includeProject(":wear:compose:integration-tests:macrobenchmark", [BuildType.COMPOSE])
includeProject(":wear:compose:integration-tests:macrobenchmark-target", [BuildType.COMPOSE])
includeProject(":wear:compose:integration-tests:navigation", [BuildType.COMPOSE])
diff --git a/slice/slice-builders-ktx/lint-baseline.xml b/slice/slice-builders-ktx/lint-baseline.xml
deleted file mode 100644
index ba31f50..0000000
--- a/slice/slice-builders-ktx/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="annotation class SliceMarker"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.kt"/>
- </issue>
-
-</issues>
diff --git a/slice/slice-builders-ktx/src/main/java/androidx/slice/builders/ListBuilder.kt b/slice/slice-builders-ktx/src/main/java/androidx/slice/builders/ListBuilder.kt
index 0075e93..101ed21 100644
--- a/slice/slice-builders-ktx/src/main/java/androidx/slice/builders/ListBuilder.kt
+++ b/slice/slice-builders-ktx/src/main/java/androidx/slice/builders/ListBuilder.kt
@@ -23,9 +23,6 @@
import androidx.core.graphics.drawable.IconCompat
import androidx.slice.builders.ListBuilder.ICON_IMAGE
-/**
- * @hide
- */
@RestrictTo(LIBRARY)
@DslMarker
annotation class SliceMarker
diff --git a/slice/slice-builders/lint-baseline.xml b/slice/slice-builders/lint-baseline.xml
index bb7a657..125de78 100644
--- a/slice/slice-builders/lint-baseline.xml
+++ b/slice/slice-builders/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
+<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">
<issue
id="WrongConstant"
@@ -11,1401 +11,6 @@
</issue>
<issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction getPrimaryAction() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<CellBuilder> getCells() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CellBuilder getSeeMoreCell() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public PendingIntent getSeeMoreIntent() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getDescription() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getLayoutDirection() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int TYPE_TEXT = 0;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int TYPE_TITLE = 1;"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int TYPE_IMAGE = 2;"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int TYPE_OVERLAY = 3;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<Object> getObjects() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<Integer> getTypes() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<Boolean> getLoadings() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getCellDescription() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public PendingIntent getContentIntent() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getTitle() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getSubtitle() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction getSliceAction() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/GridRowBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class GridRowBuilderListV1Impl extends TemplateBuilderImpl {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/GridRowBuilderListV1Impl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void apply(@NonNull Slice.Builder b) {"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/GridRowBuilderListV1Impl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface ListBuilder {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @interface ImageMode {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @interface LayoutDirection {}"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected TemplateBuilderImpl selectImpl() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public androidx.slice.builders.impl.ListBuilder getImpl() {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @interface RangeMode {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isTitleItemLoading() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getTitleImageMode() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public IconCompat getTitleIcon() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getValue() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getMax() {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isValueSet() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getTitle() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getSubtitle() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction getPrimaryAction() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getContentDescription() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getLayoutDirection() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getMode() {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int TYPE_ACTION = 2;"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getMin() {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getMax() {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public float getValue() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isValueSet() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public PendingIntent getAction() {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getContentDescription() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public PendingIntent getInputAction() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getTitle() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getSubtitle() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction getPrimaryAction() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isTitleItemLoading() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getTitleImageMode() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public IconCompat getTitleIcon() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isTitleItemLoading() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getTitleImageMode() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public IconCompat getTitleIcon() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int TYPE_ACTION = 2;"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<Object> getEndItems() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<Integer> getEndTypes() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<Boolean> getEndLoads() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getMin() {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getMax() {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getValue() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isValueSet() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getTitle() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getSubtitle() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public PendingIntent getAction() {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public PendingIntent getInputAction() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public IconCompat getThumb() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction getPrimaryAction() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getContentDescription() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getLayoutDirection() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int TYPE_TIMESTAMP = 0;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int TYPE_ICON = 1;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int TYPE_ACTION = 2;"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Uri getUri() {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isEndOfSection() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean hasEndActionOrToggle() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean hasEndImage() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean hasDefaultToggle() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean hasTimestamp() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public long getTimeStamp() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isTitleItemLoading() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getTitleImageMode() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public IconCompat getTitleIcon() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction getTitleAction() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction getPrimaryAction() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getTitle() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isTitleLoading() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getSubtitle() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isSubtitleLoading() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getContentDescription() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getLayoutDirection() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<Object> getEndItems() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<Integer> getEndTypes() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<Boolean> getEndLoads() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isTitleActionLoading() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public HeaderBuilder(@NonNull final Uri uri) {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Uri getUri() {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getTitle() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isTitleLoading() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getSubtitle() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isSubtitleLoading() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getSummary() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isSummaryLoading() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction getPrimaryAction() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getContentDescription() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getLayoutDirection() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/ListBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class ListBuilderBasicImpl extends TemplateBuilderImpl implements ListBuilder {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class ListBuilderImpl extends TemplateBuilderImpl implements ListBuilder {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class MessagingBasicImpl extends TemplateBuilderImpl implements"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/MessagingBasicImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface MessagingBuilder {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/MessagingBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class MessagingListV1Impl extends TemplateBuilderImpl implements MessagingBuilder{"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/MessagingListV1Impl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class MessagingSliceBuilder extends TemplateSliceBuilder {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/MessagingSliceBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected TemplateBuilderImpl selectImpl() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/MessagingSliceBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class MessagingV1Impl extends TemplateBuilderImpl implements MessagingBuilder {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/MessagingV1Impl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public List<Pair<String, CharSequence>> getOptions() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SelectionBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction getPrimaryAction() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SelectionBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public PendingIntent getInputAction() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SelectionBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public String getSelectedOption() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SelectionBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getTitle() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SelectionBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getSubtitle() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SelectionBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getContentDescription() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SelectionBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getLayoutDirection() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SelectionBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void check() {"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SelectionBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SelectionBuilderBasicImpl extends SelectionBuilderImpl {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/SelectionBuilderBasicImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public abstract class SelectionBuilderImpl extends TemplateBuilderImpl {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/SelectionBuilderImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SelectionBuilderListV2Impl extends SelectionBuilderImpl {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/SelectionBuilderListV2Impl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction(@NonNull PendingIntent action, @NonNull CharSequence actionTitle,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction(@NonNull PendingIntent action, @NonNull CharSequence actionTitle,"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static SliceAction createDatePicker(@NonNull PendingIntent action,"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static SliceAction createTimePicker(@NonNull PendingIntent action,"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Slice buildSlice(@NonNull Slice.Builder builder) {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceActionImpl getImpl() {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setPrimaryAction(@NonNull Slice.Builder builder) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/SliceAction.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public abstract class TemplateBuilderImpl {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/TemplateBuilderImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Slice.Builder getBuilder() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/TemplateBuilderImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Slice.Builder createChildBuilder() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/TemplateBuilderImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public abstract void apply(@NonNull Slice.Builder builder);"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/TemplateBuilderImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Clock getClock() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/TemplateBuilderImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceSpec getSpec() {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/TemplateBuilderImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected ArrayList<String> parseImageMode(int imageMode, boolean isLoading) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/impl/TemplateBuilderImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected TemplateSliceBuilder(TemplateBuilderImpl impl) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/TemplateSliceBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public TemplateSliceBuilder(Context context, Uri uri) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/TemplateSliceBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected Slice.Builder getBuilder() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/TemplateSliceBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" abstract void setImpl(TemplateBuilderImpl impl);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/TemplateSliceBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected TemplateBuilderImpl selectImpl() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/TemplateSliceBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected boolean checkCompatible(SliceSpec candidate) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/TemplateSliceBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected Clock getClock() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/builders/TemplateSliceBuilder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" static <T> Pair<SliceSpec, Class<? extends TemplateBuilderImpl>> pair(SliceSpec spec,"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/slice/builders/TemplateSliceBuilder.java"/>
- </issue>
-
- <issue
id="ClassVerificationFailure"
message="This call references a method added in API level 26; however, the containing class androidx.slice.builders.impl.ListBuilderBasicImpl is reachable from earlier API levels and will fail run-time class verification."
errorLine1=" setTtl(ttl == null ? INFINITY : ttl.toMillis());"
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/GridRowBuilder.java b/slice/slice-builders/src/main/java/androidx/slice/builders/GridRowBuilder.java
index 4e8de26..4523685 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/GridRowBuilder.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/GridRowBuilder.java
@@ -184,7 +184,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public SliceAction getPrimaryAction() {
@@ -192,7 +191,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public List<CellBuilder> getCells() {
@@ -200,7 +198,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public CellBuilder getSeeMoreCell() {
@@ -208,7 +205,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public PendingIntent getSeeMoreIntent() {
@@ -216,7 +212,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public CharSequence getDescription() {
@@ -224,7 +219,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getLayoutDirection() {
@@ -265,22 +259,18 @@
*/
public static class CellBuilder {
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final int TYPE_TEXT = 0;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final int TYPE_TITLE = 1;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final int TYPE_IMAGE = 2;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final int TYPE_OVERLAY = 3;
@@ -465,7 +455,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public List<Object> getObjects() {
@@ -473,7 +462,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public List<Integer> getTypes() {
@@ -481,7 +469,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public List<Boolean> getLoadings() {
@@ -489,7 +476,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public CharSequence getCellDescription() {
@@ -497,7 +483,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public PendingIntent getContentIntent() {
@@ -505,7 +490,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -519,7 +503,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -533,7 +516,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/ListBuilder.java b/slice/slice-builders/src/main/java/androidx/slice/builders/ListBuilder.java
index b532dfe..77d5f5b 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/ListBuilder.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/ListBuilder.java
@@ -180,7 +180,6 @@
public static final int UNKNOWN_IMAGE = SliceHints.UNKNOWN_IMAGE;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
@@ -197,7 +196,6 @@
public static final long INFINITY = SliceHints.INFINITY;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
@@ -494,7 +492,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Override
@@ -511,7 +508,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@NonNull
@@ -520,7 +516,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
@@ -727,7 +722,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isTitleItemLoading() {
@@ -735,7 +729,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getTitleImageMode() {
@@ -743,7 +736,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -752,7 +744,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getValue() {
@@ -760,7 +751,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getMax() {
@@ -768,7 +758,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isValueSet() {
@@ -776,7 +765,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -785,7 +773,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -794,7 +781,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -803,7 +789,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -812,7 +797,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getLayoutDirection() {
@@ -820,7 +804,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getMode() {
@@ -838,7 +821,6 @@
@SuppressLint("MissingBuildMethod")
public static final class RatingBuilder {
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final int TYPE_ACTION = 2;
@@ -867,7 +849,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getMin() {
@@ -884,7 +865,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getMax() {
@@ -901,7 +881,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public float getValue() {
@@ -922,7 +901,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isValueSet() {
@@ -930,7 +908,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -939,7 +916,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1029,7 +1005,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1058,7 +1033,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1067,7 +1041,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1076,7 +1049,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1085,7 +1057,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isTitleItemLoading() {
@@ -1093,7 +1064,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getTitleImageMode() {
@@ -1101,7 +1071,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1338,7 +1307,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isTitleItemLoading() {
@@ -1346,7 +1314,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getTitleImageMode() {
@@ -1354,7 +1321,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1363,13 +1329,11 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final int TYPE_ACTION = 2;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@NonNull
@@ -1378,7 +1342,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@NonNull
@@ -1387,7 +1350,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@NonNull
@@ -1396,7 +1358,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getMin() {
@@ -1404,7 +1365,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getMax() {
@@ -1412,7 +1372,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getValue() {
@@ -1420,7 +1379,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isValueSet() {
@@ -1428,7 +1386,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1437,7 +1394,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1446,7 +1402,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1455,7 +1410,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1464,7 +1418,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1473,7 +1426,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1482,7 +1434,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1491,7 +1442,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getLayoutDirection() {
@@ -1558,17 +1508,14 @@
private boolean mTitleActionLoading;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final int TYPE_TIMESTAMP = 0;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final int TYPE_ICON = 1;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final int TYPE_ACTION = 2;
@@ -1873,7 +1820,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1882,7 +1828,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isEndOfSection() {
@@ -1890,7 +1835,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean hasEndActionOrToggle() {
@@ -1898,7 +1842,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean hasEndImage() {
@@ -1906,7 +1849,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean hasDefaultToggle() {
@@ -1914,7 +1856,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean hasTimestamp() {
@@ -1922,7 +1863,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public long getTimeStamp() {
@@ -1930,7 +1870,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isTitleItemLoading() {
@@ -1938,7 +1877,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getTitleImageMode() {
@@ -1946,7 +1884,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1955,7 +1892,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1964,7 +1900,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1973,7 +1908,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1982,7 +1916,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isTitleLoading() {
@@ -1990,7 +1923,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -1999,7 +1931,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isSubtitleLoading() {
@@ -2007,7 +1938,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -2016,7 +1946,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getLayoutDirection() {
@@ -2024,7 +1953,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@NonNull
@@ -2033,7 +1961,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@NonNull
@@ -2042,7 +1969,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@NonNull
@@ -2051,7 +1977,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isTitleActionLoading() {
@@ -2103,7 +2028,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY_GROUP_PREFIX)
public HeaderBuilder(@NonNull final Uri uri) {
@@ -2227,7 +2151,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -2236,7 +2159,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -2245,7 +2167,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isTitleLoading() {
@@ -2253,7 +2174,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -2262,7 +2182,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isSubtitleLoading() {
@@ -2270,7 +2189,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -2279,7 +2197,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public boolean isSummaryLoading() {
@@ -2287,7 +2204,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -2296,7 +2212,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Nullable
@@ -2305,7 +2220,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getLayoutDirection() {
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/MessagingSliceBuilder.java b/slice/slice-builders/src/main/java/androidx/slice/builders/MessagingSliceBuilder.java
index e91c43f..4041d50 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/MessagingSliceBuilder.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/MessagingSliceBuilder.java
@@ -38,7 +38,6 @@
/**
* Builder to construct slice content in a messaging format.
- * @hide
*/
@RestrictTo(LIBRARY_GROUP_PREFIX)
@RequiresApi(19)
@@ -83,7 +82,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Override
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/SelectionBuilder.java b/slice/slice-builders/src/main/java/androidx/slice/builders/SelectionBuilder.java
index be06a6b..4e5550a 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/SelectionBuilder.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/SelectionBuilder.java
@@ -180,7 +180,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public List<Pair<String, CharSequence>> getOptions() {
@@ -188,7 +187,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public SliceAction getPrimaryAction() {
@@ -196,7 +194,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public PendingIntent getInputAction() {
@@ -204,7 +201,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public String getSelectedOption() {
@@ -212,7 +208,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public CharSequence getTitle() {
@@ -220,7 +215,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public CharSequence getSubtitle() {
@@ -228,7 +222,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public CharSequence getContentDescription() {
@@ -236,7 +229,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public int getLayoutDirection() {
@@ -244,7 +236,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public void check() {
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/SliceAction.java b/slice/slice-builders/src/main/java/androidx/slice/builders/SliceAction.java
index 0109be7..64263dd 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/SliceAction.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/SliceAction.java
@@ -43,7 +43,6 @@
private final SliceActionImpl mSliceAction;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(23)
@@ -53,7 +52,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(23)
@@ -63,7 +61,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(23)
@@ -79,7 +76,6 @@
* @param actionIcon the icon to display for this action.
* @param actionTitle the title for this action, also used for content description if one hasn't
* been set via {@link #setContentDescription(CharSequence)}.
- * @hide
*/
@RestrictTo(LIBRARY)
public SliceAction(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,
@@ -103,7 +99,6 @@
* @see ListBuilder#ICON_IMAGE
* @see ListBuilder#SMALL_IMAGE
* @see ListBuilder#LARGE_IMAGE
- * @hide
*/
@RestrictTo(LIBRARY_GROUP)
public SliceAction(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,
@@ -120,7 +115,6 @@
* @param actionTitle the title for this toggle, also used for content description if one hasn't
* been set via {@link #setContentDescription(CharSequence)}.
* @param isChecked the state of the toggle.
- * @hide
*/
@RestrictTo(LIBRARY_GROUP)
public SliceAction(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,
@@ -135,7 +129,6 @@
* @param actionTitle the title for this toggle, also used for content description if one hasn't
* been set via {@link #setContentDescription(CharSequence)}.
* @param isChecked the state of the toggle.
- * @hide
*/
@RestrictTo(LIBRARY_GROUP)
public SliceAction(@NonNull PendingIntent action, @NonNull CharSequence actionTitle,
@@ -150,7 +143,6 @@
* @param actionTitle the timestamp for this date or time picker.
* @param dateTimeMillis the default state of the date or time picker.
* @param isDatePicker if it is a date picker, as opposed to a time picker.
- * @hide
*/
@RestrictTo(LIBRARY_GROUP)
public SliceAction(@NonNull PendingIntent action, @NonNull CharSequence actionTitle,
@@ -203,8 +195,8 @@
* @param action the pending intent to invoke for this picker.
* @param actionTitle the timestamp title for this picker.
* @param dateTimeMillis the default state of the date picker.
- * @hide
*/
+ @RestrictTo(LIBRARY)
@NonNull
public static SliceAction createDatePicker(@NonNull PendingIntent action,
@NonNull CharSequence actionTitle, long dateTimeMillis) {
@@ -218,8 +210,8 @@
* @param action the pending intent to invoke for this picker.
* @param actionTitle the timestamp title for this picker.
* @param dateTimeMillis the default state of the time picker.
- * @hide
*/
+ @RestrictTo(LIBRARY)
@NonNull
public static SliceAction createTimePicker(@NonNull PendingIntent action,
@NonNull CharSequence actionTitle, long dateTimeMillis) {
@@ -465,7 +457,6 @@
* @param builder this should be a new builder that has any additional hints the action might
* need.
* @return the slice representation of this action.
- * @hide
*/
@RestrictTo(LIBRARY)
@NonNull
@@ -474,7 +465,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@NonNull
@@ -484,7 +474,6 @@
/**
* @param builder the parent slice builder that contains the primary action.
- * @hide
*/
@RestrictTo(LIBRARY)
public void setPrimaryAction(@NonNull Slice.Builder builder) {
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/TemplateSliceBuilder.java b/slice/slice-builders/src/main/java/androidx/slice/builders/TemplateSliceBuilder.java
index 12d7b07..07accb6 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/TemplateSliceBuilder.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/TemplateSliceBuilder.java
@@ -51,7 +51,6 @@
private List<SliceSpec> mSpecs;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
protected TemplateSliceBuilder(TemplateBuilderImpl impl) {
@@ -62,7 +61,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public TemplateSliceBuilder(Context context, Uri uri) {
@@ -85,7 +83,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
protected Slice.Builder getBuilder() {
@@ -93,13 +90,11 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
abstract void setImpl(TemplateBuilderImpl impl);
/**
- * @hide
*/
@RestrictTo(LIBRARY)
protected TemplateBuilderImpl selectImpl() {
@@ -107,7 +102,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
protected boolean checkCompatible(SliceSpec candidate) {
@@ -129,7 +123,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
protected Clock getClock() {
@@ -141,7 +134,6 @@
/**
* This is for typing, to clean up the code.
- * @hide
*/
@RestrictTo(LIBRARY)
@SuppressWarnings("unchecked")
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderListV1Impl.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderListV1Impl.java
index 184cd4e..ec399bc 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderListV1Impl.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderListV1Impl.java
@@ -42,7 +42,6 @@
import java.util.List;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(19)
@@ -229,7 +228,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@Override
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
index de5bf68..8718ac9 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
@@ -39,7 +39,6 @@
import java.util.Set;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
index c137500..faf5588 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
@@ -57,7 +57,6 @@
import java.util.Set;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java
index 1c34c39..111bd0b 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java
@@ -82,7 +82,6 @@
import java.util.Set;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingBasicImpl.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingBasicImpl.java
index cb5d540..239e6fb 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingBasicImpl.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingBasicImpl.java
@@ -34,7 +34,6 @@
import androidx.slice.SliceSpec;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingBuilder.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingBuilder.java
index 4285eae..03f48ce 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingBuilder.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingBuilder.java
@@ -24,7 +24,6 @@
import androidx.annotation.RestrictTo;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingListV1Impl.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingListV1Impl.java
index 93f5989..8dacf8f 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingListV1Impl.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingListV1Impl.java
@@ -30,7 +30,6 @@
import androidx.slice.SliceSpec;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingV1Impl.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingV1Impl.java
index 25cfecb..d913d79 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingV1Impl.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/MessagingV1Impl.java
@@ -28,7 +28,6 @@
import androidx.slice.SliceSpec;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderBasicImpl.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderBasicImpl.java
index 1def00e..1c341f1 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderBasicImpl.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderBasicImpl.java
@@ -30,7 +30,6 @@
import androidx.slice.builders.SelectionBuilder;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderImpl.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderImpl.java
index 5143668..f25d0a6 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderImpl.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderImpl.java
@@ -25,7 +25,6 @@
import androidx.slice.builders.SelectionBuilder;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderListV2Impl.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderListV2Impl.java
index af4d92e..0c25ad0 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderListV2Impl.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/SelectionBuilderListV2Impl.java
@@ -38,7 +38,6 @@
import java.util.List;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/TemplateBuilderImpl.java b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/TemplateBuilderImpl.java
index 9a377d2..8cb26f66 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/impl/TemplateBuilderImpl.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/impl/TemplateBuilderImpl.java
@@ -40,7 +40,6 @@
import java.util.ArrayList;
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@RequiresApi(19)
@@ -74,7 +73,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public Slice.Builder getBuilder() {
@@ -82,7 +80,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public Slice.Builder createChildBuilder() {
@@ -90,13 +87,11 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public abstract void apply(@NonNull Slice.Builder builder);
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public Clock getClock() {
@@ -104,7 +99,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public SliceSpec getSpec() {
@@ -112,7 +106,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@NonNull
diff --git a/slice/slice-core/lint-baseline.xml b/slice/slice-core/lint-baseline.xml
index 528ca08..f6b771e 100644
--- a/slice/slice-core/lint-baseline.xml
+++ b/slice/slice-core/lint-baseline.xml
@@ -1,680 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class ArrayUtils {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/ArrayUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public interface Clock {"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/slice/Clock.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class CompatPermissionManager {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/compat/CompatPermissionManager.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class CompatPinnedList {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/compat/CompatPinnedList.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class CornerDrawable extends InsetDrawable {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/CornerDrawable.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final String SUBTYPE_RANGE_MODE = "range_mode";"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @interface SliceHint { }"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" Slice(ArrayList<SliceItem> items, @SliceHint String[] hints, Uri uri,"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Slice() {"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Slice(@NonNull Bundle in) {"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @NonNull Bundle toBundle() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @Nullable SliceSpec getSpec() {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @NonNull SliceItem[] getItemArray() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @NonNull @SliceHint String[] getHintArray() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean hasHint(@NonNull @SliceHint String hint) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void onPreParceling(boolean isStream) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void onPostParceling() {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static class Builder {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @NonNull Builder setSpec(@Nullable SliceSpec spec) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @NonNull Builder addRemoteInput(@NonNull RemoteInput remoteInput,"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @NonNull Builder addRemoteInput(@NonNull RemoteInput remoteInput,"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @NonNull Builder addItem(@NonNull SliceItem item) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public String toString(@NonNull String indent) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static void appendHints(@NonNull StringBuilder sb, @Nullable String[] hints) {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static Slice bindSlice(@NonNull Context context, @NonNull Uri uri,"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" static boolean isValidIcon(IconCompat icon) {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/Slice.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SliceActionImpl implements SliceAction {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/core/SliceActionImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceActionImpl(@NonNull PendingIntent action, @NonNull CharSequence actionTitle,"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/core/SliceActionImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceActionImpl(@NonNull SliceItem slice) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/core/SliceActionImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceItem getActionItem() {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/core/SliceActionImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static int parseImageMode(@NonNull SliceItem iconItem) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/core/SliceActionImpl.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static Set<androidx.slice.SliceSpec> wrap("
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/slice/SliceConvert.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SliceHints {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/core/SliceHints.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @interface SliceType {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" @Slice.SliceHint String[] mHints = Slice.NO_HINTS;"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceItem(Object obj, @NonNull @SliceType String format, @Nullable String subType,"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceItem(Object obj, @NonNull @SliceType String format, @Nullable String subType,"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceItem() {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceItem(@NonNull PendingIntent intent, @Nullable Slice slice,"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceItem(@NonNull ActionHandler action, @Nullable Slice slice,"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @NonNull @Slice.SliceHint String[] getHintArray() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void addHint(@Slice.SliceHint @NonNull String hint) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getSanitizedText() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean fireActionInternal(@Nullable Context context, @Nullable Intent i)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public RemoteInput getRemoteInput() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceItem(@NonNull Bundle in) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Bundle toBundle() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean hasHints(@Nullable @Slice.SliceHint String[] hints) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean hasAnyHints(@Nullable @Slice.SliceHint String... hints) {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static String typeToString(@NonNull String format) {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public String toString(@NonNull String indent) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public interface ActionHandler {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItem.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SliceItemHolder implements VersionedParcelable {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceItemHolder.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" SliceManager() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceManager.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public abstract @NonNull Set<SliceSpec> getPinnedSpecs(@NonNull Uri uri);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceManager.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class SliceManagerCompat extends SliceManager {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceManagerCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class SliceManagerWrapper extends SliceManager {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceManagerWrapper.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SlicePermissionActivity extends AppCompatActivity implements OnClickListener,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/compat/SlicePermissionActivity.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Object getWrapper() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected CompatPermissionManager onCreatePermissionManager("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Slice createPermissionSlice(@NonNull Uri sliceUri,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void handleSlicePinned(@NonNull Uri sliceUri) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void handleSliceUnpinned(@NonNull Uri sliceUri) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void validateIncomingAuthority(@Nullable String authority) throws SecurityException {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static void setSpecs(@Nullable Set<SliceSpec> specs) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static Set<SliceSpec> getCurrentSpecs() {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static void setClock(@Nullable Clock clock) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static Clock getClock() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceProvider.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SliceProviderCompat {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/compat/SliceProviderCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SliceProviderWrapperContainer {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/compat/SliceProviderWrapperContainer.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SliceQuery {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/core/SliceQuery.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public final class SliceSpec implements VersionedParcelable {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceSpec.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceSpec() {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceSpec.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SliceSpecs {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceSpecs.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SystemClock implements Clock {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SystemClock.java"/>
- </issue>
+<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">
<issue
id="BanUncheckedReflection"
diff --git a/slice/slice-core/src/main/java/androidx/slice/ArrayUtils.java b/slice/slice-core/src/main/java/androidx/slice/ArrayUtils.java
index a020ad3..e5dd970 100644
--- a/slice/slice-core/src/main/java/androidx/slice/ArrayUtils.java
+++ b/slice/slice-core/src/main/java/androidx/slice/ArrayUtils.java
@@ -24,7 +24,6 @@
import java.lang.reflect.Array;
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@RequiresApi(19)
diff --git a/slice/slice-core/src/main/java/androidx/slice/Clock.java b/slice/slice-core/src/main/java/androidx/slice/Clock.java
index a1b758e..f68560c 100644
--- a/slice/slice-core/src/main/java/androidx/slice/Clock.java
+++ b/slice/slice-core/src/main/java/androidx/slice/Clock.java
@@ -22,7 +22,6 @@
import androidx.annotation.RestrictTo;
/**
- * @hide
*/
@RestrictTo(LIBRARY_GROUP_PREFIX)
@RequiresApi(19)
diff --git a/slice/slice-core/src/main/java/androidx/slice/CornerDrawable.java b/slice/slice-core/src/main/java/androidx/slice/CornerDrawable.java
index 5afbe40..9ccb915 100644
--- a/slice/slice-core/src/main/java/androidx/slice/CornerDrawable.java
+++ b/slice/slice-core/src/main/java/androidx/slice/CornerDrawable.java
@@ -30,7 +30,6 @@
* A wrapper for Drawables that uses a path to add mask for corners around the drawable,
* to match the radius of the underlying shape.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class CornerDrawable extends InsetDrawable {
diff --git a/slice/slice-core/src/main/java/androidx/slice/Slice.java b/slice/slice-core/src/main/java/androidx/slice/Slice.java
index d7cf29b..8044c1e 100644
--- a/slice/slice-core/src/main/java/androidx/slice/Slice.java
+++ b/slice/slice-core/src/main/java/androidx/slice/Slice.java
@@ -51,7 +51,6 @@
import static androidx.slice.core.SliceHints.HINT_SELECTION_OPTION;
import static androidx.slice.core.SliceHints.HINT_SHOW_LABEL;
-import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.app.slice.SliceManager;
@@ -105,7 +104,6 @@
* Subtype to tag an item as representing the progress bar mode for a
* {@link android.app.slice.Slice#SUBTYPE_RANGE}
*
- * @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public static final String SUBTYPE_RANGE_MODE = "range_mode";
@@ -120,7 +118,6 @@
static final SliceItem[] NO_ITEMS = new SliceItem[0];
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
@StringDef({
@@ -164,7 +161,6 @@
String mUri = null;
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
Slice(ArrayList<SliceItem> items, @SliceHint String[] hints, Uri uri,
@@ -177,14 +173,12 @@
/**
* Used for VersionedParcelable
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public Slice() {
}
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
@SuppressWarnings("deprecation")
@@ -204,7 +198,6 @@
}
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public @NonNull Bundle toBundle() {
@@ -225,7 +218,6 @@
/**
* @return The spec for this slice
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public @Nullable SliceSpec getSpec() {
@@ -247,7 +239,6 @@
}
/**
- * @hide
* @return
*/
@RestrictTo(LIBRARY)
@@ -263,7 +254,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public @NonNull @SliceHint String[] getHintArray() {
@@ -271,7 +261,6 @@
}
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
public boolean hasHint(@NonNull @SliceHint String hint) {
@@ -279,7 +268,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@Override
@@ -287,7 +275,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@Override
@@ -304,7 +291,6 @@
/**
* A Builder used to construct {@link Slice}s
- * @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
public static class Builder {
@@ -339,7 +325,6 @@
/**
* Add the spec for this slice.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public @NonNull Builder setSpec(@Nullable SliceSpec spec) {
@@ -462,7 +447,6 @@
* Add remote input to the slice being constructed
* @param subType Optional template-specific type information
* @see SliceItem#getSubType()
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public @NonNull Builder addRemoteInput(@NonNull RemoteInput remoteInput,
@@ -475,7 +459,6 @@
* Add remote input to the slice being constructed
* @param subType Optional template-specific type information
* @see SliceItem#getSubType()
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public @NonNull Builder addRemoteInput(@NonNull RemoteInput remoteInput,
@@ -553,7 +536,6 @@
/**
* Add a SliceItem to the slice being constructed.
- * @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public @NonNull Builder addItem(@NonNull SliceItem item) {
@@ -580,7 +562,6 @@
/**
* @return A string representation of this slice.
- * @hide
*/
@NonNull
@RestrictTo(Scope.LIBRARY)
@@ -606,7 +587,6 @@
}
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public static void appendHints(@NonNull StringBuilder sb, @Nullable String[] hints) {
@@ -628,7 +608,6 @@
* @param context Context to be used.
* @param uri The URI to a slice provider
* @return The Slice provided by the app or null if none is given.
- * @hide
* @see Slice
*/
@RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
@@ -651,7 +630,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
static boolean isValidIcon(IconCompat icon) {
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceConvert.java b/slice/slice-core/src/main/java/androidx/slice/SliceConvert.java
index 71e9c23..3711e65 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceConvert.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceConvert.java
@@ -169,7 +169,6 @@
}
/**
- * @hide
*/
@NonNull
@RestrictTo(RestrictTo.Scope.LIBRARY)
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceItem.java b/slice/slice-core/src/main/java/androidx/slice/SliceItem.java
index f9e12a3..c35fdef 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceItem.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceItem.java
@@ -100,7 +100,6 @@
private static final String SLICE_CONTENT_SENSITIVE = "sensitive";
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
@StringDef({FORMAT_SLICE, FORMAT_TEXT, FORMAT_IMAGE, FORMAT_ACTION, FORMAT_INT,
@@ -110,7 +109,6 @@
}
/**
- * @hide
*/
@NonNull
@RestrictTo(Scope.LIBRARY)
@@ -137,7 +135,6 @@
SliceItemHolder mHolder;
/**
- * @hide
*/
@SuppressWarnings("NullableProblems")
@SuppressLint("UnknownNullness") // obj cannot be correctly annotated
@@ -151,7 +148,6 @@
}
/**
- * @hide
*/
@SuppressLint("UnknownNullness") // obj cannot be correctly annotated
@RestrictTo(Scope.LIBRARY_GROUP)
@@ -162,14 +158,12 @@
/**
* Used by VersionedParcelable.
- * @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public SliceItem() {
}
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public SliceItem(@NonNull PendingIntent intent, @Nullable Slice slice,
@@ -179,7 +173,6 @@
}
/**
- * @hide
*/
@SuppressLint("LambdaLast")
@RestrictTo(Scope.LIBRARY_GROUP)
@@ -199,7 +192,6 @@
}
/**
- * @hide
*/
@SuppressWarnings("unused")
@RestrictTo(Scope.LIBRARY)
@@ -208,7 +200,6 @@
}
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public void addHint(@Slice.SliceHint @NonNull String hint) {
@@ -258,7 +249,6 @@
}
/**
- * @hide
* @return The text held by this {@link android.app.slice.SliceItem#FORMAT_TEXT} SliceItem with
* ony spans that are unsupported by the androidx Slice renderer removed.
*/
@@ -314,7 +304,6 @@
}
/**
- * @hide
*/
@SuppressWarnings("unchecked")
@RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
@@ -334,7 +323,6 @@
/**
* @return The remote input held by this {@link android.app.slice.SliceItem#FORMAT_REMOTE_INPUT}
* SliceItem
- * @hide
*/
@Nullable
@RequiresApi(20)
@@ -383,7 +371,6 @@
}
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY)
public SliceItem(@NonNull Bundle in) {
@@ -394,7 +381,6 @@
}
/**
- * @hide
*/
@NonNull
@RestrictTo(Scope.LIBRARY)
@@ -408,7 +394,6 @@
}
/**
- * @hide
*/
@SuppressWarnings("unused")
@RestrictTo(Scope.LIBRARY)
@@ -423,7 +408,6 @@
}
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public boolean hasAnyHints(@Nullable @Slice.SliceHint String... hints) {
@@ -494,7 +478,6 @@
}
/**
- * @hide
*/
@NonNull
@RestrictTo(Scope.LIBRARY)
@@ -529,7 +512,6 @@
/**
* @return A string representation of this slice item.
- * @hide
*/
@NonNull
@RestrictTo(Scope.LIBRARY)
@@ -754,7 +736,6 @@
}
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
public interface ActionHandler {
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceItemHolder.java b/slice/slice-core/src/main/java/androidx/slice/SliceItemHolder.java
index 1cdd23398..ab2ebba 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceItemHolder.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceItemHolder.java
@@ -45,7 +45,6 @@
import java.util.ArrayList;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@VersionedParcelize(allowSerialization = true, ignoreParcelables = true,
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceManager.java b/slice/slice-core/src/main/java/androidx/slice/SliceManager.java
index e0baa5e..390f09a 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceManager.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceManager.java
@@ -49,7 +49,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
SliceManager() {
@@ -62,7 +61,6 @@
* into account all clients and returns only specs supported by all.
* @see SliceSpec
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public abstract @NonNull Set<SliceSpec> getPinnedSpecs(@NonNull Uri uri);
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceManagerCompat.java b/slice/slice-core/src/main/java/androidx/slice/SliceManagerCompat.java
index 7399d29..549d939 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceManagerCompat.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceManagerCompat.java
@@ -29,7 +29,6 @@
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceManagerWrapper.java b/slice/slice-core/src/main/java/androidx/slice/SliceManagerWrapper.java
index 349dc92..d1bd08e 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceManagerWrapper.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceManagerWrapper.java
@@ -33,7 +33,6 @@
import java.util.Set;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(api = 28)
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceProvider.java b/slice/slice-core/src/main/java/androidx/slice/SliceProvider.java
index 8a72034..9cd8ddc 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceProvider.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceProvider.java
@@ -191,7 +191,6 @@
public abstract boolean onCreateSliceProvider();
/**
- * @hide
*/
@Nullable
@RestrictTo(RestrictTo.Scope.LIBRARY)
@@ -224,7 +223,6 @@
}
/**
- * @hide
* @param autoGrantPermissions
*/
@NonNull
@@ -326,7 +324,6 @@
/**
* Generate a slice that contains a permission request.
- * @hide
*/
@NonNull
@RestrictTo(RestrictTo.Scope.LIBRARY)
@@ -448,7 +445,6 @@
public void onSliceUnpinned(@NonNull Uri sliceUri) {}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
@@ -460,7 +456,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
@@ -520,7 +515,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void validateIncomingAuthority(@Nullable String authority) throws SecurityException {
@@ -603,7 +597,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
@@ -612,7 +605,6 @@
}
/**
- * @hide
*/
@Nullable
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@@ -622,7 +614,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
@@ -631,7 +622,6 @@
}
/**
- * @hide
*/
@Nullable
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceSpec.java b/slice/slice-core/src/main/java/androidx/slice/SliceSpec.java
index c0aaebe..13bacd9 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceSpec.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceSpec.java
@@ -39,7 +39,6 @@
* {@link SliceSpec} that one of the supported {@link SliceSpec}s provided
* {@link #canRender}.
*
- * @hide
* @see Slice
* @see SliceProvider#onBindSlice(Uri)
*/
@@ -55,7 +54,6 @@
/**
* Used for VersionedParcelable
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public SliceSpec() {
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceSpecs.java b/slice/slice-core/src/main/java/androidx/slice/SliceSpecs.java
index 0374db9..436d24b 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceSpecs.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceSpecs.java
@@ -21,7 +21,6 @@
/**
* Constants for each of the slice specs
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@RequiresApi(19)
diff --git a/slice/slice-core/src/main/java/androidx/slice/SystemClock.java b/slice/slice-core/src/main/java/androidx/slice/SystemClock.java
index 4b740f3..888d3e4 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SystemClock.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SystemClock.java
@@ -22,7 +22,6 @@
import androidx.annotation.RestrictTo;
/**
- * @hide
*/
@RestrictTo(LIBRARY_GROUP_PREFIX)
@RequiresApi(19)
diff --git a/slice/slice-core/src/main/java/androidx/slice/compat/CompatPermissionManager.java b/slice/slice-core/src/main/java/androidx/slice/compat/CompatPermissionManager.java
index 52259f6..dc700dd 100644
--- a/slice/slice-core/src/main/java/androidx/slice/compat/CompatPermissionManager.java
+++ b/slice/slice-core/src/main/java/androidx/slice/compat/CompatPermissionManager.java
@@ -37,7 +37,6 @@
import java.util.Set;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresApi(19)
diff --git a/slice/slice-core/src/main/java/androidx/slice/compat/CompatPinnedList.java b/slice/slice-core/src/main/java/androidx/slice/compat/CompatPinnedList.java
index 876ec00..f9de140 100644
--- a/slice/slice-core/src/main/java/androidx/slice/compat/CompatPinnedList.java
+++ b/slice/slice-core/src/main/java/androidx/slice/compat/CompatPinnedList.java
@@ -38,7 +38,6 @@
/**
* Tracks the current packages requesting pinning of any given slice. It will clear the
* list after a reboot since the packages are no longer requesting pinning.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java b/slice/slice-core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java
index af0d22d..9d704cc 100644
--- a/slice/slice-core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java
+++ b/slice/slice-core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java
@@ -40,7 +40,6 @@
/**
* Dialog that grants slice permissions for an app.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderCompat.java b/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
index f2ba233..a03e977 100644
--- a/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
+++ b/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
@@ -64,7 +64,6 @@
import java.util.Set;
/**
- * @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@RequiresApi(19)
diff --git a/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderWrapperContainer.java b/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderWrapperContainer.java
index c4e6120..b24671f 100644
--- a/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderWrapperContainer.java
+++ b/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderWrapperContainer.java
@@ -41,7 +41,6 @@
import java.util.Set;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public class SliceProviderWrapperContainer {
diff --git a/slice/slice-core/src/main/java/androidx/slice/core/SliceActionImpl.java b/slice/slice-core/src/main/java/androidx/slice/core/SliceActionImpl.java
index e46617b..503cdbf 100644
--- a/slice/slice-core/src/main/java/androidx/slice/core/SliceActionImpl.java
+++ b/slice/slice-core/src/main/java/androidx/slice/core/SliceActionImpl.java
@@ -31,6 +31,7 @@
import static android.app.slice.SliceItem.FORMAT_LONG;
import static android.app.slice.SliceItem.FORMAT_TEXT;
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
import static androidx.slice.core.SliceHints.ACTION_WITH_LABEL;
@@ -60,7 +61,6 @@
/**
* Class representing an action, supports tappable icons, custom toggle icons, and default toggles.
- * @hide
*/
@RestrictTo(LIBRARY_GROUP_PREFIX)
@RequiresApi(19)
@@ -119,8 +119,8 @@
* @param actionTitle the timestamp title for this picker.
* @param dateTimeMillis the default state of the date or time picker.
* @param isDatePicker if it is a date picker, as opposed to a time picker.
- * @hide
*/
+ @RestrictTo(LIBRARY)
public SliceActionImpl(@NonNull PendingIntent action, @NonNull CharSequence actionTitle,
long dateTimeMillis, boolean isDatePicker) {
mAction = action;
@@ -194,7 +194,6 @@
*
* @param slice the slice item to construct the action out of.
*
- * @hide
*/
@RestrictTo(LIBRARY_GROUP)
@SuppressLint("InlinedApi")
@@ -314,7 +313,6 @@
}
/**
- * @hide
*/
@Nullable
@RestrictTo(LIBRARY_GROUP_PREFIX)
@@ -498,7 +496,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY_GROUP_PREFIX)
public static int parseImageMode(@NonNull SliceItem iconItem) {
diff --git a/slice/slice-core/src/main/java/androidx/slice/core/SliceHints.java b/slice/slice-core/src/main/java/androidx/slice/core/SliceHints.java
index 85d312a..e08441b 100644
--- a/slice/slice-core/src/main/java/androidx/slice/core/SliceHints.java
+++ b/slice/slice-core/src/main/java/androidx/slice/core/SliceHints.java
@@ -28,7 +28,6 @@
/**
* Temporary class to contain hint constants for slices to be used.
- * @hide
*/
@RestrictTo(LIBRARY_GROUP_PREFIX)
@RequiresApi(19)
diff --git a/slice/slice-core/src/main/java/androidx/slice/core/SliceQuery.java b/slice/slice-core/src/main/java/androidx/slice/core/SliceQuery.java
index 684de91..3111e1b 100644
--- a/slice/slice-core/src/main/java/androidx/slice/core/SliceQuery.java
+++ b/slice/slice-core/src/main/java/androidx/slice/core/SliceQuery.java
@@ -37,7 +37,6 @@
/**
* Utilities for finding content within a Slice.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@RequiresApi(19)
diff --git a/slice/slice-remotecallback/lint-baseline.xml b/slice/slice-remotecallback/lint-baseline.xml
deleted file mode 100644
index 5f18321..0000000
--- a/slice/slice-remotecallback/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public RemoteCallback toRemoteCallback(@NonNull Class<T> cls, @NonNull Context context,"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/remotecallback/RemoteSliceProvider.java"/>
- </issue>
-
-</issues>
diff --git a/slice/slice-remotecallback/src/main/java/androidx/slice/remotecallback/RemoteSliceProvider.java b/slice/slice-remotecallback/src/main/java/androidx/slice/remotecallback/RemoteSliceProvider.java
index c8ca571..be81d93 100644
--- a/slice/slice-remotecallback/src/main/java/androidx/slice/remotecallback/RemoteSliceProvider.java
+++ b/slice/slice-remotecallback/src/main/java/androidx/slice/remotecallback/RemoteSliceProvider.java
@@ -77,7 +77,6 @@
/**
* Note: Only visible because metalava doesn't realize this is hidden. Will properly
* disappear when we have support for androidx-level @RestrictTo.
- * @hide
*/
@NonNull
@Override
diff --git a/slice/slice-test/lint-baseline.xml b/slice/slice-test/lint-baseline.xml
index 59a7e74..9003689 100644
--- a/slice/slice-test/lint-baseline.xml
+++ b/slice/slice-test/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-alpha05)" variant="all" version="8.0.0-alpha05">
+<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">
<issue
id="UnspecifiedImmutableFlag"
diff --git a/slice/slice-view/api/current.txt b/slice/slice-view/api/current.txt
index 9ba9a2f..91918d9 100644
--- a/slice/slice-view/api/current.txt
+++ b/slice/slice-view/api/current.txt
@@ -152,8 +152,8 @@
method public androidx.slice.widget.GridRowView getGridRowView();
method public int getItemCount();
method public androidx.slice.widget.RowView getRowView();
- method public void onBindViewHolder(androidx.slice.widget.SliceAdapter.SliceViewHolder, int);
- method public androidx.slice.widget.SliceAdapter.SliceViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public void onBindViewHolder(androidx.slice.widget.SliceAdapter.SliceViewHolder, int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public androidx.slice.widget.SliceAdapter.SliceViewHolder onCreateViewHolder(android.view.ViewGroup, int);
}
@RequiresApi(19) public abstract class SliceChildView extends android.widget.FrameLayout {
diff --git a/slice/slice-view/api/restricted_current.txt b/slice/slice-view/api/restricted_current.txt
index f46664b..9f3c43a 100644
--- a/slice/slice-view/api/restricted_current.txt
+++ b/slice/slice-view/api/restricted_current.txt
@@ -210,8 +210,8 @@
method public androidx.slice.widget.GridRowView getGridRowView();
method public int getItemCount();
method public androidx.slice.widget.RowView getRowView();
- method public void onBindViewHolder(androidx.slice.widget.SliceAdapter.SliceViewHolder, int);
- method public androidx.slice.widget.SliceAdapter.SliceViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public void onBindViewHolder(androidx.slice.widget.SliceAdapter.SliceViewHolder, int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public androidx.slice.widget.SliceAdapter.SliceViewHolder onCreateViewHolder(android.view.ViewGroup, int);
}
@RequiresApi(19) public abstract class SliceChildView extends android.widget.FrameLayout {
diff --git a/slice/slice-view/lint-baseline.xml b/slice/slice-view/lint-baseline.xml
index d002e99..d89abc3 100644
--- a/slice/slice-view/lint-baseline.xml
+++ b/slice/slice-view/lint-baseline.xml
@@ -1,1661 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class ActionRow extends FrameLayout {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/ActionRow.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class DisplayedListItems {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/DisplayedListItems.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @interface SliceRowType {}"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/EventInfo.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int ROW_TYPE_DATE_PICK = 7;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/EventInfo.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int ROW_TYPE_TIME_PICK = 8;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/EventInfo.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @interface SliceActionType{}"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/EventInfo.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int ACTION_TYPE_DATE_PICK = 6;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/EventInfo.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final int ACTION_TYPE_TIME_PICK = 7;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/EventInfo.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @interface SliceButtonPosition {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/EventInfo.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public GridContent(@NonNull SliceItem gridItem, int position) {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getTitle() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public ArrayList<CellContent> getGridContent() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceItem getContentIntent() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceItem getSeeMoreItem() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isAllImages() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getLargestImageMode() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getMaxCellLineCount() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean hasImage() {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean getIsLastIndex() { return mIsLastIndex; }"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setIsLastIndex(boolean isLast) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getHeight(@NonNull SliceStyle style, @NonNull SliceViewPolicy policy) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static class CellContent {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected final View mForeground;"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected int mRowIndex;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected int mRowCount;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected int mMaxCells = -1;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected @Nullable GridContent mGridContent;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected final int mLargeImageHeight;"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected final int mSmallImageSize;"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected final int mSmallImageMinWidth;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected final int mIconSize;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected final LinearLayout mViewContainer;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setInsets(int l, int t, int r, int b) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setTint(@ColorInt int tintColor) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void onClick(@NonNull View view) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean onTouch(@NonNull View view, @NonNull MotionEvent event) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getHiddenItemCount() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/GridRowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class ListContent extends SliceContent {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/ListContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class LocationBasedViewTracker implements Runnable, View.OnLayoutChangeListener {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/LocationBasedViewTracker.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static void trackInputFocused(ViewGroup parent) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/LocationBasedViewTracker.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static void trackA11yFocus(ViewGroup parent) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/LocationBasedViewTracker.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class MessageView extends SliceChildView {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/MessageView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class RemoteInputView extends LinearLayout implements View.OnClickListener, TextWatcher {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RemoteInputView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setRevealParameters(int cx, int cy, int r) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RemoteInputView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final boolean isConfirmKey(int keyCode) {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RemoteInputView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class RowContent extends SliceContent {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getHeight(SliceStyle style, SliceViewPolicy policy) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class RowStyle {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowStyle.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected Set<SliceItem> mLoadingActions = new HashSet<>();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setStyle(SliceStyle styles, RowStyle rowStyle) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setInsets(int l, int t, int r, int b) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setTint(@ColorInt int tintColor) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setSliceActions(List<SliceAction> actions) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setShowLastUpdated(boolean showLastUpdated) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setAllowTwoLines(boolean allowTwoLines) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setLastUpdated(long lastUpdated) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setLoadingActions(Set<SliceItem> actions) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void resetView() {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/RowView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class ShortcutView extends SliceChildView {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/ShortcutView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SliceActionView extends FrameLayout implements View.OnClickListener,"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceActionView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setParents(SliceView parent, TemplateView templateView) {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setInsets(int l, int t, int r, int b) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setSliceObserver(SliceView.OnSliceActionListener observer) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setSliceActions(List<SliceAction> actions) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setSliceItems(List<SliceContent> slices, int color, int mode) {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setStyle(SliceStyle style) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setPolicy(SliceViewPolicy p) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setShowLastUpdated(boolean showLastUpdated) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setLastUpdated(long lastUpdated) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setLoadingActions(Set<SliceItem> actions) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Set<SliceItem> getLoadingActions() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void onSliceActionLoading(SliceItem actionItem, int position) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setAllowTwoLines(boolean allowTwoLines) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void notifyHeaderChanged() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void onBindViewHolder(@NonNull SliceViewHolder holder, int position) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected static class SliceWrapper {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public class SliceViewHolder extends RecyclerView.ViewHolder implements View.OnTouchListener,"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceAdapter.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected SliceView.OnSliceActionListener mObserver;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected int mMode;"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected int mTintColor = -1;"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected boolean mShowLastUpdated;"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected long mLastUpdated = -1;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected int mInsetStart;"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected int mInsetTop;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected int mInsetEnd;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected int mInsetBottom;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected SliceActionView.SliceActionLoadingListener mLoadingListener;"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected SliceStyle mSliceStyle;"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected RowStyle mRowStyle;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected SliceViewPolicy mViewPolicy;"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setSliceContent(ListContent content) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setInsets(int l, int t, int r, int b) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setSliceActions(List<SliceAction> actions) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getMode() {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setTint(@ColorInt int tintColor) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setShowLastUpdated(boolean showLastUpdated) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setLastUpdated(long lastUpdated) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setSliceActionListener(SliceView.OnSliceActionListener observer) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setSliceActionLoadingListener(SliceActionView.SliceActionLoadingListener listener) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setActionLoading(SliceItem item) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setLoadingActions(Set<SliceItem> loadingActions) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setAllowTwoLines(boolean allowTwoLines) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Set<SliceItem> getLoadingActions() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setStyle(SliceStyle styles, @NonNull RowStyle rowStyle) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setPolicy(@Nullable SliceViewPolicy policy) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getHiddenItemCount() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceChildView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected SliceItem mSliceItem;"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected SliceItem mColorItem;"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected SliceItem mLayoutDirItem;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected SliceItem mContentDescr;"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected int mRowIndex;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceContent(@Nullable SliceItem item, int rowIndex) {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceItem getSliceItem() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getAccentColor() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getLayoutDir() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public CharSequence getContentDescription() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getRowIndex() { return mRowIndex; }"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getHeight(SliceStyle style, SliceViewPolicy policy) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isValid() {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceAction getShortcut(@Nullable Context context) {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceContent.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final SliceSpec OLD_BASIC = new SliceSpec("androidx.app.slice.BASIC", 1);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceLiveData.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final SliceSpec OLD_LIST = new SliceSpec("androidx.app.slice.LIST", 1);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceLiveData.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final Set<SliceSpec> SUPPORTED_SPECS = new ArraySet<>("
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceLiveData.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static CachedSliceLiveData fromStream(@NonNull Context context,"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceLiveData.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected synchronized void loadInitialSlice() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceLiveData.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" protected void updateSlice() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceLiveData.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @interface SliceLoadingState{}"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceMetadata.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static List<SliceAction> getSliceActions(@NonNull Slice slice) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceMetadata.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isExpired() {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceMetadata.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean neverExpires() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceMetadata.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public long getTimeToExpiry() {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceMetadata.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public ListContent getListContent() {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceMetadata.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class SliceMetrics {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceMetrics.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class SliceMetricsWrapper extends SliceMetrics {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceMetricsWrapper.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceStructure(SliceItem s) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceStructure.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Uri getUri() {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceStructure.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SliceStyle {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceStyle.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static IconCompat convert(Context context, IconCompat icon, SerializeOptions options) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static int parseImageMode(@NonNull SliceItem iconItem) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void checkThrow(String format) {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @FormatMode int getActionMode() {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @FormatMode int getImageMode() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getMaxWidth() {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getMaxHeight() {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Bitmap.CompressFormat getFormat() {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getQuality() {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceParseException(String s, Throwable e) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public SliceParseException(String s) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceUtils.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public @interface SliceMode {}"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isSliceViewClickable() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setClickInfo(int[] info) {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setMode(@SliceMode int mode, boolean animate) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setShowActionRow(boolean show) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean isShowingActionRow() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static String modeToString(@SliceMode int mode) {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public static final Comparator<SliceAction> SLICE_ACTION_PRIORITY_COMPARATOR ="
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" SliceViewManager() {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceViewManager.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public abstract class SliceViewManagerBase extends SliceViewManager {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceViewManagerBase.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class SliceViewManagerCompat extends SliceViewManagerBase {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceViewManagerCompat.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class SliceViewManagerWrapper extends SliceViewManagerBase {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceViewManagerWrapper.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SliceViewPolicy {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceViewPolicy.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="public class SliceViewUtil {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/SliceViewUtil.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class SliceXml {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/SliceXml.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setInsets(int l, int t, int r, int b) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void onForegroundActivated(MotionEvent event) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setPolicy(SliceViewPolicy policy) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setActionLoading(SliceItem item) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setLoadingActions(Set<SliceItem> loadingActions) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public Set<SliceItem> getLoadingActions() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setTint(int tint) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setSliceActionListener(SliceView.OnSliceActionListener observer) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setSliceActions(List<SliceAction> actions) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setSliceContent(ListContent sliceContent) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setStyle(SliceStyle style, @NonNull RowStyle rowStyle) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setShowLastUpdated(boolean showLastUpdated) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setLastUpdated(long lastUpdated) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void setAllowTwoLines(boolean allowTwoLines) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void resetView() {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void onScrollingChanged(boolean newScrolling) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void onMaxHeightChanged(int newNewHeight) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void onMaxSmallChanged(int newMaxSmallHeight) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void onModeChanged(int newMode) {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public int getHiddenItemCount() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/slice/widget/TemplateView.java"/>
- </issue>
+<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">
<issue
id="BanSynchronizedMethods"
diff --git a/slice/slice-view/src/main/java/androidx/slice/SliceMetadata.java b/slice/slice-view/src/main/java/androidx/slice/SliceMetadata.java
index 545fe54..edbc303 100644
--- a/slice/slice-view/src/main/java/androidx/slice/SliceMetadata.java
+++ b/slice/slice-view/src/main/java/androidx/slice/SliceMetadata.java
@@ -76,7 +76,6 @@
public class SliceMetadata {
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
@@ -468,7 +467,6 @@
/**
* @return the group of slice actions associated with the provided slice, if they exist.
- * @hide
*/
@Nullable
@RestrictTo(RestrictTo.Scope.LIBRARY)
@@ -490,7 +488,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public boolean isExpired() {
@@ -499,7 +496,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public boolean neverExpires() {
@@ -507,7 +503,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public long getTimeToExpiry() {
@@ -517,7 +512,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public ListContent getListContent() {
diff --git a/slice/slice-view/src/main/java/androidx/slice/SliceStructure.java b/slice/slice-view/src/main/java/androidx/slice/SliceStructure.java
index d73d691..f4f1f27 100644
--- a/slice/slice-view/src/main/java/androidx/slice/SliceStructure.java
+++ b/slice/slice-view/src/main/java/androidx/slice/SliceStructure.java
@@ -56,7 +56,6 @@
/**
* Create a SliceStructure.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public SliceStructure(SliceItem s) {
@@ -72,7 +71,6 @@
/**
* @return the Uri associated with this content item if one exists.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Nullable
diff --git a/slice/slice-view/src/main/java/androidx/slice/SliceUtils.java b/slice/slice-view/src/main/java/androidx/slice/SliceUtils.java
index cf42a848..46f1d35 100644
--- a/slice/slice-view/src/main/java/androidx/slice/SliceUtils.java
+++ b/slice/slice-view/src/main/java/androidx/slice/SliceUtils.java
@@ -236,7 +236,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public static IconCompat convert(Context context, IconCompat icon, SerializeOptions options) {
@@ -314,7 +313,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public static int parseImageMode(@NonNull SliceItem iconItem) {
@@ -375,7 +373,6 @@
private int mQuality = 100;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void checkThrow(String format) {
@@ -394,7 +391,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public @FormatMode int getActionMode() {
@@ -402,7 +398,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public @FormatMode int getImageMode() {
@@ -410,7 +405,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public int getMaxWidth() {
@@ -418,7 +412,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public int getMaxHeight() {
@@ -426,7 +419,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public Bitmap.CompressFormat getFormat() {
@@ -434,7 +426,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public int getQuality() {
@@ -527,7 +518,6 @@
*/
public static class SliceParseException extends Exception {
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public SliceParseException(String s, Throwable e) {
@@ -535,7 +525,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public SliceParseException(String s) {
diff --git a/slice/slice-view/src/main/java/androidx/slice/SliceViewManager.java b/slice/slice-view/src/main/java/androidx/slice/SliceViewManager.java
index 0d2b294..95c0d6d 100644
--- a/slice/slice-view/src/main/java/androidx/slice/SliceViewManager.java
+++ b/slice/slice-view/src/main/java/androidx/slice/SliceViewManager.java
@@ -50,7 +50,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
SliceViewManager() {
diff --git a/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerBase.java b/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerBase.java
index 4ab5626..217d0f17d 100644
--- a/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerBase.java
+++ b/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerBase.java
@@ -34,7 +34,6 @@
import java.util.concurrent.Executor;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerCompat.java b/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerCompat.java
index b129081..1c1d436 100644
--- a/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerCompat.java
+++ b/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerCompat.java
@@ -33,7 +33,6 @@
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerWrapper.java b/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerWrapper.java
index 5c9989d..c4364d9 100644
--- a/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerWrapper.java
+++ b/slice/slice-view/src/main/java/androidx/slice/SliceViewManagerWrapper.java
@@ -40,7 +40,6 @@
import java.util.Set;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(api = 28)
diff --git a/slice/slice-view/src/main/java/androidx/slice/SliceXml.java b/slice/slice-view/src/main/java/androidx/slice/SliceXml.java
index aa8b562..1251afb 100644
--- a/slice/slice-view/src/main/java/androidx/slice/SliceXml.java
+++ b/slice/slice-view/src/main/java/androidx/slice/SliceXml.java
@@ -56,7 +56,6 @@
import java.util.List;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/ActionRow.java b/slice/slice-view/src/main/java/androidx/slice/widget/ActionRow.java
index efd9763..15f0ac0 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/ActionRow.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/ActionRow.java
@@ -51,7 +51,6 @@
import java.util.List;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/DisplayedListItems.java b/slice/slice-view/src/main/java/androidx/slice/widget/DisplayedListItems.java
index b815243..4b5ee95 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/DisplayedListItems.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/DisplayedListItems.java
@@ -23,7 +23,6 @@
/**
* The slice items we can render on the available space.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
class DisplayedListItems {
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/EventInfo.java b/slice/slice-view/src/main/java/androidx/slice/widget/EventInfo.java
index 2220d02..db5231f 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/EventInfo.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/EventInfo.java
@@ -30,7 +30,6 @@
public class EventInfo {
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
@@ -82,19 +81,16 @@
public static final int ROW_TYPE_SELECTION = 6;
/**
* Indicates the row represents a date selection (date picker).
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final int ROW_TYPE_DATE_PICK = 7;
/**
* Indicates the row represents a time selection (time picker).
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final int ROW_TYPE_TIME_PICK = 8;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
@@ -134,19 +130,16 @@
public static final int ACTION_TYPE_SELECTION = 5;
/**
* Indicates the event was a selection from a date picker.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final int ACTION_TYPE_DATE_PICK = 6;
/**
* Indicates the event was a selection from a time picker.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final int ACTION_TYPE_TIME_PICK = 7;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/GridContent.java b/slice/slice-view/src/main/java/androidx/slice/widget/GridContent.java
index b6c1724..ee38115 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/GridContent.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/GridContent.java
@@ -72,7 +72,6 @@
private SliceItem mTitleItem;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public GridContent(@NonNull SliceItem gridItem, int position) {
@@ -133,7 +132,6 @@
/**
* @return the title of this grid row, if it exists.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@Nullable
@@ -148,7 +146,6 @@
/**
* @return the list of cell content for this grid.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@NonNull
@@ -158,7 +155,6 @@
/**
* @return the content intent item for this grid.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@Nullable
@@ -168,7 +164,6 @@
/**
* @return the see more item to use when not all items in the grid can be displayed.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@Nullable
@@ -186,7 +181,6 @@
/**
* @return whether the contents of this grid is just images.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public boolean isAllImages() {
@@ -195,7 +189,6 @@
/**
* @return the largest image size in this row, if there are images.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public int getLargestImageMode() {
@@ -242,7 +235,6 @@
/**
* @return the max number of lines of text in the cells of this grid row.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public int getMaxCellLineCount() {
@@ -251,7 +243,6 @@
/**
* @return whether this row contains an image.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public boolean hasImage() {
@@ -260,14 +251,12 @@
/**
* @return whether this content is being displayed last in a list.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public boolean getIsLastIndex() { return mIsLastIndex; }
/**
* Sets whether this content is being displayed last in a list.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public void setIsLastIndex(boolean isLast) {
@@ -275,7 +264,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -286,7 +274,6 @@
/**
* Extracts information required to present content in a cell.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public static class CellContent {
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/GridRowView.java b/slice/slice-view/src/main/java/androidx/slice/widget/GridRowView.java
index 10215a4..9bbd5de 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/GridRowView.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/GridRowView.java
@@ -110,44 +110,44 @@
private int mHiddenItemCount;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected final View mForeground;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected int mRowIndex;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected int mRowCount;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected int mMaxCells = -1;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected @Nullable GridContent mGridContent;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected final int mLargeImageHeight;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected final int mSmallImageSize;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected final int mSmallImageMinWidth;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected final int mIconSize;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected final LinearLayout mViewContainer;
public GridRowView(@NonNull Context context) {
@@ -173,7 +173,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -215,7 +214,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -776,7 +774,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -802,7 +799,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -840,7 +836,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/ListContent.java b/slice/slice-view/src/main/java/androidx/slice/widget/ListContent.java
index 10d5836..8151152 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/ListContent.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/ListContent.java
@@ -51,7 +51,6 @@
/**
* Extracts information required to present content in a list format from a slice.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/LocationBasedViewTracker.java b/slice/slice-view/src/main/java/androidx/slice/widget/LocationBasedViewTracker.java
index b1b3c18..0404633 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/LocationBasedViewTracker.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/LocationBasedViewTracker.java
@@ -32,7 +32,6 @@
/**
* Utility class to track view based on relative location to the parent.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public class LocationBasedViewTracker implements Runnable, View.OnLayoutChangeListener {
@@ -110,7 +109,6 @@
/**
* Tries to preserve the input focus after the next content change
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public static void trackInputFocused(ViewGroup parent) {
@@ -122,7 +120,6 @@
/**
* Tries to preserve the accessibility focus after the next content change
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public static void trackA11yFocus(ViewGroup parent) {
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/MessageView.java b/slice/slice-view/src/main/java/androidx/slice/widget/MessageView.java
index 4f56a9b..8e44e18 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/MessageView.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/MessageView.java
@@ -37,7 +37,6 @@
import java.util.List;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/RemoteInputView.java b/slice/slice-view/src/main/java/androidx/slice/widget/RemoteInputView.java
index af12f00..09392c9 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/RemoteInputView.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/RemoteInputView.java
@@ -58,7 +58,6 @@
/**
* Host for the remote input.
*
- * @hide
*/
// TODO this should be unified with SystemUI RemoteInputView (b/67527720)
@SuppressWarnings("AppCompatCustomView")
@@ -266,7 +265,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setRevealParameters(int cx, int cy, int r) {
@@ -432,7 +430,6 @@
}
/** Whether key will, by default, trigger a click on the focused view.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public static final boolean isConfirmKey(int keyCode) {
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/RowContent.java b/slice/slice-view/src/main/java/androidx/slice/widget/RowContent.java
index dd54cb42..eed88be 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/RowContent.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/RowContent.java
@@ -57,7 +57,6 @@
/**
* Extracts information required to present content in a row format from a slice.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
@RequiresApi(19)
@@ -353,7 +352,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/RowStyle.java b/slice/slice-view/src/main/java/androidx/slice/widget/RowStyle.java
index cf3c170..02416ac 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/RowStyle.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/RowStyle.java
@@ -28,7 +28,6 @@
/**
* Holds style information shared between child views of a row
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/RowView.java b/slice/slice-view/src/main/java/androidx/slice/widget/RowView.java
index f094431..34d23e5 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/RowView.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/RowView.java
@@ -159,7 +159,6 @@
private boolean mIsStarRating;
private final ProgressBar mActionSpinner;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
protected Set<SliceItem> mLoadingActions = new HashSet<>();
@@ -236,7 +235,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -314,7 +312,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -386,7 +383,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -402,7 +398,6 @@
* @param actions if the actions are null then there are no header actions for this row.
* If the actions are an empty list, then something has explicitly set that no header
* actions should appear.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -414,7 +409,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -426,7 +420,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -706,7 +699,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -1148,7 +1140,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -1367,7 +1358,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/ShortcutView.java b/slice/slice-view/src/main/java/androidx/slice/widget/ShortcutView.java
index ac95f15..89ae3d0 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/ShortcutView.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/ShortcutView.java
@@ -39,7 +39,6 @@
import java.util.Set;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/SliceActionView.java b/slice/slice-view/src/main/java/androidx/slice/widget/SliceActionView.java
index 719e639..e5b20d0 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/SliceActionView.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/SliceActionView.java
@@ -52,7 +52,6 @@
/**
* Supports displaying {@link androidx.slice.core.SliceActionImpl}s.
- * @hide
*/
@SuppressWarnings("AppCompatCustomView")
@RestrictTo(LIBRARY)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/SliceAdapter.java b/slice/slice-view/src/main/java/androidx/slice/widget/SliceAdapter.java
index 08781d8..f8ae73a 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/SliceAdapter.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/SliceAdapter.java
@@ -32,6 +32,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
import androidx.collection.ArrayMap;
import androidx.recyclerview.widget.RecyclerView;
import androidx.slice.SliceItem;
@@ -102,8 +103,8 @@
/**
* Sets the SliceView parent and the template parent.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setParents(SliceView parent, TemplateView templateView) {
mParent = parent;
mTemplateView = templateView;
@@ -113,8 +114,8 @@
* Sets the insets (padding) for slice view. SliceAdapter will handle determining
* if a child needs a particular padding, i.e. if it's the first row then the top inset
* will be applied to it whereas subsequent rows would get a top inset of 0.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setInsets(int l, int t, int r, int b) {
mInsetStart = l;
mInsetTop = t;
@@ -124,16 +125,16 @@
/**
* Sets the observer to pass down to child views.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setSliceObserver(SliceView.OnSliceActionListener observer) {
mSliceObserver = observer;
}
/**
* Sets the actions to display for this slice, this adjusts what's displayed in the header item.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setSliceActions(List<SliceAction> actions) {
mSliceActions = actions;
notifyHeaderChanged();
@@ -141,8 +142,8 @@
/**
* Set the {@link SliceItem}'s to be displayed in the adapter and the accent color.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setSliceItems(List<SliceContent> slices, int color, int mode) {
if (slices == null) {
mLoadingActions.clear();
@@ -160,8 +161,8 @@
/**
* Sets the style information to use for views in this adapter.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setStyle(SliceStyle style) {
mSliceStyle = style;
notifyDataSetChanged();
@@ -169,16 +170,16 @@
/**
* Sets the policy information to use for views in this adapter.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setPolicy(SliceViewPolicy p) {
mPolicy = p;
}
/**
* Sets whether the last updated time should be shown on the slice.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setShowLastUpdated(boolean showLastUpdated) {
if (mShowLastUpdated != showLastUpdated) {
mShowLastUpdated = showLastUpdated;
@@ -188,8 +189,8 @@
/**
* Sets when the slice was last updated.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setLastUpdated(long lastUpdated) {
if (mLastUpdated != lastUpdated) {
mLastUpdated = lastUpdated;
@@ -199,8 +200,8 @@
/**
* Indicates that no actions should be loading and updates the views.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setLoadingActions(Set<SliceItem> actions) {
if (actions == null) {
mLoadingActions.clear();
@@ -212,15 +213,15 @@
/**
* Returns the currently loading actions.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public Set<SliceItem> getLoadingActions() {
return mLoadingActions;
}
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
public void onSliceActionLoading(SliceItem actionItem, int position) {
mLoadingActions.add(actionItem);
@@ -233,8 +234,8 @@
/**
* Sets whether this slice can have 2 lines of subtitle text in the first row.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setAllowTwoLines(boolean allowTwoLines) {
mAllowTwoLines = allowTwoLines;
notifyHeaderChanged();
@@ -242,8 +243,8 @@
/**
* Notifies that content in the header of this adapter has changed.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void notifyHeaderChanged() {
if (getItemCount() > 0) {
notifyItemChanged(HEADER_INDEX);
@@ -251,8 +252,8 @@
}
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@NonNull
public SliceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
@@ -277,8 +278,8 @@
}
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
public void onBindViewHolder(@NonNull SliceViewHolder holder, int position) {
SliceWrapper slice = mSlices.get(position);
@@ -320,8 +321,8 @@
}
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected static class SliceWrapper {
final SliceContent mItem;
final int mType;
@@ -354,8 +355,8 @@
/**
* A {@link RecyclerView.ViewHolder} for presenting slices in {@link SliceAdapter}.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public class SliceViewHolder extends RecyclerView.ViewHolder implements View.OnTouchListener,
View.OnClickListener {
public final SliceChildView mSliceChildView;
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/SliceChildView.java b/slice/slice-view/src/main/java/androidx/slice/widget/SliceChildView.java
index 8c61fb4..b0795bf 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/SliceChildView.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/SliceChildView.java
@@ -40,56 +40,56 @@
public abstract class SliceChildView extends FrameLayout {
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected SliceView.OnSliceActionListener mObserver;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected int mMode;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected int mTintColor = -1;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected boolean mShowLastUpdated;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected long mLastUpdated = -1;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected int mInsetStart;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected int mInsetTop;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected int mInsetEnd;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected int mInsetBottom;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected SliceActionView.SliceActionLoadingListener mLoadingListener;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected SliceStyle mSliceStyle;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected RowStyle mRowStyle;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected SliceViewPolicy mViewPolicy;
public SliceChildView(@NonNull Context context) {
@@ -107,7 +107,6 @@
/**
* Sets the content to display in this slice.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setSliceContent(ListContent content) {
@@ -116,7 +115,6 @@
/**
* Sets the insets (padding) for the slice.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setInsets(int l, int t, int r, int b) {
@@ -136,7 +134,6 @@
/**
* Sets the slice actions for this view.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setSliceActions(List<SliceAction> actions) {
@@ -145,8 +142,8 @@
/**
* @return the mode of the slice being presented.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
@SliceView.SliceMode
public int getMode() {
return mViewPolicy != null ? mViewPolicy.getMode() : MODE_LARGE;
@@ -154,7 +151,6 @@
/**
* Sets a custom color to use for tinting elements like icons for this view.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setTint(@ColorInt int tintColor) {
@@ -163,7 +159,6 @@
/**
* Sets whether the last updated time should be displayed.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setShowLastUpdated(boolean showLastUpdated) {
@@ -172,7 +167,6 @@
/**
* Sets when the content of this view was last updated.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setLastUpdated(long lastUpdated) {
@@ -181,23 +175,22 @@
/**
* Sets the observer to notify when an interaction events occur on the view.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setSliceActionListener(SliceView.OnSliceActionListener observer) {
mObserver = observer;
}
/**
* Sets the listener to notify whenever an action is being loaded.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public void setSliceActionLoadingListener(SliceActionView.SliceActionLoadingListener listener) {
mLoadingListener = listener;
}
/**
* Indicates that a particular action is being loaded.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setActionLoading(SliceItem item) {
@@ -205,7 +198,6 @@
/**
* Sets the actions that are being loaded.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setLoadingActions(Set<SliceItem> loadingActions) {
@@ -213,7 +205,6 @@
/**
* Sets whether this slice can have 2 lines of subtitle text in the first row.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setAllowTwoLines(boolean allowTwoLines) {
@@ -221,7 +212,6 @@
/**
* The set of currently loading actions.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public Set<SliceItem> getLoadingActions() {
@@ -230,7 +220,6 @@
/**
* Sets the style information for this view.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setStyle(SliceStyle styles, @NonNull RowStyle rowStyle) {
@@ -240,7 +229,6 @@
/**
* Sets the policy information for this view.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setPolicy(@Nullable SliceViewPolicy policy) {
@@ -248,7 +236,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public int getHiddenItemCount() {
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/SliceContent.java b/slice/slice-view/src/main/java/androidx/slice/widget/SliceContent.java
index 6dc5983..a56e1e9 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/SliceContent.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/SliceContent.java
@@ -58,24 +58,24 @@
public class SliceContent {
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected SliceItem mSliceItem;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected SliceItem mColorItem;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected SliceItem mLayoutDirItem;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected SliceItem mContentDescr;
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
protected int mRowIndex;
public SliceContent(@Nullable Slice slice) {
@@ -86,7 +86,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public SliceContent(@Nullable SliceItem item, int rowIndex) {
@@ -108,8 +107,8 @@
/**
* @return the slice item used to construct this content.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
@Nullable
public SliceItem getSliceItem() {
return mSliceItem;
@@ -117,24 +116,24 @@
/**
* @return the accent color to use for this content or -1 if no color is set.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public int getAccentColor() {
return mColorItem != null ? mColorItem.getInt() : -1;
}
/**
* @return the layout direction to use for this content or -1 if no direction set.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public int getLayoutDir() {
return mLayoutDirItem != null ? resolveLayoutDirection(mLayoutDirItem.getInt()) : -1;
}
/**
* @return the content description to use for this row if set.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
@Nullable
public CharSequence getContentDescription() {
return mContentDescr != null ? mContentDescr.getText() : null;
@@ -142,31 +141,31 @@
/**
* @return the row index of this content, or -1 if no row index is set.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public int getRowIndex() { return mRowIndex; }
/**
* @return the desired height of this content based on the provided mode and context or the
* default height if context is null.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public int getHeight(SliceStyle style, SliceViewPolicy policy) {
return 0;
}
/**
* @return whether this content is valid to display or not.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
public boolean isValid() {
return mSliceItem != null;
}
/**
* @return the action that represents the shortcut.
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
@Nullable
public SliceAction getShortcut(@Nullable Context context) {
if (mSliceItem == null) {
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/SliceLiveData.java b/slice/slice-view/src/main/java/androidx/slice/widget/SliceLiveData.java
index 9357327..8fc3a85 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/SliceLiveData.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/SliceLiveData.java
@@ -61,19 +61,16 @@
private static final String TAG = "SliceLiveData";
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final SliceSpec OLD_BASIC = new SliceSpec("androidx.app.slice.BASIC", 1);
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final SliceSpec OLD_LIST = new SliceSpec("androidx.app.slice.LIST", 1);
/**
- * @hide
*/
@RestrictTo(LIBRARY)
public static final Set<SliceSpec> SUPPORTED_SPECS = new ArraySet<>(
@@ -139,7 +136,6 @@
/**
* Version for testing
- * @hide
*/
@RestrictTo(LIBRARY_GROUP_PREFIX)
@NonNull
@@ -208,7 +204,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
@SuppressWarnings("deprecation") /* AsyncTask */
@@ -292,7 +287,6 @@
}
/**
- * @hide
*/
@RestrictTo(LIBRARY)
protected void updateSlice() {
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/SliceMetrics.java b/slice/slice-view/src/main/java/androidx/slice/widget/SliceMetrics.java
index 6592759..faa5e10 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/SliceMetrics.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/SliceMetrics.java
@@ -26,7 +26,6 @@
import androidx.annotation.RestrictTo;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/SliceMetricsWrapper.java b/slice/slice-view/src/main/java/androidx/slice/widget/SliceMetricsWrapper.java
index ad74f35..adb43d8 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/SliceMetricsWrapper.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/SliceMetricsWrapper.java
@@ -24,7 +24,6 @@
import androidx.annotation.RestrictTo;
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(api = 28)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/SliceStyle.java b/slice/slice-view/src/main/java/androidx/slice/widget/SliceStyle.java
index 60917e0..2440e67 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/SliceStyle.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/SliceStyle.java
@@ -41,7 +41,6 @@
/**
* Holds style information shared between child views of a slice
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/SliceView.java b/slice/slice-view/src/main/java/androidx/slice/widget/SliceView.java
index 2d53b83..8c6fd44 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/SliceView.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/SliceView.java
@@ -115,7 +115,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
@@ -253,7 +252,6 @@
/**
* Indicates whether this view reacts to click events or not.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public boolean isSliceViewClickable() {
@@ -263,7 +261,6 @@
/**
* Sets the event info for logging a click.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setClickInfo(int[] info) {
@@ -629,7 +626,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void setMode(@SliceMode int mode, boolean animate) {
@@ -714,7 +710,6 @@
}
/**
- * @hide
*
* Whether this view should show a row of actions with it.
*/
@@ -726,7 +721,6 @@
/**
* @return whether this view is showing a row of actions.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public boolean isShowingActionRow() {
@@ -853,7 +847,6 @@
/**
* @return String representation of the provided mode.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public static String modeToString(@SliceMode int mode) {
@@ -970,7 +963,6 @@
};
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public static final Comparator<SliceAction> SLICE_ACTION_PRIORITY_COMPARATOR =
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/SliceViewPolicy.java b/slice/slice-view/src/main/java/androidx/slice/widget/SliceViewPolicy.java
index 7c32336..57dcf89 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/SliceViewPolicy.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/SliceViewPolicy.java
@@ -24,7 +24,6 @@
/**
* Class containing configurable settings for SliceView that may impact interaction and contents
* of the slice that are displayed.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/SliceViewUtil.java b/slice/slice-view/src/main/java/androidx/slice/widget/SliceViewUtil.java
index 88b64df..f4f0499 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/SliceViewUtil.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/SliceViewUtil.java
@@ -51,7 +51,6 @@
/**
* A bunch of utilities for slice UI.
*
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
diff --git a/slice/slice-view/src/main/java/androidx/slice/widget/TemplateView.java b/slice/slice-view/src/main/java/androidx/slice/widget/TemplateView.java
index 33f8625..b26282b 100644
--- a/slice/slice-view/src/main/java/androidx/slice/widget/TemplateView.java
+++ b/slice/slice-view/src/main/java/androidx/slice/widget/TemplateView.java
@@ -98,7 +98,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -110,7 +109,6 @@
/**
* Called when the foreground view handling touch feedback should be activated.
* @param event the event to handle.
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void onForegroundActivated(MotionEvent event) {
@@ -136,7 +134,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -147,7 +144,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -156,7 +152,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -165,7 +160,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -174,7 +168,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -184,8 +177,8 @@
}
/**
- * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
public void setSliceActionListener(SliceView.OnSliceActionListener observer) {
mObserver = observer;
@@ -195,7 +188,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -204,7 +196,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -215,7 +206,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -232,7 +222,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -242,7 +231,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -252,7 +240,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -283,7 +270,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -295,7 +281,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -310,7 +295,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -321,7 +305,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -332,7 +315,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
@@ -343,7 +325,6 @@
}
/**
- * @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Override
diff --git a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt
index 95a513e..f67bb85 100644
--- a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt
+++ b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt
@@ -92,8 +92,6 @@
val apiDirName = "$API_DIR/aidl${variant.name.usLocaleCapitalize()}"
val builtApiDir = project.layout.buildDirectory.dir(apiDirName)
- val lastReleasedApiDir =
- project.layout.projectDirectory.dir("$apiDirName/$RELEASED_API_DIR")
val lastCheckedInApiDir =
project.layout.projectDirectory.dir("$apiDirName/$CURRENT_API_DIR")
@@ -128,16 +126,6 @@
builtApiDir,
compileAidlApiTask
)
- val checkAidlApiReleaseTask = registerCheckApiAidlRelease(
- project,
- variant,
- aidlExecutable,
- aidlFramework,
- importsDir,
- depImports,
- lastReleasedApiDir,
- generateAidlApiTask
- )
val checkAidlApiTask = registerCheckAidlApi(
project,
variant,
@@ -146,14 +134,14 @@
importsDir,
depImports,
lastCheckedInApiDir,
- generateAidlApiTask,
- checkAidlApiReleaseTask
+ generateAidlApiTask
)
val updateAidlApiTask = registerUpdateAidlApi(
project,
variant,
lastCheckedInApiDir,
- generateAidlApiTask
+ generateAidlApiTask,
+ checkAidlApiTask
)
if (variant.name == DEFAULT_VARIANT_NAME) {
@@ -168,7 +156,6 @@
extension.allTasks[variant.name] = setOf(
compileAidlApiTask,
generateAidlApiTask,
- checkAidlApiReleaseTask,
checkAidlApiTask,
updateAidlApiTask
)
@@ -182,16 +169,11 @@
internal const val API_DIR = "api"
/**
- * Directory under [API_DIR] where the current (work-in-progress) API files are stored.
+ * Directory under [API_DIR] where frozen API files are stored.
*/
internal const val CURRENT_API_DIR = "current"
/**
- * Directory under [API_DIR] where the released (frozen) API files are stored.
- */
-internal const val RELEASED_API_DIR = "released"
-
-/**
* Source type for Stable AIDL files.
*/
internal const val SOURCE_TYPE_STABLE_AIDL = "stableAidl"
diff --git a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlTasks.kt b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlTasks.kt
index 4d1dbfe..c9fa664 100644
--- a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlTasks.kt
+++ b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlTasks.kt
@@ -80,7 +80,7 @@
depImports: List<FileCollection>,
outputDir: Provider<Directory>
): TaskProvider<StableAidlCompile> = project.tasks.register(
- computeTaskName("compile", variant, "AidlApi"),
+ computeTaskName("compile", variant),
StableAidlCompile::class.java
) { task ->
task.group = TASK_GROUP_API
@@ -142,7 +142,7 @@
variant: Variant,
compileAidlApiTask: TaskProvider<StableAidlCompile>
): TaskProvider<StableAidlPackageApi> = project.tasks.register(
- computeTaskName("package", variant, "AidlApi"),
+ computeTaskName("package", variant),
StableAidlPackageApi::class.java
) { task ->
task.packagedDir.set(compileAidlApiTask.flatMap { it.packagedDir })
@@ -166,7 +166,7 @@
builtApiDir: Provider<Directory>,
compileAidlApiTask: Provider<StableAidlCompile>
): TaskProvider<StableAidlCompile> = project.tasks.register(
- computeTaskName("generate", variant, "AidlApi"),
+ computeTaskName("generate", variant),
StableAidlCompile::class.java
) { task ->
task.group = TASK_GROUP_API
@@ -187,37 +187,6 @@
task.dependsOn(compileAidlApiTask)
}
-// Policy: If the artifact has previously been released, e.g. has a beta or later API file
-// checked in, then we must verify "release compatibility" against the work-in-progress
-// API file.
-fun registerCheckApiAidlRelease(
- project: Project,
- variant: Variant,
- aidlExecutable: Provider<RegularFile>,
- aidlFramework: Provider<RegularFile>,
- importsDir: SourceDirectories.Flat,
- depImports: List<FileCollection>,
- lastReleasedApiDir: Directory,
- generateAidlTask: Provider<StableAidlCompile>
-): TaskProvider<StableAidlCheckApi> = project.tasks.register(
- computeTaskName("check", variant, "AidlApiRelease"),
- StableAidlCheckApi::class.java
-) { task ->
- task.group = TASK_GROUP_API
- task.description = "Checks the AIDL source code API surface against the " +
- "stabilized AIDL API files"
- task.variantName = variant.name
- task.aidlExecutable.set(aidlExecutable)
- task.aidlFrameworkProvider.set(aidlFramework)
- task.importDirs.set(importsDir.all)
- depImports.forEach { task.dependencyImportDirs.addAll(it.elements) }
- task.checkApiMode.set(StableAidlCheckApi.MODE_COMPATIBLE)
- task.expectedApiDir.set(lastReleasedApiDir)
- task.actualApiDir.set(generateAidlTask.flatMap { it.sourceOutputDir })
- task.failOnMissingExpected.set(false)
- task.cacheEvenIfNoOutputs()
-}
-
// Policy: All changes to API surfaces for which compatibility is enforced must be
// explicitly confirmed by running the updateApi task. To enforce this, the implementation
fun registerCheckAidlApi(
@@ -228,10 +197,9 @@
importsDir: SourceDirectories.Flat,
depImports: List<FileCollection>,
lastCheckedInApiFile: Directory,
- generateAidlTask: Provider<StableAidlCompile>,
- checkAidlApiReleaseTask: Provider<StableAidlCheckApi>
+ generateAidlTask: Provider<StableAidlCompile>
): TaskProvider<StableAidlCheckApi> = project.tasks.register(
- computeTaskName("check", variant, "AidlApi"),
+ computeTaskName("check", variant),
StableAidlCheckApi::class.java
) { task ->
task.group = TASK_GROUP_API
@@ -247,7 +215,6 @@
task.actualApiDir.set(generateAidlTask.flatMap { it.sourceOutputDir })
task.failOnMissingExpected.set(true)
task.cacheEvenIfNoOutputs()
- task.dependsOn(checkAidlApiReleaseTask)
}
fun registerUpdateAidlApi(
@@ -255,8 +222,9 @@
variant: Variant,
lastCheckedInApiFile: Directory,
generateAidlTask: Provider<StableAidlCompile>,
+ checkAidlApiTask: Provider<StableAidlCheckApi>
): TaskProvider<UpdateStableAidlApiTask> = project.tasks.register(
- computeTaskName("update", variant, "AidlApi"),
+ computeTaskName("update", variant),
UpdateStableAidlApiTask::class.java
) { task ->
task.group = TASK_GROUP_API
@@ -265,6 +233,8 @@
task.apiLocation.set(generateAidlTask.flatMap { it.sourceOutputDir })
task.outputApiLocations.set(listOf(lastCheckedInApiFile.asFile))
task.forceUpdate.set(project.providers.gradleProperty("force").isPresent)
+ // We depend on the outputs, but we also depend
+ task.dependsOn(checkAidlApiTask)
}
/**
@@ -283,5 +253,5 @@
return File(this.project.buildDir, "placeholderOutput/" + this.name.replace(":", "-"))
}
-private fun computeTaskName(prefix: String, variant: Variant, suffix: String) =
- "$prefix${variant.name.usLocaleCapitalize()}$suffix"
+private fun computeTaskName(prefix: String, variant: Variant) =
+ "$prefix${variant.name.usLocaleCapitalize()}AidlApi"
diff --git a/stableaidl/stableaidl-gradle-plugin/src/test/java/androidx/stableaidl/StableAidlPluginTest.kt b/stableaidl/stableaidl-gradle-plugin/src/test/java/androidx/stableaidl/StableAidlPluginTest.kt
index 41bf28a..b7d9b47 100644
--- a/stableaidl/stableaidl-gradle-plugin/src/test/java/androidx/stableaidl/StableAidlPluginTest.kt
+++ b/stableaidl/stableaidl-gradle-plugin/src/test/java/androidx/stableaidl/StableAidlPluginTest.kt
@@ -67,7 +67,7 @@
// Tasks should contain those defined in StableAidlTasks.
val output = gradleRunner.withArguments("tasks", "--stacktrace").build()
assertTrue { output.output.contains("compileDebugAidlApi - ") }
- assertTrue { output.output.contains("checkDebugAidlApiRelease - ") }
+ assertTrue { output.output.contains("checkDebugAidlApi - ") }
}
@Test
@@ -97,7 +97,7 @@
// Tasks should contain those defined in StableAidlTasks.
val output = gradleRunner.withArguments("tasks", "--stacktrace").build()
assertTrue { output.output.contains("compileDebugAidlApi - ") }
- assertTrue { output.output.contains("checkDebugAidlApiRelease - ") }
+ assertTrue { output.output.contains("checkDebugAidlApi - ") }
}
@Test
diff --git a/test/screenshot/screenshot/src/main/java/androidx/test/screenshot/ScreenshotTestRule.kt b/test/screenshot/screenshot/src/main/java/androidx/test/screenshot/ScreenshotTestRule.kt
index 7cbd8db..511d9e5f 100644
--- a/test/screenshot/screenshot/src/main/java/androidx/test/screenshot/ScreenshotTestRule.kt
+++ b/test/screenshot/screenshot/src/main/java/androidx/test/screenshot/ScreenshotTestRule.kt
@@ -119,20 +119,14 @@
class ScreenshotTestStatement(private val base: Statement) : Statement() {
override fun evaluate() {
- if (Build.MODEL.contains("Cuttlefish")) {
- // We currently support Cuttlefish with API 29 because of the storage access.
- Assume.assumeTrue(
- "Requires SDK 29.",
- Build.VERSION.SDK_INT == 29
- )
- } else if (Build.MODEL.contains("gphone")) {
- // We also support emulators with API 33 now
+ if (Build.MODEL.contains("gphone")) {
+ // We support emulators with API 33
Assume.assumeTrue(
"Requires SDK 33.",
Build.VERSION.SDK_INT == 33
)
} else {
- Assume.assumeTrue("Requires Cuttlefish or emulator", false)
+ Assume.assumeTrue("Requires API 33 emulator", false)
}
base.evaluate()
}
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BaseTest.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BaseTest.java
index da92d0f..fac1c20 100644
--- a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BaseTest.java
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BaseTest.java
@@ -22,9 +22,11 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -46,7 +48,7 @@
@RunWith(AndroidJUnit4.class)
public abstract class BaseTest {
- private static final long TIMEOUT_MS = 10_000;
+ protected static final long TIMEOUT_MS = 10_000;
protected static final String TEST_APP = "androidx.test.uiautomator.testapp";
protected static final int DEFAULT_FLAGS =
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK;
@@ -77,8 +79,13 @@
}
protected void launchTestActivity(@NonNull Class<? extends Activity> activity) {
+ launchTestActivity(activity, new Intent().setFlags(DEFAULT_FLAGS), null);
+ }
+
+ protected void launchTestActivity(@NonNull Class<? extends Activity> activity,
+ @NonNull Intent intent, @Nullable Bundle options) {
Context context = ApplicationProvider.getApplicationContext();
- context.startActivity(new Intent().setFlags(DEFAULT_FLAGS).setClass(context, activity));
+ context.startActivity(new Intent(intent).setClass(context, activity), options);
assertTrue("Test app not visible after launching activity",
mDevice.wait(Until.hasObject(By.pkg(TEST_APP)), TIMEOUT_MS));
}
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/MultiDisplayTest.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/MultiDisplayTest.java
new file mode 100644
index 0000000..484dd9f
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/MultiDisplayTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.test.uiautomator.testapp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.view.Display;
+
+import androidx.annotation.NonNull;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@SdkSuppress(minSdkVersion = 30)
+public class MultiDisplayTest extends BaseTest {
+ private static final int MULTI_DISPLAY_FLAGS =
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+
+ @Before
+ public void assumeMultiDisplay() {
+ // Tests need to run with multiple displays.
+ assumeTrue(getDisplayIds().size() > 1);
+ }
+
+ @Test
+ public void testMultiDisplay_click() {
+ int selectedDisplayId = getSecondaryDisplayId();
+ launchTestActivityOnDisplay(ClickTestActivity.class, selectedDisplayId);
+
+ UiObject2 button = mDevice.findObject(By.res(TEST_APP, "button1"));
+ button.click();
+ assertEquals(selectedDisplayId, button.getDisplayId());
+ assertTrue(button.wait(Until.textEquals("text1_clicked"), TIMEOUT_MS));
+ }
+
+ // Helper to launch an activity on a specific display.
+ private void launchTestActivityOnDisplay(@NonNull Class<? extends Activity> activity,
+ int displayId) {
+ launchTestActivity(activity, new Intent().setFlags(MULTI_DISPLAY_FLAGS),
+ ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle());
+ }
+
+ // Helper to get all the display IDs in the current testing environment.
+ private static Set<Integer> getDisplayIds() {
+ Context context = ApplicationProvider.getApplicationContext();
+ DisplayManager displayManager = context.getSystemService(DisplayManager.class);
+ return Arrays.stream(displayManager.getDisplays()).map(Display::getDisplayId).collect(
+ Collectors.toSet());
+ }
+
+ // Helper to get the ID of the first non-default display.
+ private static int getSecondaryDisplayId() {
+ int selectedDisplayId = 0;
+ for (int displayId : getDisplayIds()) {
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ selectedDisplayId = displayId;
+ break;
+ }
+ }
+ return selectedDisplayId;
+ }
+}
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTest.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTest.java
index 3f0f1f5..6e38237 100644
--- a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTest.java
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTest.java
@@ -21,7 +21,6 @@
import static org.junit.Assert.assertTrue;
import android.graphics.Rect;
-import android.os.Build;
import android.os.SystemClock;
import androidx.test.filters.LargeTest;
@@ -87,13 +86,10 @@
assertTrue(bottomHalf.contains(pipWindow.getVisibleBounds()));
}
+ @Ignore // b/262909049, b/281290766
@Test
@SdkSuppress(minSdkVersion = 32)
public void testMultiWindow_splitScreen() {
- if (Build.VERSION.SDK_INT == 33 && !"REL".equals(Build.VERSION.CODENAME)) {
- return; // b/262909049: Do not run this test on pre-release Android U.
- }
-
// Launch two split-screen activities with different IDs.
launchTestActivity(SplitScreenTestActivity.class);
SystemClock.sleep(TRANSITION_DELAY_MS); // Wait for the windows to settle.
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Test.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Test.java
index 8f82b96..67efd97 100644
--- a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Test.java
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Test.java
@@ -16,6 +16,8 @@
package androidx.test.uiautomator.testapp;
+import static android.os.Build.VERSION.SDK_INT;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -26,6 +28,7 @@
import android.graphics.Point;
import android.graphics.Rect;
+import android.view.Display;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
@@ -38,6 +41,7 @@
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
+import org.junit.Assume;
import org.junit.Ignore;
import org.junit.Test;
@@ -341,6 +345,14 @@
}
@Test
+ public void testGetDisplayId() {
+ launchTestActivity(MainActivity.class);
+
+ UiObject2 button = mDevice.findObject(By.res(TEST_APP, "button"));
+ assertEquals(Display.DEFAULT_DISPLAY, button.getDisplayId());
+ }
+
+ @Test
public void testGetVisibleBounds() {
launchTestActivity(VisibleBoundsTestActivity.class);
@@ -642,6 +654,7 @@
@Test
public void testScrollUntil_conditionSatisfied() {
+ Assume.assumeFalse(SDK_INT == 26); // b/272346700
launchTestActivity(VerticalScrollTestActivity.class);
assertTrue(mDevice.hasObject(By.res(TEST_APP, "top_text"))); // Initially at top.
assertFalse(mDevice.hasObject(By.res(TEST_APP, "bottom_text")));
@@ -674,27 +687,9 @@
assertFalse(mDevice.hasObject(By.res(TEST_APP, "bottom_text")));
UiObject2 scrollView = mDevice.findObject(By.res(TEST_APP, "scroll_view"));
- // Scroll for the event condition that occurs early before scrolling to the end.
- Integer result = scrollView.scrollUntil(Direction.DOWN,
- new EventCondition<Integer>() {
- private Integer mResult = null;
- @Override
- public Integer getResult() {
- return mResult;
- }
-
- @Override
- public boolean accept(AccessibilityEvent event) {
- if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
- mResult = event.getEventType();
- return true;
- }
- return false;
- }
- });
- assertEquals(result, (Integer) AccessibilityEvent.TYPE_VIEW_SCROLLED);
- // We haven't scrolled to the end.
- assertFalse(mDevice.hasObject(By.res(TEST_APP, "bottom_text")));
+ // Scroll to the end.
+ assertTrue(scrollView.scrollUntil(Direction.DOWN, Until.scrollFinished(Direction.DOWN)));
+ assertTrue(mDevice.hasObject(By.res(TEST_APP, "bottom_text")));
}
@Test
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObjectTest.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObjectTest.java
index f74a13b..da9c476 100644
--- a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObjectTest.java
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObjectTest.java
@@ -341,18 +341,6 @@
}
@Test
- public void testLegacySetText() throws Exception {
- launchTestActivity(ClearTextTestActivity.class);
-
- UiObject editText = mDevice.findObject(new UiSelector().resourceId(TEST_APP + ":id"
- + "/edit_text"));
-
- assertEquals("sample_text", editText.getText());
- editText.legacySetText("new_text");
- assertEquals("new_text", editText.getText());
- }
-
- @Test
public void testSetText() throws Exception {
launchTestActivity(ClearTextTestActivity.class);
@@ -385,7 +373,6 @@
assertUiObjectNotFound(noNode::getText);
assertUiObjectNotFound(noNode::getClassName);
assertUiObjectNotFound(noNode::getContentDescription);
- assertUiObjectNotFound(() -> noNode.legacySetText("new_text"));
assertUiObjectNotFound(() -> noNode.setText("new_text"));
assertUiObjectNotFound(noNode::clearTextField);
assertUiObjectNotFound(noNode::getPackageName);
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiScrollableTest.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiScrollableTest.java
index 3384042..b2d36b9 100644
--- a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiScrollableTest.java
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiScrollableTest.java
@@ -183,22 +183,6 @@
}
@Test
- public void testEnsureFullyVisible() throws Exception {
- launchTestActivity(VerticalScrollTestActivity.class);
-
- UiScrollable relativeLayout = new UiScrollable(
- new UiSelector().resourceId(TEST_APP + ":id/relative_layout"));
- UiObject target = mDevice.findObject(
- new UiSelector().resourceId(TEST_APP + ":id/bottom_text"));
-
- assertTrue(relativeLayout.scrollIntoView(target));
- assertTrue(relativeLayout.ensureFullyVisible(target));
- assertUiObjectNotFound(
- () -> relativeLayout.ensureFullyVisible(
- mDevice.findObject(new UiSelector().resourceId(TEST_APP + ":id/no_node"))));
- }
-
- @Test
public void testScrollTextIntoView() throws Exception {
launchTestActivity(VerticalScrollTestActivity.class);
diff --git a/test/uiautomator/uiautomator/api/2.2.0.txt b/test/uiautomator/uiautomator/api/2.2.0.txt
new file mode 100644
index 0000000..4399b8c
--- /dev/null
+++ b/test/uiautomator/uiautomator/api/2.2.0.txt
@@ -0,0 +1,417 @@
+// Signature format: 4.0
+package androidx.test.uiautomator {
+
+ public class By {
+ method public static androidx.test.uiautomator.BySelector! checkable(boolean);
+ method public static androidx.test.uiautomator.BySelector! checked(boolean);
+ method public static androidx.test.uiautomator.BySelector! clazz(Class!);
+ method public static androidx.test.uiautomator.BySelector! clazz(String!);
+ method public static androidx.test.uiautomator.BySelector! clazz(String!, String!);
+ method public static androidx.test.uiautomator.BySelector! clazz(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.BySelector! clickable(boolean);
+ method public static androidx.test.uiautomator.BySelector! copy(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.BySelector! depth(int);
+ method public static androidx.test.uiautomator.BySelector! desc(String!);
+ method public static androidx.test.uiautomator.BySelector! desc(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.BySelector! descContains(String!);
+ method public static androidx.test.uiautomator.BySelector! descEndsWith(String!);
+ method public static androidx.test.uiautomator.BySelector! descStartsWith(String!);
+ method public static androidx.test.uiautomator.BySelector! enabled(boolean);
+ method public static androidx.test.uiautomator.BySelector! focusable(boolean);
+ method public static androidx.test.uiautomator.BySelector! focused(boolean);
+ method public static androidx.test.uiautomator.BySelector! hasChild(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.BySelector! hasDescendant(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.BySelector! hasDescendant(androidx.test.uiautomator.BySelector!, int);
+ method public static androidx.test.uiautomator.BySelector! longClickable(boolean);
+ method public static androidx.test.uiautomator.BySelector! pkg(String!);
+ method public static androidx.test.uiautomator.BySelector! pkg(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.BySelector! res(String!);
+ method public static androidx.test.uiautomator.BySelector! res(String!, String!);
+ method public static androidx.test.uiautomator.BySelector! res(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.BySelector! scrollable(boolean);
+ method public static androidx.test.uiautomator.BySelector! selected(boolean);
+ method public static androidx.test.uiautomator.BySelector! text(String!);
+ method public static androidx.test.uiautomator.BySelector! text(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.BySelector! textContains(String!);
+ method public static androidx.test.uiautomator.BySelector! textEndsWith(String!);
+ method public static androidx.test.uiautomator.BySelector! textStartsWith(String!);
+ }
+
+ public class BySelector {
+ method public androidx.test.uiautomator.BySelector! checkable(boolean);
+ method public androidx.test.uiautomator.BySelector! checked(boolean);
+ method public androidx.test.uiautomator.BySelector! clazz(Class!);
+ method public androidx.test.uiautomator.BySelector! clazz(String!);
+ method public androidx.test.uiautomator.BySelector! clazz(String!, String!);
+ method public androidx.test.uiautomator.BySelector! clazz(java.util.regex.Pattern!);
+ method public androidx.test.uiautomator.BySelector! clickable(boolean);
+ method public androidx.test.uiautomator.BySelector! depth(int);
+ method public androidx.test.uiautomator.BySelector! depth(int, int);
+ method public androidx.test.uiautomator.BySelector! desc(String!);
+ method public androidx.test.uiautomator.BySelector! desc(java.util.regex.Pattern!);
+ method public androidx.test.uiautomator.BySelector! descContains(String!);
+ method public androidx.test.uiautomator.BySelector! descEndsWith(String!);
+ method public androidx.test.uiautomator.BySelector! descStartsWith(String!);
+ method public androidx.test.uiautomator.BySelector! enabled(boolean);
+ method public androidx.test.uiautomator.BySelector! focusable(boolean);
+ method public androidx.test.uiautomator.BySelector! focused(boolean);
+ method public androidx.test.uiautomator.BySelector! hasChild(androidx.test.uiautomator.BySelector!);
+ method public androidx.test.uiautomator.BySelector! hasDescendant(androidx.test.uiautomator.BySelector!);
+ method public androidx.test.uiautomator.BySelector! hasDescendant(androidx.test.uiautomator.BySelector!, int);
+ method public androidx.test.uiautomator.BySelector! longClickable(boolean);
+ method public androidx.test.uiautomator.BySelector! maxDepth(int);
+ method public androidx.test.uiautomator.BySelector! minDepth(int);
+ method public androidx.test.uiautomator.BySelector! pkg(String!);
+ method public androidx.test.uiautomator.BySelector! pkg(java.util.regex.Pattern!);
+ method public androidx.test.uiautomator.BySelector! res(String!);
+ method public androidx.test.uiautomator.BySelector! res(String!, String!);
+ method public androidx.test.uiautomator.BySelector! res(java.util.regex.Pattern!);
+ method public androidx.test.uiautomator.BySelector! scrollable(boolean);
+ method public androidx.test.uiautomator.BySelector! selected(boolean);
+ method public androidx.test.uiautomator.BySelector! text(String!);
+ method public androidx.test.uiautomator.BySelector! text(java.util.regex.Pattern!);
+ method public androidx.test.uiautomator.BySelector! textContains(String!);
+ method public androidx.test.uiautomator.BySelector! textEndsWith(String!);
+ method public androidx.test.uiautomator.BySelector! textStartsWith(String!);
+ }
+
+ public final class Configurator {
+ method public long getActionAcknowledgmentTimeout();
+ method public static androidx.test.uiautomator.Configurator! getInstance();
+ method public long getKeyInjectionDelay();
+ method public long getScrollAcknowledgmentTimeout();
+ method public int getToolType();
+ method public int getUiAutomationFlags();
+ method public long getWaitForIdleTimeout();
+ method public long getWaitForSelectorTimeout();
+ method public androidx.test.uiautomator.Configurator! setActionAcknowledgmentTimeout(long);
+ method public androidx.test.uiautomator.Configurator! setKeyInjectionDelay(long);
+ method public androidx.test.uiautomator.Configurator! setScrollAcknowledgmentTimeout(long);
+ method public androidx.test.uiautomator.Configurator! setToolType(int);
+ method public androidx.test.uiautomator.Configurator! setUiAutomationFlags(int);
+ method public androidx.test.uiautomator.Configurator! setWaitForIdleTimeout(long);
+ method public androidx.test.uiautomator.Configurator! setWaitForSelectorTimeout(long);
+ }
+
+ public enum Direction {
+ method public static androidx.test.uiautomator.Direction! reverse(androidx.test.uiautomator.Direction!);
+ enum_constant public static final androidx.test.uiautomator.Direction DOWN;
+ enum_constant public static final androidx.test.uiautomator.Direction LEFT;
+ enum_constant public static final androidx.test.uiautomator.Direction RIGHT;
+ enum_constant public static final androidx.test.uiautomator.Direction UP;
+ }
+
+ public abstract class EventCondition<R> {
+ ctor public EventCondition();
+ }
+
+ public interface IAutomationSupport {
+ method public void sendStatus(int, android.os.Bundle!);
+ }
+
+ public abstract class SearchCondition<R> {
+ ctor public SearchCondition();
+ }
+
+ public class StaleObjectException extends java.lang.RuntimeException {
+ ctor public StaleObjectException();
+ }
+
+ public class UiAutomatorInstrumentationTestRunner extends android.test.InstrumentationTestRunner {
+ ctor public UiAutomatorInstrumentationTestRunner();
+ method protected android.test.AndroidTestRunner! getAndroidTestRunner();
+ method protected void initializeUiAutomatorTest(androidx.test.uiautomator.UiAutomatorTestCase!);
+ }
+
+ @Deprecated public class UiAutomatorTestCase extends android.test.InstrumentationTestCase {
+ ctor @Deprecated public UiAutomatorTestCase();
+ method @Deprecated public androidx.test.uiautomator.IAutomationSupport! getAutomationSupport();
+ method @Deprecated public android.os.Bundle! getParams();
+ method @Deprecated public androidx.test.uiautomator.UiDevice! getUiDevice();
+ method @Deprecated public void sleep(long);
+ }
+
+ public class UiCollection extends androidx.test.uiautomator.UiObject {
+ ctor public UiCollection(androidx.test.uiautomator.UiSelector!);
+ method public androidx.test.uiautomator.UiObject! getChildByDescription(androidx.test.uiautomator.UiSelector!, String!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getChildByInstance(androidx.test.uiautomator.UiSelector!, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getChildByText(androidx.test.uiautomator.UiSelector!, String!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getChildCount(androidx.test.uiautomator.UiSelector!);
+ }
+
+ public class UiDevice {
+ method public void clearLastTraversedText();
+ method public boolean click(int, int);
+ method public boolean drag(int, int, int, int, int);
+ method public void dumpWindowHierarchy(java.io.File!) throws java.io.IOException;
+ method public void dumpWindowHierarchy(java.io.OutputStream!) throws java.io.IOException;
+ method @Deprecated public void dumpWindowHierarchy(String!);
+ method public androidx.test.uiautomator.UiObject2! findObject(androidx.test.uiautomator.BySelector!);
+ method public androidx.test.uiautomator.UiObject! findObject(androidx.test.uiautomator.UiSelector!);
+ method public java.util.List<androidx.test.uiautomator.UiObject2!>! findObjects(androidx.test.uiautomator.BySelector!);
+ method public void freezeRotation() throws android.os.RemoteException;
+ method @Deprecated public String! getCurrentActivityName();
+ method public String! getCurrentPackageName();
+ method public int getDisplayHeight();
+ method public int getDisplayRotation();
+ method public android.graphics.Point! getDisplaySizeDp();
+ method public int getDisplayWidth();
+ method @Deprecated public static androidx.test.uiautomator.UiDevice! getInstance();
+ method public static androidx.test.uiautomator.UiDevice! getInstance(android.app.Instrumentation!);
+ method public String! getLastTraversedText();
+ method public String! getLauncherPackageName();
+ method public String! getProductName();
+ method public boolean hasAnyWatcherTriggered();
+ method public boolean hasObject(androidx.test.uiautomator.BySelector!);
+ method public boolean hasWatcherTriggered(String!);
+ method public boolean isNaturalOrientation();
+ method public boolean isScreenOn() throws android.os.RemoteException;
+ method public boolean openNotification();
+ method public boolean openQuickSettings();
+ method public <R> R! performActionAndWait(Runnable!, androidx.test.uiautomator.EventCondition<R!>!, long);
+ method public boolean pressBack();
+ method public boolean pressDPadCenter();
+ method public boolean pressDPadDown();
+ method public boolean pressDPadLeft();
+ method public boolean pressDPadRight();
+ method public boolean pressDPadUp();
+ method public boolean pressDelete();
+ method public boolean pressEnter();
+ method public boolean pressHome();
+ method public boolean pressKeyCode(int);
+ method public boolean pressKeyCode(int, int);
+ method public boolean pressMenu();
+ method public boolean pressRecentApps() throws android.os.RemoteException;
+ method public boolean pressSearch();
+ method public void registerWatcher(String!, androidx.test.uiautomator.UiWatcher!);
+ method public void removeWatcher(String!);
+ method public void resetWatcherTriggers();
+ method public void runWatchers();
+ method public void setCompressedLayoutHeirarchy(boolean);
+ method public void setOrientationLeft() throws android.os.RemoteException;
+ method public void setOrientationNatural() throws android.os.RemoteException;
+ method public void setOrientationRight() throws android.os.RemoteException;
+ method public void sleep() throws android.os.RemoteException;
+ method public boolean swipe(android.graphics.Point![]!, int);
+ method public boolean swipe(int, int, int, int, int);
+ method public boolean takeScreenshot(java.io.File!);
+ method public boolean takeScreenshot(java.io.File!, float, int);
+ method public void unfreezeRotation() throws android.os.RemoteException;
+ method public <R> R! wait(androidx.test.uiautomator.SearchCondition<R!>!, long);
+ method public void waitForIdle();
+ method public void waitForIdle(long);
+ method public boolean waitForWindowUpdate(String!, long);
+ method public void wakeUp() throws android.os.RemoteException;
+ }
+
+ public class UiObject {
+ ctor @Deprecated public UiObject(androidx.test.uiautomator.UiSelector!);
+ method public void clearTextField() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean click() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickAndWaitForNewWindow() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickAndWaitForNewWindow(long) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickBottomRight() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickTopLeft() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean dragTo(androidx.test.uiautomator.UiObject!, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean dragTo(int, int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean exists();
+ method protected android.view.accessibility.AccessibilityNodeInfo! findAccessibilityNodeInfo(long);
+ method public android.graphics.Rect! getBounds() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getChild(androidx.test.uiautomator.UiSelector!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getChildCount() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String! getClassName() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String! getContentDescription() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getFromParent(androidx.test.uiautomator.UiSelector!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String! getPackageName() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public final androidx.test.uiautomator.UiSelector! getSelector();
+ method public String! getText() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public android.graphics.Rect! getVisibleBounds() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isCheckable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isChecked() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isClickable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isEnabled() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isFocusable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isFocused() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isLongClickable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isScrollable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isSelected() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClick() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClickBottomRight() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClickTopLeft() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean performMultiPointerGesture(android.view.MotionEvent.PointerCoords![]!...);
+ method public boolean performTwoPointerGesture(android.graphics.Point!, android.graphics.Point!, android.graphics.Point!, android.graphics.Point!, int);
+ method public boolean pinchIn(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean pinchOut(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean setText(String!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeDown(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeLeft(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeRight(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeUp(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean waitForExists(long);
+ method public boolean waitUntilGone(long);
+ field protected static final int FINGER_TOUCH_HALF_WIDTH = 20; // 0x14
+ field protected static final int SWIPE_MARGIN_LIMIT = 5; // 0x5
+ field @Deprecated protected static final long WAIT_FOR_EVENT_TMEOUT = 3000L; // 0xbb8L
+ field protected static final long WAIT_FOR_SELECTOR_POLL = 1000L; // 0x3e8L
+ field @Deprecated protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10000L; // 0x2710L
+ field protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500L; // 0x157cL
+ }
+
+ public class UiObject2 {
+ method public void clear();
+ method public void click();
+ method public void click(long);
+ method public <R> R! clickAndWait(androidx.test.uiautomator.EventCondition<R!>!, long);
+ method public void drag(android.graphics.Point!);
+ method public void drag(android.graphics.Point!, int);
+ method public androidx.test.uiautomator.UiObject2! findObject(androidx.test.uiautomator.BySelector!);
+ method public java.util.List<androidx.test.uiautomator.UiObject2!>! findObjects(androidx.test.uiautomator.BySelector!);
+ method public boolean fling(androidx.test.uiautomator.Direction!);
+ method public boolean fling(androidx.test.uiautomator.Direction!, int);
+ method public String! getApplicationPackage();
+ method public int getChildCount();
+ method public java.util.List<androidx.test.uiautomator.UiObject2!>! getChildren();
+ method public String! getClassName();
+ method public String! getContentDescription();
+ method public androidx.test.uiautomator.UiObject2! getParent();
+ method public String! getResourceName();
+ method public String! getText();
+ method public android.graphics.Rect! getVisibleBounds();
+ method public android.graphics.Point! getVisibleCenter();
+ method public boolean hasObject(androidx.test.uiautomator.BySelector!);
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isLongClickable();
+ method public boolean isScrollable();
+ method public boolean isSelected();
+ method public void longClick();
+ method public void pinchClose(float);
+ method public void pinchClose(float, int);
+ method public void pinchOpen(float);
+ method public void pinchOpen(float, int);
+ method public void recycle();
+ method public boolean scroll(androidx.test.uiautomator.Direction!, float);
+ method public boolean scroll(androidx.test.uiautomator.Direction!, float, int);
+ method public void setGestureMargin(int);
+ method public void setGestureMargins(int, int, int, int);
+ method public void setText(String!);
+ method public void swipe(androidx.test.uiautomator.Direction!, float);
+ method public void swipe(androidx.test.uiautomator.Direction!, float, int);
+ method public <R> R! wait(androidx.test.uiautomator.SearchCondition<R!>!, long);
+ method public <R> R! wait(androidx.test.uiautomator.UiObject2Condition<R!>!, long);
+ }
+
+ public abstract class UiObject2Condition<R> {
+ ctor public UiObject2Condition();
+ }
+
+ public class UiObjectNotFoundException extends java.lang.Exception {
+ ctor public UiObjectNotFoundException(String!);
+ ctor public UiObjectNotFoundException(String!, Throwable!);
+ ctor public UiObjectNotFoundException(Throwable!);
+ }
+
+ public class UiScrollable extends androidx.test.uiautomator.UiCollection {
+ ctor public UiScrollable(androidx.test.uiautomator.UiSelector!);
+ method protected boolean exists(androidx.test.uiautomator.UiSelector!);
+ method public boolean flingBackward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingForward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingToBeginning(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingToEnd(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getChildByDescription(androidx.test.uiautomator.UiSelector!, String!, boolean) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getChildByText(androidx.test.uiautomator.UiSelector!, String!, boolean) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getMaxSearchSwipes();
+ method public double getSwipeDeadZonePercentage();
+ method public boolean scrollBackward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollBackward(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollDescriptionIntoView(String!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollForward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollForward(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollIntoView(androidx.test.uiautomator.UiObject!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollIntoView(androidx.test.uiautomator.UiSelector!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollTextIntoView(String!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToBeginning(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToBeginning(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToEnd(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToEnd(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiScrollable! setAsHorizontalList();
+ method public androidx.test.uiautomator.UiScrollable! setAsVerticalList();
+ method public androidx.test.uiautomator.UiScrollable! setMaxSearchSwipes(int);
+ method public androidx.test.uiautomator.UiScrollable! setSwipeDeadZonePercentage(double);
+ }
+
+ public class UiSelector {
+ ctor public UiSelector();
+ method public androidx.test.uiautomator.UiSelector! checkable(boolean);
+ method public androidx.test.uiautomator.UiSelector! checked(boolean);
+ method public androidx.test.uiautomator.UiSelector! childSelector(androidx.test.uiautomator.UiSelector!);
+ method public <T> androidx.test.uiautomator.UiSelector! className(Class<T!>!);
+ method public androidx.test.uiautomator.UiSelector! className(String!);
+ method public androidx.test.uiautomator.UiSelector! classNameMatches(String!);
+ method public androidx.test.uiautomator.UiSelector! clickable(boolean);
+ method protected androidx.test.uiautomator.UiSelector! cloneSelector();
+ method public androidx.test.uiautomator.UiSelector! description(String!);
+ method public androidx.test.uiautomator.UiSelector! descriptionContains(String!);
+ method public androidx.test.uiautomator.UiSelector! descriptionMatches(String!);
+ method public androidx.test.uiautomator.UiSelector! descriptionStartsWith(String!);
+ method public androidx.test.uiautomator.UiSelector! enabled(boolean);
+ method public androidx.test.uiautomator.UiSelector! focusable(boolean);
+ method public androidx.test.uiautomator.UiSelector! focused(boolean);
+ method public androidx.test.uiautomator.UiSelector! fromParent(androidx.test.uiautomator.UiSelector!);
+ method public androidx.test.uiautomator.UiSelector! index(int);
+ method public androidx.test.uiautomator.UiSelector! instance(int);
+ method public androidx.test.uiautomator.UiSelector! longClickable(boolean);
+ method public androidx.test.uiautomator.UiSelector! packageName(String!);
+ method public androidx.test.uiautomator.UiSelector! packageNameMatches(String!);
+ method public androidx.test.uiautomator.UiSelector! resourceId(String!);
+ method public androidx.test.uiautomator.UiSelector! resourceIdMatches(String!);
+ method public androidx.test.uiautomator.UiSelector! scrollable(boolean);
+ method public androidx.test.uiautomator.UiSelector! selected(boolean);
+ method public androidx.test.uiautomator.UiSelector! text(String!);
+ method public androidx.test.uiautomator.UiSelector! textContains(String!);
+ method public androidx.test.uiautomator.UiSelector! textMatches(String!);
+ method public androidx.test.uiautomator.UiSelector! textStartsWith(String!);
+ }
+
+ public interface UiWatcher {
+ method public boolean checkForCondition();
+ }
+
+ public class Until {
+ ctor public Until();
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! checkable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! checked(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! clickable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descContains(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descEndsWith(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descEquals(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descMatches(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descMatches(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descStartsWith(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! enabled(boolean);
+ method public static androidx.test.uiautomator.SearchCondition<androidx.test.uiautomator.UiObject2!>! findObject(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.SearchCondition<java.util.List<androidx.test.uiautomator.UiObject2!>!>! findObjects(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! focusable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! focused(boolean);
+ method public static androidx.test.uiautomator.SearchCondition<java.lang.Boolean!>! gone(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.SearchCondition<java.lang.Boolean!>! hasObject(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! longClickable(boolean);
+ method public static androidx.test.uiautomator.EventCondition<java.lang.Boolean!>! newWindow();
+ method public static androidx.test.uiautomator.EventCondition<java.lang.Boolean!>! scrollFinished(androidx.test.uiautomator.Direction!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! scrollable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! selected(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textContains(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textEndsWith(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textEquals(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textMatches(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textMatches(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textNotEquals(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textStartsWith(String!);
+ }
+
+}
+
diff --git a/test/uiautomator/uiautomator/api/api_lint.ignore b/test/uiautomator/uiautomator/api/api_lint.ignore
index d212104..1c65a590 100644
--- a/test/uiautomator/uiautomator/api/api_lint.ignore
+++ b/test/uiautomator/uiautomator/api/api_lint.ignore
@@ -39,12 +39,6 @@
Percentage must use ints, was `double` in `getSwipeDeadZonePercentage`
-ReferencesDeprecated: androidx.test.uiautomator.UiAutomatorInstrumentationTestRunner#getAndroidTestRunner():
- Return type of deprecated type android.test.AndroidTestRunner in androidx.test.uiautomator.UiAutomatorInstrumentationTestRunner.getAndroidTestRunner(): this method should also be deprecated
-ReferencesDeprecated: androidx.test.uiautomator.UiAutomatorInstrumentationTestRunner#initializeUiAutomatorTest(androidx.test.uiautomator.UiAutomatorTestCase):
- Parameter of deprecated type androidx.test.uiautomator.UiAutomatorTestCase in androidx.test.uiautomator.UiAutomatorInstrumentationTestRunner.initializeUiAutomatorTest(): this method should also be deprecated
-
-
StreamFiles: androidx.test.uiautomator.UiDevice#takeScreenshot(java.io.File):
Methods accepting `File` should also accept `FileDescriptor` or streams: method androidx.test.uiautomator.UiDevice.takeScreenshot(java.io.File)
StreamFiles: androidx.test.uiautomator.UiDevice#takeScreenshot(java.io.File, float, int):
diff --git a/test/uiautomator/uiautomator/api/current.ignore b/test/uiautomator/uiautomator/api/current.ignore
new file mode 100644
index 0000000..42f04c9
--- /dev/null
+++ b/test/uiautomator/uiautomator/api/current.ignore
@@ -0,0 +1,13 @@
+// Baseline format: 1.0
+AddedAbstractMethod: androidx.test.uiautomator.EventCondition#getResult():
+ Added method androidx.test.uiautomator.EventCondition.getResult()
+
+
+RemovedMethod: androidx.test.uiautomator.UiDevice#wait(androidx.test.uiautomator.SearchCondition<R>, long):
+ Removed method androidx.test.uiautomator.UiDevice.wait(androidx.test.uiautomator.SearchCondition<R>,long)
+RemovedMethod: androidx.test.uiautomator.UiObject2#wait(androidx.test.uiautomator.SearchCondition<R>, long):
+ Removed method androidx.test.uiautomator.UiObject2.wait(androidx.test.uiautomator.SearchCondition<R>,long)
+RemovedMethod: androidx.test.uiautomator.UiObject2#wait(androidx.test.uiautomator.UiObject2Condition<R>, long):
+ Removed method androidx.test.uiautomator.UiObject2.wait(androidx.test.uiautomator.UiObject2Condition<R>,long)
+RemovedMethod: androidx.test.uiautomator.Until#Until():
+ Removed constructor androidx.test.uiautomator.Until()
diff --git a/test/uiautomator/uiautomator/api/res-2.2.0.txt b/test/uiautomator/uiautomator/api/res-2.2.0.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/uiautomator/uiautomator/api/res-2.2.0.txt
diff --git a/test/uiautomator/uiautomator/api/restricted_2.2.0.txt b/test/uiautomator/uiautomator/api/restricted_2.2.0.txt
new file mode 100644
index 0000000..4399b8c
--- /dev/null
+++ b/test/uiautomator/uiautomator/api/restricted_2.2.0.txt
@@ -0,0 +1,417 @@
+// Signature format: 4.0
+package androidx.test.uiautomator {
+
+ public class By {
+ method public static androidx.test.uiautomator.BySelector! checkable(boolean);
+ method public static androidx.test.uiautomator.BySelector! checked(boolean);
+ method public static androidx.test.uiautomator.BySelector! clazz(Class!);
+ method public static androidx.test.uiautomator.BySelector! clazz(String!);
+ method public static androidx.test.uiautomator.BySelector! clazz(String!, String!);
+ method public static androidx.test.uiautomator.BySelector! clazz(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.BySelector! clickable(boolean);
+ method public static androidx.test.uiautomator.BySelector! copy(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.BySelector! depth(int);
+ method public static androidx.test.uiautomator.BySelector! desc(String!);
+ method public static androidx.test.uiautomator.BySelector! desc(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.BySelector! descContains(String!);
+ method public static androidx.test.uiautomator.BySelector! descEndsWith(String!);
+ method public static androidx.test.uiautomator.BySelector! descStartsWith(String!);
+ method public static androidx.test.uiautomator.BySelector! enabled(boolean);
+ method public static androidx.test.uiautomator.BySelector! focusable(boolean);
+ method public static androidx.test.uiautomator.BySelector! focused(boolean);
+ method public static androidx.test.uiautomator.BySelector! hasChild(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.BySelector! hasDescendant(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.BySelector! hasDescendant(androidx.test.uiautomator.BySelector!, int);
+ method public static androidx.test.uiautomator.BySelector! longClickable(boolean);
+ method public static androidx.test.uiautomator.BySelector! pkg(String!);
+ method public static androidx.test.uiautomator.BySelector! pkg(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.BySelector! res(String!);
+ method public static androidx.test.uiautomator.BySelector! res(String!, String!);
+ method public static androidx.test.uiautomator.BySelector! res(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.BySelector! scrollable(boolean);
+ method public static androidx.test.uiautomator.BySelector! selected(boolean);
+ method public static androidx.test.uiautomator.BySelector! text(String!);
+ method public static androidx.test.uiautomator.BySelector! text(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.BySelector! textContains(String!);
+ method public static androidx.test.uiautomator.BySelector! textEndsWith(String!);
+ method public static androidx.test.uiautomator.BySelector! textStartsWith(String!);
+ }
+
+ public class BySelector {
+ method public androidx.test.uiautomator.BySelector! checkable(boolean);
+ method public androidx.test.uiautomator.BySelector! checked(boolean);
+ method public androidx.test.uiautomator.BySelector! clazz(Class!);
+ method public androidx.test.uiautomator.BySelector! clazz(String!);
+ method public androidx.test.uiautomator.BySelector! clazz(String!, String!);
+ method public androidx.test.uiautomator.BySelector! clazz(java.util.regex.Pattern!);
+ method public androidx.test.uiautomator.BySelector! clickable(boolean);
+ method public androidx.test.uiautomator.BySelector! depth(int);
+ method public androidx.test.uiautomator.BySelector! depth(int, int);
+ method public androidx.test.uiautomator.BySelector! desc(String!);
+ method public androidx.test.uiautomator.BySelector! desc(java.util.regex.Pattern!);
+ method public androidx.test.uiautomator.BySelector! descContains(String!);
+ method public androidx.test.uiautomator.BySelector! descEndsWith(String!);
+ method public androidx.test.uiautomator.BySelector! descStartsWith(String!);
+ method public androidx.test.uiautomator.BySelector! enabled(boolean);
+ method public androidx.test.uiautomator.BySelector! focusable(boolean);
+ method public androidx.test.uiautomator.BySelector! focused(boolean);
+ method public androidx.test.uiautomator.BySelector! hasChild(androidx.test.uiautomator.BySelector!);
+ method public androidx.test.uiautomator.BySelector! hasDescendant(androidx.test.uiautomator.BySelector!);
+ method public androidx.test.uiautomator.BySelector! hasDescendant(androidx.test.uiautomator.BySelector!, int);
+ method public androidx.test.uiautomator.BySelector! longClickable(boolean);
+ method public androidx.test.uiautomator.BySelector! maxDepth(int);
+ method public androidx.test.uiautomator.BySelector! minDepth(int);
+ method public androidx.test.uiautomator.BySelector! pkg(String!);
+ method public androidx.test.uiautomator.BySelector! pkg(java.util.regex.Pattern!);
+ method public androidx.test.uiautomator.BySelector! res(String!);
+ method public androidx.test.uiautomator.BySelector! res(String!, String!);
+ method public androidx.test.uiautomator.BySelector! res(java.util.regex.Pattern!);
+ method public androidx.test.uiautomator.BySelector! scrollable(boolean);
+ method public androidx.test.uiautomator.BySelector! selected(boolean);
+ method public androidx.test.uiautomator.BySelector! text(String!);
+ method public androidx.test.uiautomator.BySelector! text(java.util.regex.Pattern!);
+ method public androidx.test.uiautomator.BySelector! textContains(String!);
+ method public androidx.test.uiautomator.BySelector! textEndsWith(String!);
+ method public androidx.test.uiautomator.BySelector! textStartsWith(String!);
+ }
+
+ public final class Configurator {
+ method public long getActionAcknowledgmentTimeout();
+ method public static androidx.test.uiautomator.Configurator! getInstance();
+ method public long getKeyInjectionDelay();
+ method public long getScrollAcknowledgmentTimeout();
+ method public int getToolType();
+ method public int getUiAutomationFlags();
+ method public long getWaitForIdleTimeout();
+ method public long getWaitForSelectorTimeout();
+ method public androidx.test.uiautomator.Configurator! setActionAcknowledgmentTimeout(long);
+ method public androidx.test.uiautomator.Configurator! setKeyInjectionDelay(long);
+ method public androidx.test.uiautomator.Configurator! setScrollAcknowledgmentTimeout(long);
+ method public androidx.test.uiautomator.Configurator! setToolType(int);
+ method public androidx.test.uiautomator.Configurator! setUiAutomationFlags(int);
+ method public androidx.test.uiautomator.Configurator! setWaitForIdleTimeout(long);
+ method public androidx.test.uiautomator.Configurator! setWaitForSelectorTimeout(long);
+ }
+
+ public enum Direction {
+ method public static androidx.test.uiautomator.Direction! reverse(androidx.test.uiautomator.Direction!);
+ enum_constant public static final androidx.test.uiautomator.Direction DOWN;
+ enum_constant public static final androidx.test.uiautomator.Direction LEFT;
+ enum_constant public static final androidx.test.uiautomator.Direction RIGHT;
+ enum_constant public static final androidx.test.uiautomator.Direction UP;
+ }
+
+ public abstract class EventCondition<R> {
+ ctor public EventCondition();
+ }
+
+ public interface IAutomationSupport {
+ method public void sendStatus(int, android.os.Bundle!);
+ }
+
+ public abstract class SearchCondition<R> {
+ ctor public SearchCondition();
+ }
+
+ public class StaleObjectException extends java.lang.RuntimeException {
+ ctor public StaleObjectException();
+ }
+
+ public class UiAutomatorInstrumentationTestRunner extends android.test.InstrumentationTestRunner {
+ ctor public UiAutomatorInstrumentationTestRunner();
+ method protected android.test.AndroidTestRunner! getAndroidTestRunner();
+ method protected void initializeUiAutomatorTest(androidx.test.uiautomator.UiAutomatorTestCase!);
+ }
+
+ @Deprecated public class UiAutomatorTestCase extends android.test.InstrumentationTestCase {
+ ctor @Deprecated public UiAutomatorTestCase();
+ method @Deprecated public androidx.test.uiautomator.IAutomationSupport! getAutomationSupport();
+ method @Deprecated public android.os.Bundle! getParams();
+ method @Deprecated public androidx.test.uiautomator.UiDevice! getUiDevice();
+ method @Deprecated public void sleep(long);
+ }
+
+ public class UiCollection extends androidx.test.uiautomator.UiObject {
+ ctor public UiCollection(androidx.test.uiautomator.UiSelector!);
+ method public androidx.test.uiautomator.UiObject! getChildByDescription(androidx.test.uiautomator.UiSelector!, String!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getChildByInstance(androidx.test.uiautomator.UiSelector!, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getChildByText(androidx.test.uiautomator.UiSelector!, String!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getChildCount(androidx.test.uiautomator.UiSelector!);
+ }
+
+ public class UiDevice {
+ method public void clearLastTraversedText();
+ method public boolean click(int, int);
+ method public boolean drag(int, int, int, int, int);
+ method public void dumpWindowHierarchy(java.io.File!) throws java.io.IOException;
+ method public void dumpWindowHierarchy(java.io.OutputStream!) throws java.io.IOException;
+ method @Deprecated public void dumpWindowHierarchy(String!);
+ method public androidx.test.uiautomator.UiObject2! findObject(androidx.test.uiautomator.BySelector!);
+ method public androidx.test.uiautomator.UiObject! findObject(androidx.test.uiautomator.UiSelector!);
+ method public java.util.List<androidx.test.uiautomator.UiObject2!>! findObjects(androidx.test.uiautomator.BySelector!);
+ method public void freezeRotation() throws android.os.RemoteException;
+ method @Deprecated public String! getCurrentActivityName();
+ method public String! getCurrentPackageName();
+ method public int getDisplayHeight();
+ method public int getDisplayRotation();
+ method public android.graphics.Point! getDisplaySizeDp();
+ method public int getDisplayWidth();
+ method @Deprecated public static androidx.test.uiautomator.UiDevice! getInstance();
+ method public static androidx.test.uiautomator.UiDevice! getInstance(android.app.Instrumentation!);
+ method public String! getLastTraversedText();
+ method public String! getLauncherPackageName();
+ method public String! getProductName();
+ method public boolean hasAnyWatcherTriggered();
+ method public boolean hasObject(androidx.test.uiautomator.BySelector!);
+ method public boolean hasWatcherTriggered(String!);
+ method public boolean isNaturalOrientation();
+ method public boolean isScreenOn() throws android.os.RemoteException;
+ method public boolean openNotification();
+ method public boolean openQuickSettings();
+ method public <R> R! performActionAndWait(Runnable!, androidx.test.uiautomator.EventCondition<R!>!, long);
+ method public boolean pressBack();
+ method public boolean pressDPadCenter();
+ method public boolean pressDPadDown();
+ method public boolean pressDPadLeft();
+ method public boolean pressDPadRight();
+ method public boolean pressDPadUp();
+ method public boolean pressDelete();
+ method public boolean pressEnter();
+ method public boolean pressHome();
+ method public boolean pressKeyCode(int);
+ method public boolean pressKeyCode(int, int);
+ method public boolean pressMenu();
+ method public boolean pressRecentApps() throws android.os.RemoteException;
+ method public boolean pressSearch();
+ method public void registerWatcher(String!, androidx.test.uiautomator.UiWatcher!);
+ method public void removeWatcher(String!);
+ method public void resetWatcherTriggers();
+ method public void runWatchers();
+ method public void setCompressedLayoutHeirarchy(boolean);
+ method public void setOrientationLeft() throws android.os.RemoteException;
+ method public void setOrientationNatural() throws android.os.RemoteException;
+ method public void setOrientationRight() throws android.os.RemoteException;
+ method public void sleep() throws android.os.RemoteException;
+ method public boolean swipe(android.graphics.Point![]!, int);
+ method public boolean swipe(int, int, int, int, int);
+ method public boolean takeScreenshot(java.io.File!);
+ method public boolean takeScreenshot(java.io.File!, float, int);
+ method public void unfreezeRotation() throws android.os.RemoteException;
+ method public <R> R! wait(androidx.test.uiautomator.SearchCondition<R!>!, long);
+ method public void waitForIdle();
+ method public void waitForIdle(long);
+ method public boolean waitForWindowUpdate(String!, long);
+ method public void wakeUp() throws android.os.RemoteException;
+ }
+
+ public class UiObject {
+ ctor @Deprecated public UiObject(androidx.test.uiautomator.UiSelector!);
+ method public void clearTextField() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean click() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickAndWaitForNewWindow() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickAndWaitForNewWindow(long) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickBottomRight() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickTopLeft() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean dragTo(androidx.test.uiautomator.UiObject!, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean dragTo(int, int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean exists();
+ method protected android.view.accessibility.AccessibilityNodeInfo! findAccessibilityNodeInfo(long);
+ method public android.graphics.Rect! getBounds() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getChild(androidx.test.uiautomator.UiSelector!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getChildCount() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String! getClassName() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String! getContentDescription() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getFromParent(androidx.test.uiautomator.UiSelector!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String! getPackageName() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public final androidx.test.uiautomator.UiSelector! getSelector();
+ method public String! getText() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public android.graphics.Rect! getVisibleBounds() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isCheckable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isChecked() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isClickable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isEnabled() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isFocusable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isFocused() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isLongClickable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isScrollable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isSelected() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClick() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClickBottomRight() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClickTopLeft() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean performMultiPointerGesture(android.view.MotionEvent.PointerCoords![]!...);
+ method public boolean performTwoPointerGesture(android.graphics.Point!, android.graphics.Point!, android.graphics.Point!, android.graphics.Point!, int);
+ method public boolean pinchIn(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean pinchOut(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean setText(String!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeDown(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeLeft(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeRight(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeUp(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean waitForExists(long);
+ method public boolean waitUntilGone(long);
+ field protected static final int FINGER_TOUCH_HALF_WIDTH = 20; // 0x14
+ field protected static final int SWIPE_MARGIN_LIMIT = 5; // 0x5
+ field @Deprecated protected static final long WAIT_FOR_EVENT_TMEOUT = 3000L; // 0xbb8L
+ field protected static final long WAIT_FOR_SELECTOR_POLL = 1000L; // 0x3e8L
+ field @Deprecated protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10000L; // 0x2710L
+ field protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500L; // 0x157cL
+ }
+
+ public class UiObject2 {
+ method public void clear();
+ method public void click();
+ method public void click(long);
+ method public <R> R! clickAndWait(androidx.test.uiautomator.EventCondition<R!>!, long);
+ method public void drag(android.graphics.Point!);
+ method public void drag(android.graphics.Point!, int);
+ method public androidx.test.uiautomator.UiObject2! findObject(androidx.test.uiautomator.BySelector!);
+ method public java.util.List<androidx.test.uiautomator.UiObject2!>! findObjects(androidx.test.uiautomator.BySelector!);
+ method public boolean fling(androidx.test.uiautomator.Direction!);
+ method public boolean fling(androidx.test.uiautomator.Direction!, int);
+ method public String! getApplicationPackage();
+ method public int getChildCount();
+ method public java.util.List<androidx.test.uiautomator.UiObject2!>! getChildren();
+ method public String! getClassName();
+ method public String! getContentDescription();
+ method public androidx.test.uiautomator.UiObject2! getParent();
+ method public String! getResourceName();
+ method public String! getText();
+ method public android.graphics.Rect! getVisibleBounds();
+ method public android.graphics.Point! getVisibleCenter();
+ method public boolean hasObject(androidx.test.uiautomator.BySelector!);
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isLongClickable();
+ method public boolean isScrollable();
+ method public boolean isSelected();
+ method public void longClick();
+ method public void pinchClose(float);
+ method public void pinchClose(float, int);
+ method public void pinchOpen(float);
+ method public void pinchOpen(float, int);
+ method public void recycle();
+ method public boolean scroll(androidx.test.uiautomator.Direction!, float);
+ method public boolean scroll(androidx.test.uiautomator.Direction!, float, int);
+ method public void setGestureMargin(int);
+ method public void setGestureMargins(int, int, int, int);
+ method public void setText(String!);
+ method public void swipe(androidx.test.uiautomator.Direction!, float);
+ method public void swipe(androidx.test.uiautomator.Direction!, float, int);
+ method public <R> R! wait(androidx.test.uiautomator.SearchCondition<R!>!, long);
+ method public <R> R! wait(androidx.test.uiautomator.UiObject2Condition<R!>!, long);
+ }
+
+ public abstract class UiObject2Condition<R> {
+ ctor public UiObject2Condition();
+ }
+
+ public class UiObjectNotFoundException extends java.lang.Exception {
+ ctor public UiObjectNotFoundException(String!);
+ ctor public UiObjectNotFoundException(String!, Throwable!);
+ ctor public UiObjectNotFoundException(Throwable!);
+ }
+
+ public class UiScrollable extends androidx.test.uiautomator.UiCollection {
+ ctor public UiScrollable(androidx.test.uiautomator.UiSelector!);
+ method protected boolean exists(androidx.test.uiautomator.UiSelector!);
+ method public boolean flingBackward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingForward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingToBeginning(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingToEnd(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getChildByDescription(androidx.test.uiautomator.UiSelector!, String!, boolean) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject! getChildByText(androidx.test.uiautomator.UiSelector!, String!, boolean) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getMaxSearchSwipes();
+ method public double getSwipeDeadZonePercentage();
+ method public boolean scrollBackward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollBackward(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollDescriptionIntoView(String!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollForward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollForward(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollIntoView(androidx.test.uiautomator.UiObject!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollIntoView(androidx.test.uiautomator.UiSelector!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollTextIntoView(String!) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToBeginning(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToBeginning(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToEnd(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToEnd(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiScrollable! setAsHorizontalList();
+ method public androidx.test.uiautomator.UiScrollable! setAsVerticalList();
+ method public androidx.test.uiautomator.UiScrollable! setMaxSearchSwipes(int);
+ method public androidx.test.uiautomator.UiScrollable! setSwipeDeadZonePercentage(double);
+ }
+
+ public class UiSelector {
+ ctor public UiSelector();
+ method public androidx.test.uiautomator.UiSelector! checkable(boolean);
+ method public androidx.test.uiautomator.UiSelector! checked(boolean);
+ method public androidx.test.uiautomator.UiSelector! childSelector(androidx.test.uiautomator.UiSelector!);
+ method public <T> androidx.test.uiautomator.UiSelector! className(Class<T!>!);
+ method public androidx.test.uiautomator.UiSelector! className(String!);
+ method public androidx.test.uiautomator.UiSelector! classNameMatches(String!);
+ method public androidx.test.uiautomator.UiSelector! clickable(boolean);
+ method protected androidx.test.uiautomator.UiSelector! cloneSelector();
+ method public androidx.test.uiautomator.UiSelector! description(String!);
+ method public androidx.test.uiautomator.UiSelector! descriptionContains(String!);
+ method public androidx.test.uiautomator.UiSelector! descriptionMatches(String!);
+ method public androidx.test.uiautomator.UiSelector! descriptionStartsWith(String!);
+ method public androidx.test.uiautomator.UiSelector! enabled(boolean);
+ method public androidx.test.uiautomator.UiSelector! focusable(boolean);
+ method public androidx.test.uiautomator.UiSelector! focused(boolean);
+ method public androidx.test.uiautomator.UiSelector! fromParent(androidx.test.uiautomator.UiSelector!);
+ method public androidx.test.uiautomator.UiSelector! index(int);
+ method public androidx.test.uiautomator.UiSelector! instance(int);
+ method public androidx.test.uiautomator.UiSelector! longClickable(boolean);
+ method public androidx.test.uiautomator.UiSelector! packageName(String!);
+ method public androidx.test.uiautomator.UiSelector! packageNameMatches(String!);
+ method public androidx.test.uiautomator.UiSelector! resourceId(String!);
+ method public androidx.test.uiautomator.UiSelector! resourceIdMatches(String!);
+ method public androidx.test.uiautomator.UiSelector! scrollable(boolean);
+ method public androidx.test.uiautomator.UiSelector! selected(boolean);
+ method public androidx.test.uiautomator.UiSelector! text(String!);
+ method public androidx.test.uiautomator.UiSelector! textContains(String!);
+ method public androidx.test.uiautomator.UiSelector! textMatches(String!);
+ method public androidx.test.uiautomator.UiSelector! textStartsWith(String!);
+ }
+
+ public interface UiWatcher {
+ method public boolean checkForCondition();
+ }
+
+ public class Until {
+ ctor public Until();
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! checkable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! checked(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! clickable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descContains(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descEndsWith(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descEquals(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descMatches(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descMatches(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! descStartsWith(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! enabled(boolean);
+ method public static androidx.test.uiautomator.SearchCondition<androidx.test.uiautomator.UiObject2!>! findObject(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.SearchCondition<java.util.List<androidx.test.uiautomator.UiObject2!>!>! findObjects(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! focusable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! focused(boolean);
+ method public static androidx.test.uiautomator.SearchCondition<java.lang.Boolean!>! gone(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.SearchCondition<java.lang.Boolean!>! hasObject(androidx.test.uiautomator.BySelector!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! longClickable(boolean);
+ method public static androidx.test.uiautomator.EventCondition<java.lang.Boolean!>! newWindow();
+ method public static androidx.test.uiautomator.EventCondition<java.lang.Boolean!>! scrollFinished(androidx.test.uiautomator.Direction!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! scrollable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! selected(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textContains(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textEndsWith(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textEquals(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textMatches(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textMatches(java.util.regex.Pattern!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textNotEquals(String!);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!>! textStartsWith(String!);
+ }
+
+}
+
diff --git a/test/uiautomator/uiautomator/api/restricted_current.ignore b/test/uiautomator/uiautomator/api/restricted_current.ignore
new file mode 100644
index 0000000..42f04c9
--- /dev/null
+++ b/test/uiautomator/uiautomator/api/restricted_current.ignore
@@ -0,0 +1,13 @@
+// Baseline format: 1.0
+AddedAbstractMethod: androidx.test.uiautomator.EventCondition#getResult():
+ Added method androidx.test.uiautomator.EventCondition.getResult()
+
+
+RemovedMethod: androidx.test.uiautomator.UiDevice#wait(androidx.test.uiautomator.SearchCondition<R>, long):
+ Removed method androidx.test.uiautomator.UiDevice.wait(androidx.test.uiautomator.SearchCondition<R>,long)
+RemovedMethod: androidx.test.uiautomator.UiObject2#wait(androidx.test.uiautomator.SearchCondition<R>, long):
+ Removed method androidx.test.uiautomator.UiObject2.wait(androidx.test.uiautomator.SearchCondition<R>,long)
+RemovedMethod: androidx.test.uiautomator.UiObject2#wait(androidx.test.uiautomator.UiObject2Condition<R>, long):
+ Removed method androidx.test.uiautomator.UiObject2.wait(androidx.test.uiautomator.UiObject2Condition<R>,long)
+RemovedMethod: androidx.test.uiautomator.Until#Until():
+ Removed constructor androidx.test.uiautomator.Until()
diff --git a/test/uiautomator/uiautomator/lint-baseline.xml b/test/uiautomator/uiautomator/lint-baseline.xml
index a0091eb..a62bf81 100644
--- a/test/uiautomator/uiautomator/lint-baseline.xml
+++ b/test/uiautomator/uiautomator/lint-baseline.xml
@@ -1,14 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1="class AccessibilityNodeInfoDumper {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/test/uiautomator/AccessibilityNodeInfoDumper.java"/>
- </issue>
+<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">
<issue
id="BanHideAnnotation"
@@ -20,33 +11,6 @@
</issue>
<issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void legacySetText(@Nullable String text) throws UiObjectNotFoundException {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/test/uiautomator/UiObject.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public void legacySetText(@Nullable String text) {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/test/uiautomator/UiObject2.java"/>
- </issue>
-
- <issue
- id="BanHideAnnotation"
- message="@hide is not allowed in Javadoc"
- errorLine1=" public boolean ensureFullyVisible(@NonNull UiObject childObject)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/test/uiautomator/UiScrollable.java"/>
- </issue>
-
- <issue
id="BanUncheckedReflection"
message="Calling `Method.invoke` without an SDK check"
errorLine1=" sMotionEvent_setDisplayId.invoke(ev, displayId);"
diff --git a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/AccessibilityNodeInfoDumper.java b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/AccessibilityNodeInfoDumper.java
index a90b0e6..b67734a 100644
--- a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/AccessibilityNodeInfoDumper.java
+++ b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/AccessibilityNodeInfoDumper.java
@@ -29,10 +29,6 @@
import java.io.IOException;
import java.io.OutputStream;
-/**
- *
- * @hide
- */
class AccessibilityNodeInfoDumper {
private AccessibilityNodeInfoDumper() { }
diff --git a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiDevice.java b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiDevice.java
index bea6c94..eeedb1a 100644
--- a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiDevice.java
+++ b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiDevice.java
@@ -1087,7 +1087,7 @@
* @param cmd the command to run
* @return the standard output of the command
* @throws IOException
- * @hide
+ * @hide legacy hidden method, kept for compatibility with existing tests.
*/
@RequiresApi(21)
@NonNull
diff --git a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiObject.java b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiObject.java
index e9a106f..6be203f 100644
--- a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiObject.java
+++ b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiObject.java
@@ -555,37 +555,6 @@
}
/**
- * Set the text content by sending individual key codes.
- * @hide
- */
- public void legacySetText(@Nullable String text) throws UiObjectNotFoundException {
- // Per framework convention, setText(null) means clearing it.
- if (text == null) {
- text = "";
- }
- // long click left + center
- AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
- if (node == null) {
- throw new UiObjectNotFoundException(getSelector().toString());
- }
- Log.d(TAG, String.format("Setting text to '%s'.", text));
- Rect rect = getVisibleBounds(node);
- getInteractionController().longTapNoSync(rect.left + 20, rect.centerY());
- // check if the edit menu is open
- UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all"));
- if (selectAll.waitForExists(50)) {
- selectAll.click();
- }
- // wait for the selection
- SystemClock.sleep(250);
- // delete it
- getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0);
-
- // Send new text
- getInteractionController().sendText(text);
- }
-
- /**
* Sets the text in an editable field, after clearing the field's content.
*
* <p>
diff --git a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiObject2.java b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiObject2.java
index a5ffde7..b3abb55 100644
--- a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiObject2.java
+++ b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiObject2.java
@@ -24,7 +24,6 @@
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Bundle;
-import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
@@ -833,40 +832,6 @@
Until.scrollFinished(direction), FLING_TIMEOUT, swipe);
}
- /**
- * Set the text content by sending individual key codes.
- *
- * @hide
- */
- public void legacySetText(@Nullable String text) {
- AccessibilityNodeInfo node = getAccessibilityNodeInfo();
-
- // Per framework convention, setText(null) means clearing it
- if (text == null) {
- text = "";
- }
-
- Log.d(TAG, String.format("Setting text to '%s'.", text));
- CharSequence currentText = node.getText();
- if (currentText == null || !text.contentEquals(currentText)) {
- InteractionController ic = getDevice().getInteractionController();
-
- // Long click left + center
- Rect rect = getVisibleBounds();
- ic.longTapNoSync(rect.left + 20, rect.centerY());
-
- // Select existing text
- getDevice().wait(Until.findObject(By.descContains("Select all")), 50).click();
- // Wait for the selection
- SystemClock.sleep(250);
- // Delete it
- ic.sendKey(KeyEvent.KEYCODE_DEL, 0);
-
- // Send new text
- ic.sendText(text);
- }
- }
-
/** Sets this object's text content if it is an editable field. */
public void setText(@Nullable String text) {
AccessibilityNodeInfo node = getAccessibilityNodeInfo();
diff --git a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiScrollable.java b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiScrollable.java
index 8473756..f973a64 100644
--- a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiScrollable.java
+++ b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiScrollable.java
@@ -270,51 +270,6 @@
}
/**
- * Scrolls forward until the UiObject is fully visible in the scrollable container.
- * Use this method to make sure that the child item's edges are not offscreen.
- *
- * @param childObject {@link UiObject} representing the child element
- * @return true if the child element is already fully visible, or
- * if the method scrolled successfully until the child became fully visible;
- * otherwise, false if the attempt to scroll failed.
- * @throws UiObjectNotFoundException
- * @hide
- */
- public boolean ensureFullyVisible(@NonNull UiObject childObject)
- throws UiObjectNotFoundException {
- Log.d(TAG, String.format("Ensuring %s is fully visible.", childObject.getSelector()));
- Rect actual = childObject.getBounds();
- Rect visible = childObject.getVisibleBounds();
- if (visible.width() * visible.height() == actual.width() * actual.height()) {
- // area match, item fully visible
- return true;
- }
- boolean shouldSwipeForward = false;
- if (mIsVerticalList) {
- // if list is vertical, matching top edge implies obscured bottom edge
- // so we need to scroll list forward
- shouldSwipeForward = actual.top == visible.top;
- } else {
- // if list is horizontal, matching left edge implies obscured right edge,
- // so we need to scroll list forward
- shouldSwipeForward = actual.left == visible.left;
- }
- if (mIsVerticalList) {
- if (shouldSwipeForward) {
- return swipeUp(10);
- } else {
- return swipeDown(10);
- }
- } else {
- if (shouldSwipeForward) {
- return swipeLeft(10);
- } else {
- return swipeRight(10);
- }
- }
- }
-
- /**
* Performs a forward scroll action on the scrollable layout element until
* the text you provided is visible, or until swipe attempts have been exhausted.
* See {@link #setMaxSearchSwipes(int)}
diff --git a/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/FailureMetadata.kt b/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/FailureMetadata.kt
index e966b77..13650be 100644
--- a/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/FailureMetadata.kt
+++ b/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/FailureMetadata.kt
@@ -23,13 +23,6 @@
fun withMessage(messageToPrepend: String): FailureMetadata =
copy(messagesToPrepend = messagesToPrepend + messageToPrepend)
- fun formatMessage(message: String? = null): String {
- val messages = if (message == null) messagesToPrepend else messagesToPrepend + message
-
- return when {
- messages.isEmpty() -> message ?: ""
- messages.size == 1 -> messages.single()
- else -> messages.joinToString(separator = ". ", postfix = ".")
- }
- }
+ fun formatMessage(vararg messages: String?): String =
+ (messagesToPrepend + messages.filterNotNull()).joinToString(separator = "\n")
}
diff --git a/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/KruthAsserter.kt b/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/KruthAsserter.kt
index 9964628..cfca771 100644
--- a/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/KruthAsserter.kt
+++ b/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/KruthAsserter.kt
@@ -41,7 +41,10 @@
*/
fun assertTrue(actual: Boolean, message: String? = null) {
contract { returns() implies actual }
- kotlin.test.assertTrue(actual = actual, message = formatMessage(message))
+
+ if (!actual) {
+ fail(message)
+ }
}
/**
@@ -51,7 +54,10 @@
*/
fun assertFalse(actual: Boolean, message: String? = null) {
contract { returns() implies !actual }
- kotlin.test.assertFalse(actual = actual, message = formatMessage(message))
+
+ if (actual) {
+ fail(message)
+ }
}
/**
@@ -60,11 +66,7 @@
* @param message the message to report if the assertion fails.
*/
fun assertEquals(expected: Any?, actual: Any?, message: String? = null) {
- kotlin.test.assertEquals(
- expected = expected,
- actual = actual,
- message = formatMessage(message),
- )
+ assertTrue(expected == actual, message)
}
/**
@@ -73,11 +75,7 @@
* @param message the message to report if the assertion fails.
*/
fun assertNotEquals(illegal: Any?, actual: Any?, message: String? = null) {
- kotlin.test.assertNotEquals(
- illegal = illegal,
- actual = actual,
- message = formatMessage(message),
- )
+ assertFalse(illegal == actual, message)
}
/**
@@ -87,7 +85,7 @@
*/
fun assertNull(actual: Any?, message: String? = null) {
contract { returns() implies (actual == null) }
- kotlin.test.assertNull(actual = actual, message = formatMessage(message))
+ assertTrue(actual == null, message)
}
/**
@@ -97,8 +95,8 @@
*/
fun <T : Any> assertNotNull(actual: T?, message: String? = null): T {
contract { returns() implies (actual != null) }
- kotlin.test.assertNotNull(actual = actual, message = formatMessage(message))
+ assertFalse(actual == null, message)
- return requireNonNull(actual)
+ return actual
}
}
\ No newline at end of file
diff --git a/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/MapSubject.kt b/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/MapSubject.kt
index 8cc9fe9..621abee 100644
--- a/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/MapSubject.kt
+++ b/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/MapSubject.kt
@@ -35,4 +35,40 @@
asserter.fail("Expected to contain $key, but was ${actual.keys}")
}
}
+
+ /** Fails if the map does not contain exactly the given set of entries in the given map. */
+ fun containsExactlyEntriesIn(expectedMap: Map<K, V>): Ordered {
+ requireNonNull(actual) { "Expected $expectedMap, but was null" }
+
+ if (expectedMap.isEmpty()) {
+ isEmpty()
+ } else if ((expectedMap.entries - actual.entries).isNotEmpty()) {
+ asserter.fail("Expected $expectedMap, but was $actual")
+ }
+
+ return MapInOrder(expectedMap)
+ }
+
+ private inner class MapInOrder(
+ private val expectedMap: Map<*, *>,
+ ) : Ordered {
+
+ /**
+ * Checks whether the common elements between actual and expected are in the same order.
+ *
+ * This doesn't check whether the keys have the same values or whether all the required keys
+ * are actually present. That was supposed to be done before the "in order" part.
+ */
+ override fun inOrder() {
+ // We're using the fact that Iterable#intersect keeps the order of the first set.
+ checkNotNull(actual)
+ val expectedKeyOrder = (expectedMap.keys intersect actual.keys).toList()
+ val actualKeyOrder = (actual.keys intersect expectedMap.keys).toList()
+ if (actualKeyOrder != expectedKeyOrder) {
+ asserter.fail(
+ "Entries match, but order was wrong. Expected $expectedMap, but was $actual",
+ )
+ }
+ }
+ }
}
diff --git a/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/Subject.kt b/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/Subject.kt
index 12f59e3..0a0a184 100644
--- a/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/Subject.kt
+++ b/testutils/testutils-kmp/src/commonMain/kotlin/androidx/kruth/Subject.kt
@@ -33,7 +33,30 @@
private val metadata: FailureMetadata = FailureMetadata(),
) {
- internal val asserter: KruthAsserter = KruthAsserter(formatMessage = metadata::formatMessage)
+ internal val asserter: KruthAsserter get() = asserter()
+
+ internal fun asserter(withActual: Boolean = false): KruthAsserter =
+ KruthAsserter(
+ formatMessage = { message ->
+ formatFailureMessage(message = message, withActual = withActual)
+ },
+ )
+
+ private fun formatFailureMessage(message: String?, withActual: Boolean): String =
+ if (withActual) {
+ val actualString = actual.toString()
+ if ('\n' in actualString) {
+ metadata.formatMessage(
+ message,
+ "But was:",
+ actual.toString().prependIndent(),
+ )
+ } else {
+ metadata.formatMessage(message, "But was: $actualString")
+ }
+ } else {
+ metadata.formatMessage(message)
+ }
/**
* Fails if the subject is not null.
@@ -118,6 +141,10 @@
}
}
+ protected fun failWithActual(vararg messages: String): Nothing {
+ asserter(withActual = true).fail(messages.joinToString(separator = "\n"))
+ }
+
@PublishedApi
internal fun doFail(message: String) {
asserter.fail(message = message)
diff --git a/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/KruthAsserterTest.kt b/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/KruthAsserterTest.kt
new file mode 100644
index 0000000..bce09ef
--- /dev/null
+++ b/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/KruthAsserterTest.kt
@@ -0,0 +1,103 @@
+/*
+ * 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
+
+class KruthAsserterTest {
+
+ private val asserter = KruthAsserter(formatMessage = { "$it." })
+
+ @Test
+ fun fail() {
+ assertFailsWithMessage("Msg.") {
+ asserter.fail(message = "Msg")
+ }
+ }
+
+ @Test
+ fun assertTrue_success() {
+ asserter.assertTrue(actual = true)
+ }
+
+ @Test
+ fun assertTrue_failsWithMessage() {
+ assertFailsWithMessage("Msg.") {
+ asserter.assertTrue(actual = false, message = "Msg")
+ }
+ }
+
+ @Test
+ fun assertFalse_success() {
+ asserter.assertFalse(actual = false)
+ }
+
+ @Test
+ fun assertFalse_failsWithMessage() {
+ assertFailsWithMessage("Msg.") {
+ asserter.assertFalse(actual = true, message = "Msg")
+ }
+ }
+
+ @Test
+ fun assertEquals_success() {
+ asserter.assertEquals(expected = 0, actual = 0)
+ }
+
+ @Test
+ fun assertEquals_failsWithMessage() {
+ assertFailsWithMessage("Msg.") {
+ asserter.assertEquals(expected = 0, actual = 1, message = "Msg")
+ }
+ }
+
+ @Test
+ fun assertNotEquals_success() {
+ asserter.assertNotEquals(illegal = 0, actual = 1)
+ }
+
+ @Test
+ fun assertNotEquals_failsWithMessage() {
+ assertFailsWithMessage("Msg.") {
+ asserter.assertNotEquals(illegal = 0, actual = 0, message = "Msg")
+ }
+ }
+
+ @Test
+ fun assertNull_success() {
+ asserter.assertNull(actual = null)
+ }
+
+ @Test
+ fun assertNull_failsWithMessage() {
+ assertFailsWithMessage("Msg.") {
+ asserter.assertNull(actual = 0, message = "Msg")
+ }
+ }
+
+ @Test
+ fun assertNotNull_success() {
+ asserter.assertNotNull(actual = 0)
+ }
+
+ @Test
+ fun assertNotNull_failsWithMessage() {
+ assertFailsWithMessage("Msg.") {
+ asserter.assertNotNull(actual = null, message = "Msg")
+ }
+ }
+}
\ No newline at end of file
diff --git a/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/MapSubjectTest.kt b/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/MapSubjectTest.kt
index 98c6288..2b1e879 100644
--- a/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/MapSubjectTest.kt
+++ b/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/MapSubjectTest.kt
@@ -22,6 +22,71 @@
class MapSubjectTest {
@Test
+ fun containsExactlyWithNullKey() {
+ val actual = mapOf<String?, String>(null to "value")
+ assertThat(actual).containsExactlyEntriesIn(actual)
+ assertThat(actual).containsExactlyEntriesIn(actual).inOrder()
+ }
+
+ @Test
+ fun containsExactlyWithNullValue() {
+ val actual = mapOf<String, String?>("key" to null)
+ assertThat(actual).containsExactlyEntriesIn(actual)
+ assertThat(actual).containsExactlyEntriesIn(actual).inOrder()
+ }
+
+ @Test
+ fun containsExactlyEmpty() {
+ val actual = mapOf<String, Int>()
+ assertThat(actual).containsExactlyEntriesIn(actual)
+ assertThat(actual).containsExactlyEntriesIn(actual).inOrder()
+ }
+
+ @Test
+ fun containsExactlyEntriesInEmpty_fails() {
+ assertFailsWith<AssertionError> {
+ assertThat(mapOf("jan" to 1)).containsExactlyEntriesIn(emptyMap())
+ }
+ }
+
+ @Test
+ fun containsExactlyOneEntry() {
+ val actual = mapOf("jan" to 1)
+ assertThat(actual).containsExactlyEntriesIn(actual)
+ assertThat(actual).containsExactlyEntriesIn(actual).inOrder()
+ }
+
+ @Test
+ fun containsExactlyMultipleEntries() {
+ val actual = mapOf("jan" to 1, "feb" to 2, "march" to 3)
+ assertThat(actual).containsExactlyEntriesIn(actual)
+ assertThat(actual).containsExactlyEntriesIn(actual).inOrder()
+ }
+
+ @Test
+ fun containsExactlyNotInOrder() {
+ val actual = mapOf("jan" to 1, "feb" to 2, "march" to 3)
+ assertThat(actual).containsExactlyEntriesIn(actual)
+ assertThat(actual).containsExactlyEntriesIn(actual).inOrder()
+ }
+
+ @Test
+ fun containsExactlyBadNumberOfArgs() {
+ val actual = mapOf("jan" to 1, "feb" to 2, "march" to 3, "april" to 4, "may" to 5)
+ assertThat(actual).containsExactlyEntriesIn(actual)
+ assertThat(actual).containsExactlyEntriesIn(actual).inOrder()
+ }
+
+ @Test
+ fun containsExactlyInOrderWithReversedMap_fails() {
+ assertFailsWith<AssertionError> {
+ assertThat(mutableMapOf("jan" to 1, "feb" to 2, "march" to 3))
+ .containsExactlyEntriesIn(mutableMapOf("march" to 3, "feb" to 2, "jan" to 1))
+ .inOrder()
+ }
+ }
+
+ @Test
fun isEmpty() {
assertThat(mapOf<Any, Any>()).isEmpty()
}
diff --git a/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/SubjectTest.kt b/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/SubjectTest.kt
index daaa879..56b289a 100644
--- a/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/SubjectTest.kt
+++ b/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/SubjectTest.kt
@@ -697,6 +697,54 @@
}
}
+ @Test
+ fun failWithActual_printsAllMessagesPlusActualValue() {
+ val subject =
+ object : Subject<Int>(
+ actual = 0,
+ metadata = FailureMetadata(messagesToPrepend = listOf("msg1", "msg2")),
+ ) {
+ fun fail() {
+ failWithActual("msg3", "msg4")
+ }
+ }
+
+ assertFailsWithMessage(
+ """
+ msg1
+ msg2
+ msg3
+ msg4
+ But was: 0
+ """.trimIndent()
+ ) { subject.fail() }
+ }
+
+ @Test
+ fun failWithActual_printsAllMessagesPlusMultilineActualValue() {
+ val subject =
+ object : Subject<String>(
+ actual = "a\nb",
+ metadata = FailureMetadata(messagesToPrepend = listOf("msg1", "msg2")),
+ ) {
+ fun fail() {
+ failWithActual("msg3", "msg4")
+ }
+ }
+
+ assertFailsWithMessage(
+ """
+ msg1
+ msg2
+ msg3
+ msg4
+ But was:
+ a
+ b
+ """.trimIndent()
+ ) { subject.fail() }
+ }
+
private fun <T> oneShotIterable(vararg values: T): Iterable<T> =
object : Iterable<T> {
private val iterator = values.iterator()
diff --git a/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/TestingUtils.kt b/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/TestingUtils.kt
new file mode 100644
index 0000000..4f9dfa1
--- /dev/null
+++ b/testutils/testutils-kmp/src/commonTest/kotlin/androidx/kruth/TestingUtils.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.assertEquals
+import kotlin.test.fail
+
+internal fun assertFailsWithMessage(message: String, block: () -> Unit) {
+ try {
+ block()
+ fail("Expected to fail but didn't")
+ } catch (e: AssertionError) {
+ assertEquals(expected = message, actual = e.message)
+ }
+}
diff --git a/tracing/tracing-ktx/src/androidTest/java/androidx/tracing/TraceTestKt.kt b/tracing/tracing-ktx/src/androidTest/java/androidx/tracing/TraceTestKt.kt
index f192bb3..850d56a 100644
--- a/tracing/tracing-ktx/src/androidTest/java/androidx/tracing/TraceTestKt.kt
+++ b/tracing/tracing-ktx/src/androidTest/java/androidx/tracing/TraceTestKt.kt
@@ -37,6 +37,13 @@
}
@Test
+ fun testNoCrossInline() {
+ trace("Test") {
+ return
+ }
+ }
+
+ @Test
fun traceLazyTest() {
assertFalse(
"This test expects to be run without tracing enabled in this process",
diff --git a/tracing/tracing-ktx/src/main/java/androidx/tracing/Trace.kt b/tracing/tracing-ktx/src/main/java/androidx/tracing/Trace.kt
index 27e9196..1affd9e 100644
--- a/tracing/tracing-ktx/src/main/java/androidx/tracing/Trace.kt
+++ b/tracing/tracing-ktx/src/main/java/androidx/tracing/Trace.kt
@@ -23,7 +23,7 @@
* @param label A name of the code section to appear in the trace.
* @param block A block of code which is being traced.
*/
-public inline fun <T> trace(label: String, crossinline block: () -> T): T {
+public inline fun <T> trace(label: String, block: () -> T): T {
Trace.beginSection(label)
try {
return block()
diff --git a/tv/integration-tests/playground/build.gradle b/tv/integration-tests/playground/build.gradle
index 3ea0172..f8b1d68 100644
--- a/tv/integration-tests/playground/build.gradle
+++ b/tv/integration-tests/playground/build.gradle
@@ -40,6 +40,7 @@
androidx {
name = "TV-Compose Test App"
type = LibraryType.SAMPLES
+ mavenVersion = LibraryVersions.TV
inceptionYear = "2022"
description = "Test application for TV libraries"
}
diff --git a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/FeaturedCarousel.kt b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/FeaturedCarousel.kt
index 369392a..69c9d80 100644
--- a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/FeaturedCarousel.kt
+++ b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/FeaturedCarousel.kt
@@ -43,6 +43,7 @@
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -51,8 +52,11 @@
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.semantics.CollectionItemInfo
@@ -119,12 +123,14 @@
)
val carouselState = remember { CarouselState() }
+ var carouselFocused by remember { mutableStateOf(false) }
Carousel(
itemCount = backgrounds.size,
carouselState = carouselState,
modifier = modifier
.height(300.dp)
- .fillMaxWidth(),
+ .fillMaxWidth()
+ .onFocusChanged { carouselFocused = it.isFocused },
carouselIndicator = {
CarouselDefaults.IndicatorRow(
itemCount = backgrounds.size,
@@ -155,8 +161,15 @@
) {
Text(text = "This is sample text content.", color = Color.Yellow)
Text(text = "Sample description of slide ${itemIndex + 1}.", color = Color.Yellow)
+ val playButtonModifier =
+ if (carouselFocused) {
+ Modifier.requestFocusOnFirstGainingVisibility()
+ } else {
+ Modifier
+ }
+
Row {
- OverlayButton(text = "Play")
+ OverlayButton(modifier = playButtonModifier, text = "Play")
OverlayButton(text = "Add to Watchlist")
}
}
@@ -220,3 +233,20 @@
Text(text = text)
}
}
+
+@Composable
+fun Modifier.onFirstGainingVisibility(onGainingVisibility: () -> Unit): Modifier {
+ var isVisible by remember { mutableStateOf(false) }
+ LaunchedEffect(isVisible) {
+ if (isVisible) onGainingVisibility()
+ }
+
+ return onPlaced { isVisible = true }
+}
+
+@Composable
+fun Modifier.requestFocusOnFirstGainingVisibility(): Modifier {
+ val focusRequester = remember { FocusRequester() }
+ return focusRequester(focusRequester)
+ .onFirstGainingVisibility { focusRequester.requestFocus() }
+}
\ No newline at end of file
diff --git a/tv/integration-tests/presentation/build.gradle b/tv/integration-tests/presentation/build.gradle
index 85dc901..142f5a0 100644
--- a/tv/integration-tests/presentation/build.gradle
+++ b/tv/integration-tests/presentation/build.gradle
@@ -44,6 +44,7 @@
androidx {
name = "TV-Compose Test App"
type = LibraryType.SAMPLES
+ mavenVersion = LibraryVersions.TV
inceptionYear = "2022"
description = "Test application for TV libraries"
}
diff --git a/tv/samples/src/main/java/androidx/tv/samples/CarouselSamples.kt b/tv/samples/src/main/java/androidx/tv/samples/CarouselSamples.kt
index b356829..320ab30 100644
--- a/tv/samples/src/main/java/androidx/tv/samples/CarouselSamples.kt
+++ b/tv/samples/src/main/java/androidx/tv/samples/CarouselSamples.kt
@@ -36,15 +36,19 @@
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
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.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.unit.dp
import androidx.tv.material3.Carousel
import androidx.tv.material3.CarouselDefaults
@@ -55,17 +59,36 @@
@Sampled
@Composable
fun SimpleCarousel() {
+ @Composable
+ fun Modifier.onFirstGainingVisibility(onGainingVisibility: () -> Unit): Modifier {
+ var isVisible by remember { mutableStateOf(false) }
+ LaunchedEffect(isVisible) {
+ if (isVisible) onGainingVisibility()
+ }
+
+ return onPlaced { isVisible = true }
+ }
+
+ @Composable
+ fun Modifier.requestFocusOnFirstGainingVisibility(): Modifier {
+ val focusRequester = remember { FocusRequester() }
+ return focusRequester(focusRequester)
+ .onFirstGainingVisibility { focusRequester.requestFocus() }
+ }
+
val backgrounds = listOf(
Color.Red.copy(alpha = 0.3f),
Color.Yellow.copy(alpha = 0.3f),
Color.Green.copy(alpha = 0.3f)
)
+ var carouselFocused by remember { mutableStateOf(false) }
Carousel(
itemCount = backgrounds.size,
modifier = Modifier
.height(300.dp)
- .fillMaxWidth(),
+ .fillMaxWidth()
+ .onFocusChanged { carouselFocused = it.isFocused },
contentTransformEndToStart =
fadeIn(tween(1000)).togetherWith(fadeOut(tween(1000))),
contentTransformStartToEnd =
@@ -77,16 +100,22 @@
.border(2.dp, Color.White.copy(alpha = 0.5f))
.fillMaxSize()
) {
- var isFocused by remember { mutableStateOf(false) }
+ var buttonFocused by remember { mutableStateOf(false) }
+ val buttonModifier =
+ if (carouselFocused) {
+ Modifier.requestFocusOnFirstGainingVisibility()
+ } else {
+ Modifier
+ }
Button(
onClick = { },
- modifier = Modifier
- .onFocusChanged { isFocused = it.isFocused }
+ modifier = buttonModifier
+ .onFocusChanged { buttonFocused = it.isFocused }
.padding(40.dp)
.border(
width = 2.dp,
- color = if (isFocused) Color.Red else Color.Transparent,
+ color = if (buttonFocused) Color.Red else Color.Transparent,
shape = RoundedCornerShape(50)
)
// Duration of animation here should be less than or equal to carousel's
diff --git a/tv/tv-foundation/build.gradle b/tv/tv-foundation/build.gradle
index eace93c..365414c 100644
--- a/tv/tv-foundation/build.gradle
+++ b/tv/tv-foundation/build.gradle
@@ -30,12 +30,12 @@
dependencies {
api(libs.kotlinStdlib)
- def composeVersion = '1.4.2'
+ def composeVersion = '1.4.3'
implementation(libs.kotlinStdlibCommon)
- implementation("androidx.profileinstaller:profileinstaller:1.3.0")
+ implementation("androidx.profileinstaller:profileinstaller:1.3.1")
- api("androidx.annotation:annotation:1.5.0")
+ api("androidx.annotation:annotation:1.6.0")
api("androidx.compose.animation:animation:$composeVersion")
api("androidx.compose.runtime:runtime:$composeVersion")
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridAnimateItemPlacementTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridAnimateItemPlacementTest.kt
index 4c0ddc6..a87c1a9 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridAnimateItemPlacementTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridAnimateItemPlacementTest.kt
@@ -56,6 +56,7 @@
import kotlin.math.roundToInt
import kotlinx.coroutines.runBlocking
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -1235,6 +1236,7 @@
}
}
+ @Ignore("b/283960548")
@Test
fun noAnimationWhenScrollForwardByLargeOffset_differentSizes() {
rule.setContent {
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyNestedScrollingTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyNestedScrollingTest.kt
index f988a2d2..fc02698 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyNestedScrollingTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyNestedScrollingTest.kt
@@ -38,6 +38,7 @@
import androidx.tv.foundation.lazy.list.setContentWithTestViewConfiguration
import com.google.common.truth.Truth
import kotlinx.coroutines.runBlocking
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -175,6 +176,7 @@
}
}
+ @Ignore("b/278219642")
@Test
fun verticalGrid_nestedScrollingForwardWhenScrolledToTheEnd() = runBlocking {
val items = (1..3).toList()
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListBeyondBoundsTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListBeyondBoundsTest.kt
index 149cf47..4544704 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListBeyondBoundsTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListBeyondBoundsTest.kt
@@ -39,9 +39,12 @@
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Below
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Left
import androidx.compose.ui.layout.BeyondBoundsLayout.LayoutDirection.Companion.Right
+import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout
-import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.modifier.modifierLocalConsumer
+import androidx.compose.ui.node.LayoutAwareModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
@@ -107,7 +110,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -127,7 +130,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -147,7 +150,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
}
@@ -181,8 +184,7 @@
}
// Act.
- rule.waitForIdle()
- val hasMoreContent = rule.runOnUiThread {
+ val hasMoreContent = rule.runOnIdle {
beyondBoundsLayoutRef.layout(beyondBoundsLayoutDirection) {
hasMoreContent
}
@@ -202,28 +204,27 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(
Modifier
- .size(10.toDp())
- .onPlaced { placedItems += 5 }
- .modifierLocalConsumer {
- beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
- }
+ .size(10.toDp())
+ .trackPlaced(5)
+ .modifierLocalConsumer {
+ beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
+ }
)
}
items(5) { index ->
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
@@ -236,7 +237,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Just return true so that we stop as soon as we run this once.
// This should result in one extra item being added.
true
@@ -259,14 +259,14 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -276,17 +276,15 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
if (--extraItemCount > 0) {
- placedItems.clear()
// Return null to continue the search.
null
} else {
@@ -298,7 +296,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8, 9)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Return true to stop the search.
true
}
@@ -320,7 +317,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
@@ -330,26 +327,22 @@
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
)
}
items(5) { index ->
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index + 6
- }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
rule.runOnUiThread {
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
if (hasMoreContent) {
- placedItems.clear()
// Just return null so that we keep adding more items till we reach the end.
null
} else {
@@ -361,7 +354,6 @@
assertThat(placedItems).containsExactly(5, 6, 7, 8, 9, 10)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
- placedItems.clear()
// Return true to end the search.
true
}
@@ -383,14 +375,14 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index }
+ .trackPlaced(index)
)
}
item {
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
@@ -400,14 +392,13 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced { placedItems += index + 6 }
+ .trackPlaced(index + 6)
)
}
}
rule.runOnIdle {
assertThat(placedItems).containsExactly(5, 6, 7)
assertThat(visibleItems).containsExactly(5, 6, 7)
- placedItems.clear()
}
// Act.
@@ -416,7 +407,6 @@
beyondBoundsLayoutCount++
when (beyondBoundsLayoutDirection) {
Left, Right, Above, Below -> {
- assertThat(placedItems).containsExactlyElementsIn(visibleItems)
assertThat(placedItems).containsExactly(5, 6, 7)
assertThat(visibleItems).containsExactly(5, 6, 7)
}
@@ -430,7 +420,6 @@
}
}
}
- placedItems.clear()
// Just return true so that we stop as soon as we run this once.
// This should result in one extra item being added.
true
@@ -462,9 +451,7 @@
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index
- }
+ .trackPlaced(index)
)
}
item {
@@ -474,20 +461,17 @@
.modifierLocalConsumer {
beyondBoundsLayout = ModifierLocalBeyondBoundsLayout.current
}
- .onPlaced { placedItems += 5 }
+ .trackPlaced(5)
)
}
items(5) { index ->
Box(
Modifier
.size(10.toDp())
- .onPlaced {
- placedItems += index + 6
- }
+ .trackPlaced(index + 6)
)
}
}
- rule.runOnIdle { placedItems.clear() }
// Act.
var count = 0
@@ -495,7 +479,6 @@
beyondBoundsLayout!!.layout(beyondBoundsLayoutDirection) {
// Assert that we don't keep iterating when there is no ending condition.
assertThat(count++).isLessThan(lazyListState.layoutInfo.totalItemsCount)
- placedItems.clear()
// Always return null to continue the search.
null
}
@@ -515,7 +498,9 @@
Column {
BasicText(
text = "Outer button",
- Modifier.focusRequester(buttonFocusRequester).focusable())
+ Modifier
+ .focusRequester(buttonFocusRequester)
+ .focusable())
TvLazyColumn {
items(3) {
@@ -617,4 +602,37 @@
private fun unsupportedDirection(): Nothing = error(
"Lazy list does not support beyond bounds layout for the specified direction"
)
+
+ private fun Modifier.trackPlaced(index: Int): Modifier =
+ this then TrackPlacedElement(placedItems, index)
+}
+
+internal data class TrackPlacedElement(
+ var placedItems: MutableSet<Int>,
+ var index: Int
+) : ModifierNodeElement<TrackPlacedNode>() {
+ override fun create() = TrackPlacedNode(placedItems, index)
+
+ override fun update(node: TrackPlacedNode) {
+ node.placedItems = placedItems
+ node.index = index
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
+ name = "trackPlaced"
+ properties["index"] = index
+ }
+}
+
+internal class TrackPlacedNode(
+ var placedItems: MutableSet<Int>,
+ var index: Int
+) : LayoutAwareModifierNode, Modifier.Node() {
+ override fun onPlaced(coordinates: LayoutCoordinates) {
+ placedItems += index
+ }
+
+ override fun onDetach() {
+ placedItems -= index
+ }
}
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListsContentPaddingTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListsContentPaddingTest.kt
index cfead8b..557c5f0 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListsContentPaddingTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListsContentPaddingTest.kt
@@ -32,6 +32,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -455,6 +456,7 @@
}
}
+ @Ignore("b/283960394")
@Test
fun totalPaddingLargerParentSize_scrollByPadding() {
lateinit var state: TvLazyListState
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyNestedScrollingTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyNestedScrollingTest.kt
index 1a6000df..ca2966b 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyNestedScrollingTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyNestedScrollingTest.kt
@@ -117,7 +117,7 @@
}
// scroll forward
- rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_DOWN, 3)
+ rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_DOWN, 2)
// scroll back so we again on 0 position
// we scroll one extra dp to prevent rounding issues
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyRowTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyRowTest.kt
index 0817a21..bb040c9 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyRowTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyRowTest.kt
@@ -39,6 +39,7 @@
import androidx.tv.foundation.PivotOffsets
import androidx.tv.foundation.lazy.grid.keyPress
import com.google.common.truth.Truth.assertThat
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -120,6 +121,7 @@
.assertPositionInRootIsEqualTo(50.dp, 30.dp)
}
+ @Ignore("b/278219642")
@Test
fun scrollsLeftInRtl() {
lateinit var state: TvLazyListState
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/BringIntoViewRequestPriorityQueue.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/BringIntoViewRequestPriorityQueue.kt
deleted file mode 100644
index 17d95cf..0000000
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/BringIntoViewRequestPriorityQueue.kt
+++ /dev/null
@@ -1,137 +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.tv.foundation
-
-import androidx.compose.runtime.collection.mutableVectorOf
-import androidx.compose.ui.geometry.Rect
-import androidx.tv.foundation.ContentInViewModifier.Request
-import kotlin.contracts.ExperimentalContracts
-import kotlin.contracts.contract
-import kotlin.coroutines.resume
-import kotlinx.coroutines.CancellationException
-
-/**
- * Ongoing requests from [ContentInViewModifier.bringChildIntoView], with the invariant that it is
- * always sorted by overlapping order: each item's bounds completely overlaps the next item.
- *
- * Requests are enqueued by calling [enqueue], which inserts the request at the correct position
- * and cancels and removes any requests that it interrupts. When a request is enqueued, its
- * continuation has a completion handler set that will remove the request from the queue when
- * it's cancelled.
- *
- * One a request has been enqueued, it cannot be removed without completing the continuation.
- * This helps prevent leaking requests. Requests are removed in two ways:
- * 1. By an [enqueue] call for a request that doesn't overlap them, or
- * 2. By calling [cancelAndRemoveAll], which does exactly what it says.
- */
-@OptIn(ExperimentalContracts::class)
-internal class BringIntoViewRequestPriorityQueue {
- private val requests = mutableVectorOf<Request>()
-
- val size: Int get() = requests.size
-
- fun isEmpty(): Boolean = requests.isEmpty()
-
- /**
- * Adds [request] to the queue, enforcing the invariants of that list:
- * - It will be inserted in the correct position to preserve sorted order.
- * - Any requests not contains by or containing this request will be evicted.
- *
- * After this function is called, [request] will always be either resumed or cancelled
- * before it's removed from the queue, so the caller no longer needs to worry about
- * completing it.
- *
- * @return True if the request was enqueued, false if it was not, e.g. because the rect
- * function returned null.
- */
- fun enqueue(request: Request): Boolean {
- val requestBounds = request.currentBounds() ?: run {
- request.continuation.resume(Unit)
- return false
- }
-
- // If the request is cancelled for any reason, remove it from the queue.
- request.continuation.invokeOnCancellation {
- requests.remove(request)
- }
-
- for (i in requests.indices.reversed()) {
- val r = requests[i]
- val rBounds = r.currentBounds() ?: continue
- val intersection = requestBounds.intersect(rBounds)
- if (intersection == requestBounds) {
- // The current item fully contains the new request, so insert it after.
- requests.add(i + 1, request)
- return true
- } else if (intersection != rBounds) {
- // The new request and the current item do not fully overlap, so cancel the
- // current item and all requests after it, remove them, then continue the
- // search to the next-largest request.
- val cause = CancellationException(
- "bringIntoView call interrupted by a newer, non-overlapping call"
- )
- for (j in requests.size - 1..i) {
- // This mutates the list while iterating, but since we're iterating
- // backwards in both cases, it's fine.
- // Cancelling the continuation will remove the request from the queue.
- requests[i].continuation.cancel(cause)
- }
- }
- // Otherwise the new request fully contains the current item, so keep searching up
- // the queue.
- }
-
- // No existing request contained the new one. Either the new requests contains all
- // existing requests and it should be the new head of the queue, or all other requests
- // were removed.
- requests.add(0, request)
- return true
- }
-
- inline fun forEachFromSmallest(block: (bounds: Rect?) -> Unit) {
- contract { callsInPlace(block) }
- requests.forEachReversed { block(it.currentBounds()) }
- }
-
- fun resumeAndRemoveAll() {
- for (i in requests.indices) {
- requests[i].continuation.resume(Unit)
- }
- requests.clear()
- }
-
- inline fun resumeAndRemoveWhile(block: (bounds: Rect?) -> Boolean) {
- contract { callsInPlace(block) }
- while (requests.isNotEmpty()) {
- if (block(requests.last().currentBounds())) {
- requests.removeAt(requests.lastIndex).continuation.resume(Unit)
- } else {
- return
- }
- }
- }
-
- fun cancelAndRemoveAll(cause: Throwable?) {
- // The continuation completion handler will remove the request from the queue when it's
- // cancelled, so we need to make a copy of the list before iterating to avoid concurrent
- // mutation.
- requests.map { it.continuation }.forEach {
- it.cancel(cause)
- }
- check(requests.isEmpty())
- }
-}
\ No newline at end of file
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/ContentInViewModifier.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/ContentInViewModifier.kt
deleted file mode 100644
index 716e8f8..0000000
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/ContentInViewModifier.kt
+++ /dev/null
@@ -1,398 +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.tv.foundation
-
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.foundation.gestures.Orientation.Horizontal
-import androidx.compose.foundation.gestures.Orientation.Vertical
-import androidx.compose.foundation.gestures.ScrollableState
-import androidx.compose.foundation.onFocusedBoundsChanged
-import androidx.compose.foundation.relocation.BringIntoViewRequester
-import androidx.compose.foundation.relocation.BringIntoViewResponder
-import androidx.compose.foundation.relocation.bringIntoViewResponder
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Rect
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.layout.LayoutCoordinates
-import androidx.compose.ui.layout.OnPlacedModifier
-import androidx.compose.ui.layout.OnRemeasuredModifier
-import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.unit.toSize
-import kotlin.math.abs
-import kotlinx.coroutines.CancellableContinuation
-import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.CoroutineStart
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.job
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.suspendCancellableCoroutine
-
-/**
- * A [Modifier] to be placed on a scrollable container (i.e. [Modifier.scrollableWithPivot]) that
- * animates the [ScrollableState] to handle [BringIntoViewRequester] requests and keep the
- * currently-focused child in view when the viewport shrinks.
- *
- * Instances of this class should not be directly added to the modifier chain, instead use the
- * [modifier] property since this class relies on some modifiers that must be specified as modifier
- * factory functions and can't be implemented as interfaces.
- */
-@OptIn(ExperimentalFoundationApi::class)
-internal class ContentInViewModifier(
- private val scope: CoroutineScope,
- private val orientation: Orientation,
- private val scrollState: ScrollableState,
- private val reverseDirection: Boolean,
- private val pivotOffsets: PivotOffsets,
- private val userScrollEnabled: Boolean
-) : BringIntoViewResponder,
- OnRemeasuredModifier,
- OnPlacedModifier {
-
- /**
- * Ongoing requests from [bringChildIntoView], with the invariant that it is always sorted by
- * overlapping order: each item's [Rect] completely overlaps the next item.
- *
- * May contain requests whose bounds are too big to fit in the current viewport. This is for
- * a few reasons:
- * 1. The viewport may shrink after a request was enqueued, causing a request that fit at the
- * time it was enqueued to no longer fit.
- * 2. The size of the bounds of a request may change after it's added, causing it to grow
- * larger than the viewport.
- * 3. Having complete information about too-big requests allows us to make the right decision
- * about what part of the request to bring into view when smaller requests are also present.
- */
- private val bringIntoViewRequests = BringIntoViewRequestPriorityQueue()
-
- /** The [LayoutCoordinates] of this modifier (i.e. the scrollable container). */
- private var coordinates: LayoutCoordinates? = null
- private var focusedChild: LayoutCoordinates? = null
-
- /**
- * The previous bounds of the [focusedChild] used by [onRemeasured] to calculate when the
- * focused child is first clipped when scrolling is reversed.
- */
- private var focusedChildBoundsFromPreviousRemeasure: Rect? = null
-
- /**
- * Set to true when this class is actively animating the scroll to keep the focused child in
- * view.
- */
- private var trackingFocusedChild = false
-
- /** The size of the scrollable container. */
- private var viewportSize = IntSize.Zero
- private var isAnimationRunning = false
- private val animationState = UpdatableAnimationState()
-
- val modifier: Modifier = this
- .onFocusedBoundsChanged { focusedChild = it }
- .bringIntoViewResponder(this)
-
- override fun calculateRectForParent(localRect: Rect): Rect {
- check(viewportSize != IntSize.Zero) {
- "Expected BringIntoViewRequester to not be used before parents are placed."
- }
- // size will only be zero before the initial measurement.
- return computeDestination(localRect, viewportSize)
- }
-
- override suspend fun bringChildIntoView(localRect: () -> Rect?) {
- // Avoid creating no-op requests and no-op animations if the request does not require
- // scrolling or returns null.
- if (localRect()?.isMaxVisible() != false) return
-
- suspendCancellableCoroutine { continuation ->
- val request = Request(currentBounds = localRect, continuation = continuation)
- // Once the request is enqueued, even if it returns false, the queue will take care of
- // handling continuation cancellation so we don't need to do that here.
- if (bringIntoViewRequests.enqueue(request) && !isAnimationRunning) {
- launchAnimation()
- }
- }
- }
-
- override fun onPlaced(coordinates: LayoutCoordinates) {
- this.coordinates = coordinates
- }
-
- override fun onRemeasured(size: IntSize) {
- val oldSize = viewportSize
- viewportSize = size
-
- // Don't care if the viewport grew.
- if (size >= oldSize) return
-
- getFocusedChildBounds()?.let { focusedChild ->
- val previousFocusedChildBounds = focusedChildBoundsFromPreviousRemeasure ?: focusedChild
- if (!isAnimationRunning && !trackingFocusedChild &&
- // Resize caused it to go from being fully visible to at least partially
- // clipped. Need to use the lastFocusedChildBounds to compare with the old size
- // only to handle the case where scrolling direction is reversed: in that case, when
- // the child first goes out-of-bounds, it will be out of bounds regardless of which
- // size we pass in, so the only way to detect the change is to use the previous
- // bounds.
- previousFocusedChildBounds.isMaxVisible(oldSize) && !focusedChild.isMaxVisible(size)
- ) {
- trackingFocusedChild = true
- launchAnimation()
- }
-
- this.focusedChildBoundsFromPreviousRemeasure = focusedChild
- }
- }
-
- private fun getFocusedChildBounds(): Rect? {
- val coordinates = this.coordinates?.takeIf { it.isAttached } ?: return null
- val focusedChild = this.focusedChild?.takeIf { it.isAttached } ?: return null
- return coordinates.localBoundingBoxOf(focusedChild, clipBounds = false)
- }
-
- private fun launchAnimation() {
- check(!isAnimationRunning)
-
- scope.launch(start = CoroutineStart.UNDISPATCHED) {
- var cancellationException: CancellationException? = null
- val animationJob = coroutineContext.job
-
- try {
- isAnimationRunning = true
- scrollState.scroll {
- animationState.value = calculateScrollDelta()
- animationState.animateToZero(
- // This lambda will be invoked on every frame, during the choreographer
- // callback.
- beforeFrame = { delta ->
- // reverseDirection is actually opposite of what's passed in through the
- // (vertical|horizontal)Scroll modifiers.
- val scrollMultiplier = if (reverseDirection) 1f else -1f
- val adjustedDelta = scrollMultiplier * delta
- val consumedScroll = scrollMultiplier * scrollBy(adjustedDelta)
- if (abs(consumedScroll) < abs(delta)) {
- // If the scroll state didn't consume all the scroll on this frame,
- // it probably won't consume any more later either (we might have
- // hit the scroll bounds). This is a terminal condition for the
- // animation: If we don't cancel it, it could loop forever asking
- // for a scroll that will never be consumed.
- // Note this will cancel all pending BIV jobs.
- // TODO(b/239671493) Should this trigger nested scrolling?
- animationJob.cancel(
- "Scroll animation cancelled because scroll was not consumed " +
- "($consumedScroll < $delta)"
- )
- }
- },
- // This lambda will be invoked on every frame, but will be dispatched to run
- // after the choreographer callback, and after any composition and layout
- // passes for the frame. This means that the scroll performed in the above
- // lambda will have been applied to the layout nodes.
- afterFrame = {
- // Complete any BIV requests that were satisfied by this scroll
- // adjustment.
- bringIntoViewRequests.resumeAndRemoveWhile { bounds ->
- // If a request is no longer attached, remove it.
- if (bounds == null) return@resumeAndRemoveWhile true
- bounds.isMaxVisible()
- }
-
- // Stop tracking any KIV requests that were satisfied by this scroll
- // adjustment.
- if (trackingFocusedChild &&
- getFocusedChildBounds()?.isMaxVisible() == true
- ) {
- trackingFocusedChild = false
- }
-
- // Compute a new scroll target taking into account any resizes,
- // replacements, or added/removed requests since the last frame.
- animationState.value = calculateScrollDelta()
- }
- )
- }
-
- // Complete any BIV requests if the animation didn't need to run, or if there were
- // requests that were too large to satisfy. Note that if the animation was
- // cancelled, this won't run, and the requests will be cancelled instead.
- bringIntoViewRequests.resumeAndRemoveAll()
- } catch (e: CancellationException) {
- cancellationException = e
- throw e
- } finally {
- isAnimationRunning = false
- // Any BIV requests that were not completed should be considered cancelled.
- bringIntoViewRequests.cancelAndRemoveAll(cancellationException)
- trackingFocusedChild = false
- }
- }
- }
-
- /**
- * Calculates how far we need to scroll to satisfy all existing BringIntoView requests and the
- * focused child tracking.
- */
- private fun calculateScrollDelta(): Float {
- if (viewportSize == IntSize.Zero) return 0f
-
- val rectangleToMakeVisible: Rect = findBringIntoViewRequest()
- ?: (if (trackingFocusedChild) getFocusedChildBounds() else null)
- ?: return 0f
-
- val size = viewportSize.toSize()
- return when (orientation) {
- Vertical -> relocationDistance(
- rectangleToMakeVisible.top,
- rectangleToMakeVisible.bottom,
- size.height
- )
-
- Horizontal -> relocationDistance(
- rectangleToMakeVisible.left,
- rectangleToMakeVisible.right,
- size.width
- )
- }
- }
-
- /**
- * Find the largest BIV request that can completely fit inside the viewport.
- */
- private fun findBringIntoViewRequest(): Rect? {
- var rectangleToMakeVisible: Rect? = null
- bringIntoViewRequests.forEachFromSmallest { bounds ->
- // Ignore detached requests for now. They'll be removed later.
- if (bounds == null) return@forEachFromSmallest
- if (bounds.size <= viewportSize.toSize()) {
- rectangleToMakeVisible = bounds
- } else {
- // Found a request that doesn't fit, use the next-smallest one.
- // TODO(klippenstein) if there is a request that's too big to fit in the current
- // bounds, we should try to fit the largest part of it that contains the
- // next-smallest request.
- return rectangleToMakeVisible ?: bounds
- }
- }
- return rectangleToMakeVisible
- }
-
- /**
- * Compute the destination given the source rectangle and current bounds.
- *
- * @param childBounds The bounding box of the item that sent the request to be brought into view.
- * @return the destination rectangle.
- */
- private fun computeDestination(childBounds: Rect, containerSize: IntSize): Rect {
- return childBounds.translate(-relocationOffset(childBounds, containerSize))
- }
-
- // According to a comment in LazyListState.onScroll()
- // "inside measuring we do scrollToBeConsumed.roundToInt() so there will be no scroll if
- // we have less than 0.5 pixels"
- private val scrollableThreshold = 0.5f
- /**
- * Returns true if this [Rect] is as visible as it can be given the [size] of the viewport.
- * This means either it's fully visible or too big to fit in the viewport all at once and
- * already filling the whole viewport.
- */
- private fun Rect.isMaxVisible(size: IntSize = viewportSize): Boolean {
- // According to a comment in LazyListState.onScroll()
- // "inside measuring we do scrollToBeConsumed.roundToInt() so there will be no scroll if
- // we have less than 0.5 pixels". So, if any of the offsets are less than 0.5, it will be
- // considered to be max-visible
- val relocationOffset = relocationOffset(this, size)
- return abs(relocationOffset.x) <= scrollableThreshold &&
- abs(relocationOffset.y) <= scrollableThreshold
- }
-
- private fun relocationOffset(childBounds: Rect, containerSize: IntSize): Offset {
- val size = containerSize.toSize()
- return when (orientation) {
- Vertical -> Offset(
- x = 0f,
- y = relocationDistance(
- childBounds.top,
- childBounds.bottom,
- size.height
- )
- )
-
- Horizontal -> Offset(
- x = relocationDistance(
- childBounds.left,
- childBounds.right,
- size.width
- ),
- y = 0f
- )
- }
- }
-
- /**
- * Calculate the offset needed to bring one of the edges into view. The leadingEdge is the side
- * closest to the origin (For the x-axis this is 'left', for the y-axis this is 'top').
- * The trailing edge is the other side (For the x-axis this is 'right', for the y-axis this is
- * 'bottom').
- */
- private fun relocationDistance(
- leadingEdgeOfItemRequestingFocus: Float,
- trailingEdgeOfItemRequestingFocus: Float,
- containerSize: Float
- ): Float {
- if (!userScrollEnabled) return 0f
-
- val sizeOfItemRequestingFocus =
- abs(trailingEdgeOfItemRequestingFocus - leadingEdgeOfItemRequestingFocus)
- val childSmallerThanParent = sizeOfItemRequestingFocus <= containerSize
- val initialTargetForLeadingEdge =
- pivotOffsets.parentFraction * containerSize -
- (pivotOffsets.childFraction * sizeOfItemRequestingFocus)
- val spaceAvailableToShowItem = containerSize - initialTargetForLeadingEdge
-
- val targetForLeadingEdge =
- if (childSmallerThanParent && spaceAvailableToShowItem < sizeOfItemRequestingFocus) {
- containerSize - sizeOfItemRequestingFocus
- } else {
- initialTargetForLeadingEdge
- }
-
- return leadingEdgeOfItemRequestingFocus - targetForLeadingEdge
- }
-
- private operator fun IntSize.compareTo(other: IntSize): Int = when (orientation) {
- Horizontal -> width.compareTo(other.width)
- Vertical -> height.compareTo(other.height)
- }
-
- private operator fun Size.compareTo(other: Size): Int = when (orientation) {
- Horizontal -> width.compareTo(other.width)
- Vertical -> height.compareTo(other.height)
- }
-
- /**
- * A request to bring some [Rect] in the scrollable viewport.
- *
- * @param currentBounds A function that returns the current bounds that the request wants to
- * make visible.
- * @param continuation The [CancellableContinuation] from the suspend function used to make the
- * request.
- */
- internal class Request(
- val currentBounds: () -> Rect?,
- val continuation: CancellableContinuation<Unit>,
- )
-}
\ No newline at end of file
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/ScrollableWithPivot.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/ScrollableWithPivot.kt
index f7f95a3..86f2902 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/ScrollableWithPivot.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/ScrollableWithPivot.kt
@@ -1,4 +1,3 @@
-
/*
* Copyright 2022 The Android Open Source Project
*
@@ -17,25 +16,18 @@
package androidx.tv.foundation
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.CubicBezierEasing
+import androidx.compose.animation.core.tween
import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.focusGroup
+import androidx.compose.foundation.gestures.BringIntoViewScroller
import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.foundation.gestures.Orientation.Horizontal
import androidx.compose.foundation.gestures.ScrollableState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.foundation.gestures.scrollable
import androidx.compose.ui.Modifier
-import androidx.compose.ui.composed
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.debugInspectorInfo
+import androidx.compose.ui.platform.inspectable
+import kotlin.math.abs
/* Copied from
compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/
@@ -67,95 +59,66 @@
pivotOffsets: PivotOffsets,
enabled: Boolean = true,
reverseDirection: Boolean = false
-): Modifier = composed(
- inspectorInfo = debugInspectorInfo {
- name = "scrollableWithPivot"
- properties["orientation"] = orientation
- properties["state"] = state
- properties["enabled"] = enabled
- properties["reverseDirection"] = reverseDirection
- properties["pivotOffsets"] = pivotOffsets
- },
- factory = {
- val coroutineScope = rememberCoroutineScope()
- val keepFocusedChildInViewModifier =
- remember(coroutineScope, orientation, state, reverseDirection, pivotOffsets, enabled) {
- ContentInViewModifier(
- scope = coroutineScope,
- orientation = orientation,
- scrollState = state,
- reverseDirection = reverseDirection,
- pivotOffsets = pivotOffsets,
- userScrollEnabled = enabled
- )
+): Modifier = this then Modifier.inspectable(debugInspectorInfo {
+ name = "scrollableWithPivot"
+ properties["orientation"] = orientation
+ properties["state"] = state
+ properties["enabled"] = enabled
+ properties["reverseDirection"] = reverseDirection
+ properties["pivotOffsets"] = pivotOffsets
+}) {
+ Modifier.scrollable(
+ state = state,
+ orientation = orientation,
+ enabled = enabled,
+ reverseDirection = reverseDirection,
+ overscrollEffect = null,
+ bringIntoViewScroller = TvBringIntoViewScroller(pivotOffsets, enabled)
+ )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+private class TvBringIntoViewScroller(
+ val pivotOffsets: PivotOffsets,
+ val userScrollEnabled: Boolean
+) : BringIntoViewScroller {
+
+ override val scrollAnimationSpec: AnimationSpec<Float> = tween<Float>(
+ durationMillis = 125,
+ easing = CubicBezierEasing(0.25f, 0.1f, .25f, 1f)
+ )
+
+ override fun calculateScrollDistance(offset: Float, size: Float, containerSize: Float): Float {
+ if (!userScrollEnabled) return 0f
+ val leadingEdgeOfItemRequestingFocus = offset
+ val trailingEdgeOfItemRequestingFocus = offset + size
+
+ val sizeOfItemRequestingFocus =
+ abs(trailingEdgeOfItemRequestingFocus - leadingEdgeOfItemRequestingFocus)
+ val childSmallerThanParent = sizeOfItemRequestingFocus <= containerSize
+ val initialTargetForLeadingEdge =
+ pivotOffsets.parentFraction * containerSize -
+ (pivotOffsets.childFraction * sizeOfItemRequestingFocus)
+ val spaceAvailableToShowItem = containerSize - initialTargetForLeadingEdge
+
+ val targetForLeadingEdge =
+ if (childSmallerThanParent && spaceAvailableToShowItem < sizeOfItemRequestingFocus) {
+ containerSize - sizeOfItemRequestingFocus
+ } else {
+ initialTargetForLeadingEdge
}
- Modifier
- .focusGroup()
- .then(keepFocusedChildInViewModifier.modifier)
- .pointerScrollable(
- orientation,
- reverseDirection,
- state,
- enabled
- )
- }
-)
-
-@Suppress("ComposableModifierFactory")
-@Composable
-private fun Modifier.pointerScrollable(
- orientation: Orientation,
- reverseDirection: Boolean,
- controller: ScrollableState,
- enabled: Boolean
-): Modifier {
- val nestedScrollDispatcher = remember { mutableStateOf(NestedScrollDispatcher()) }
- val scrollLogic = rememberUpdatedState(
- ScrollingLogic(
- orientation,
- reverseDirection,
- controller
- )
- )
- val nestedScrollConnection = remember(enabled) {
- scrollableNestedScrollConnection(scrollLogic, enabled)
+ return leadingEdgeOfItemRequestingFocus - targetForLeadingEdge
}
- return this.nestedScroll(nestedScrollConnection, nestedScrollDispatcher.value)
-}
-
-private class ScrollingLogic(
- val orientation: Orientation,
- val reverseDirection: Boolean,
- val scrollableState: ScrollableState,
-) {
- fun Float.toOffset(): Offset = when {
- this == 0f -> Offset.Zero
- orientation == Horizontal -> Offset(this, 0f)
- else -> Offset(0f, this)
+ override fun hashCode(): Int {
+ var result = pivotOffsets.hashCode()
+ result = 31 * result + userScrollEnabled.hashCode()
+ return result
}
- fun Offset.toFloat(): Float = if (orientation == Horizontal) this.x else this.y
- fun Float.reverseIfNeeded(): Float = if (reverseDirection) this * -1 else this
-
- fun performRawScroll(scroll: Offset): Offset {
- return if (scrollableState.isScrollInProgress) {
- Offset.Zero
- } else {
- scrollableState.dispatchRawDelta(scroll.toFloat().reverseIfNeeded())
- .reverseIfNeeded().toOffset()
- }
+ override fun equals(other: Any?): Boolean {
+ if (other !is TvBringIntoViewScroller) return false
+ return pivotOffsets == other.pivotOffsets && userScrollEnabled == other.userScrollEnabled
}
}
-
-private fun scrollableNestedScrollConnection(
- scrollLogic: State<ScrollingLogic>,
- enabled: Boolean
-): NestedScrollConnection = object : NestedScrollConnection {
- override fun onPostScroll(
- consumed: Offset,
- available: Offset,
- source: NestedScrollSource
- ): Offset = if (enabled) scrollLogic.value.performRawScroll(available) else Offset.Zero
-}
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/UpdatableAnimationState.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/UpdatableAnimationState.kt
deleted file mode 100644
index 903ee4c..0000000
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/UpdatableAnimationState.kt
+++ /dev/null
@@ -1,178 +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.tv.foundation
-
-import androidx.compose.animation.core.AnimationConstants.UnspecifiedTime
-import androidx.compose.animation.core.AnimationState
-import androidx.compose.animation.core.AnimationVector1D
-import androidx.compose.animation.core.CubicBezierEasing
-import androidx.compose.animation.core.VectorConverter
-import androidx.compose.animation.core.tween
-import androidx.compose.runtime.withFrameNanos
-import androidx.compose.ui.MotionDurationScale
-import kotlin.contracts.ExperimentalContracts
-import kotlin.contracts.contract
-import kotlin.coroutines.coroutineContext
-import kotlin.math.absoluteValue
-import kotlin.math.roundToLong
-
-/**
- * Holds state for an [animation][animateToZero] that will continuously animate a float [value] to
- * zero.
- *
- * Unlike the standard [AnimationState], this class allows the value to be changed while the
- * animation is running. When that happens, the next frame will continue animating the new value
- * to zero as though the previous animation was interrupted and restarted with the new value. See
- * the docs on [animateToZero] for more information.
- *
- * An analogy for how this animation works is gravity – you can pick something up, and as soon as
- * you let it go it will start falling to the ground. If you catch it and raise it higher, it will
- * continue falling from the new height.
- *
- * Similar behavior could be achieved by using an [AnimationState] and creating a new copy and
- * launching a new coroutine to call `animateTo(0f)` every time the value changes. However, this
- * class doesn't require allocating a new state object and launching/cancelling a coroutine to
- * update the value, which makes for a more convenient API for this particular use case, and makes
- * it cheaper to update [value] on every frame.
- */
-internal class UpdatableAnimationState {
-
- private var lastFrameTime = UnspecifiedTime
- private var lastVelocity = ZeroVector
- private var isRunning = false
-
- /**
- * The value to be animated. This property will be changed on every frame while [animateToZero]
- * is running, and will be set to exactly 0f before it returns. Unlike [AnimationState], this
- * property is mutable – it can be changed it any time during the animation, and the animation
- * will continue running from the new value on the next frame.
- *
- * Simply setting this property will not start the animation – [animateToZero] must be manually
- * invoked to kick off the animation, but once it's running it does not need to be called again
- * when this property is changed, until the animation finishes.
- */
- var value: Float = 0f
-
- /**
- * Starts animating [value] to 0f. This function will suspend until [value] actually reaches
- * 0f – e.g. if [value] is reset to a non-zero value on every frame, it will never return. When
- * this function does return, [value] will have been set to exactly 0f.
- *
- * If this function is called more than once concurrently, it will throw.
- *
- * @param beforeFrame Called _inside_ the choreographer callback on every frame with the
- * difference between the previous value and the new value. This corresponds to the typical
- * frame callback used in the other animation APIs and [withFrameNanos]. It runs before
- * composition, layout, and other passes for the frame.
- * @param afterFrame Called _outside_ the choreographer callback for every frame, _after_ the
- * composition and layout passes have finished running for that frame. This function allows the
- * caller to update [value] based on any layout changes performed in [beforeFrame].
- */
- @OptIn(ExperimentalContracts::class)
- suspend fun animateToZero(
- beforeFrame: (valueDelta: Float) -> Unit,
- afterFrame: () -> Unit
- ) {
- contract { callsInPlace(beforeFrame) }
- check(!isRunning)
-
- val durationScale = coroutineContext[MotionDurationScale]?.scaleFactor ?: 1f
- isRunning = true
-
- try {
- // Don't rely on the animation's duration vs playtime to calculate completion since the
- // value could be updated after each frame, and if that happens we need to continue
- // running the animation.
- while (!value.isZeroish()) {
- withFrameNanos { frameTime ->
- if (lastFrameTime == UnspecifiedTime) {
- lastFrameTime = frameTime
- }
-
- val vectorizedCurrentValue = AnimationVector1D(value)
- val playTime = if (durationScale == 0f) {
- // The duration scale will be 0 when animations are disabled via a11y
- // settings or developer settings.
- RebasableAnimationSpec.getDurationNanos(
- initialValue = AnimationVector1D(value),
- targetValue = ZeroVector,
- initialVelocity = lastVelocity
- )
- } else {
- ((frameTime - lastFrameTime) / durationScale).roundToLong()
- }
- val newValue = RebasableAnimationSpec.getValueFromNanos(
- playTimeNanos = playTime,
- initialValue = vectorizedCurrentValue,
- targetValue = ZeroVector,
- initialVelocity = lastVelocity
- ).value
- lastVelocity = RebasableAnimationSpec.getVelocityFromNanos(
- playTimeNanos = playTime,
- initialValue = vectorizedCurrentValue,
- targetValue = ZeroVector,
- initialVelocity = lastVelocity
- )
- lastFrameTime = frameTime
-
- val delta = value - newValue
- value = newValue
- beforeFrame(delta)
- }
- afterFrame()
-
- if (durationScale == 0f) {
- // Never run more than one loop when animations are disabled.
- break
- }
- }
-
- // The last iteration of the loop may have called block with a non-zero value due to
- // the visibility threshold, so ensure it gets called one last time with actual zero.
- if (value.absoluteValue != 0f) {
- withFrameNanos {
- val delta = value
- // Update the value before invoking the callback so that the callback will see
- // the correct value if it looks at it.
- value = 0f
- beforeFrame(delta)
- }
- afterFrame()
- }
- } finally {
- lastFrameTime = UnspecifiedTime
- lastVelocity = ZeroVector
- isRunning = false
- }
- }
-
- private companion object {
- const val VisibilityThreshold = 0.01f
- val ZeroVector = AnimationVector1D(0f)
-
- /**
- * Spring does not work well with PivotOffset version of this class
- */
- val RebasableAnimationSpec = tween<Float>(
- durationMillis = 125,
- easing = CubicBezierEasing(0.25f, 0.1f, .25f, 1f)
- )
- .vectorize(Float.VectorConverter)
-
- fun Float.isZeroish() = absoluteValue < VisibilityThreshold
- }
-}
\ No newline at end of file
diff --git a/tv/tv-material/api/current.txt b/tv/tv-material/api/current.txt
index 9fa65e0..11e4e98 100644
--- a/tv/tv-material/api/current.txt
+++ b/tv/tv-material/api/current.txt
@@ -45,11 +45,17 @@
}
public final class ButtonKt {
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ButtonScale {
+ field public static final androidx.tv.material3.ButtonScale.Companion Companion;
+ }
+
+ public static final class ButtonScale.Companion {
+ method public androidx.tv.material3.ButtonScale getNone();
+ property public final androidx.tv.material3.ButtonScale None;
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ButtonShape {
@@ -80,17 +86,17 @@
}
public final class CardKt {
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Card(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ClassicCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void CompactCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.ui.graphics.Brush scrimBrush, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideClassicCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Card(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ClassicCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void CompactCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.ui.graphics.Brush scrimBrush, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideClassicCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardLayoutColors {
}
@androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardLayoutDefaults {
- method @androidx.compose.runtime.Composable public void ImageCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public void ImageCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardLayoutColors contentColor(optional long contentColor, optional long focusedContentColor, optional long pressedContentColor);
field public static final androidx.tv.material3.CardLayoutDefaults INSTANCE;
}
@@ -101,6 +107,12 @@
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardScale {
+ field public static final androidx.tv.material3.CardScale.Companion Companion;
+ }
+
+ public static final class CardScale.Companion {
+ method public androidx.tv.material3.CardScale getNone();
+ property public final androidx.tv.material3.CardScale None;
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardShape {
@@ -304,8 +316,8 @@
}
public final class IconButtonKt {
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void OutlinedIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void OutlinedIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
}
public final class IconKt {
@@ -450,8 +462,8 @@
public final class SurfaceKt {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(optional androidx.compose.ui.Modifier modifier, optional float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.NonInteractiveSurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional float tonalElevation, optional androidx.tv.material3.ToggleableSurfaceShape shape, optional androidx.tv.material3.ToggleableSurfaceColors colors, optional androidx.tv.material3.ToggleableSurfaceScale scale, optional androidx.tv.material3.ToggleableSurfaceBorder border, optional androidx.tv.material3.ToggleableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional float tonalElevation, optional androidx.tv.material3.ClickableSurfaceShape shape, optional androidx.tv.material3.ClickableSurfaceColors colors, optional androidx.tv.material3.ClickableSurfaceScale scale, optional androidx.tv.material3.ClickableSurfaceBorder border, optional androidx.tv.material3.ClickableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional float tonalElevation, optional androidx.tv.material3.ToggleableSurfaceShape shape, optional androidx.tv.material3.ToggleableSurfaceColors colors, optional androidx.tv.material3.ToggleableSurfaceScale scale, optional androidx.tv.material3.ToggleableSurfaceBorder border, optional androidx.tv.material3.ToggleableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional float tonalElevation, optional androidx.tv.material3.ClickableSurfaceShape shape, optional androidx.tv.material3.ClickableSurfaceColors colors, optional androidx.tv.material3.ClickableSurfaceScale scale, optional androidx.tv.material3.ClickableSurfaceBorder border, optional androidx.tv.material3.ClickableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> getLocalAbsoluteTonalElevation();
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> LocalAbsoluteTonalElevation;
}
@@ -524,6 +536,12 @@
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ToggleableSurfaceScale {
+ field public static final androidx.tv.material3.ToggleableSurfaceScale.Companion Companion;
+ }
+
+ public static final class ToggleableSurfaceScale.Companion {
+ method public androidx.tv.material3.ToggleableSurfaceScale getNone();
+ property public final androidx.tv.material3.ToggleableSurfaceScale None;
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ToggleableSurfaceShape {
@@ -578,8 +596,8 @@
}
public final class WideButtonKt {
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> background, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.WideButtonContentColor contentColor, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, 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 @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? subtitle, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> background, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.WideButtonContentColor contentColor, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> background, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.WideButtonContentColor contentColor, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, 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 @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? subtitle, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> background, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.WideButtonContentColor contentColor, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding);
}
}
diff --git a/tv/tv-material/api/restricted_current.txt b/tv/tv-material/api/restricted_current.txt
index 9fa65e0..11e4e98 100644
--- a/tv/tv-material/api/restricted_current.txt
+++ b/tv/tv-material/api/restricted_current.txt
@@ -45,11 +45,17 @@
}
public final class ButtonKt {
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ButtonScale {
+ field public static final androidx.tv.material3.ButtonScale.Companion Companion;
+ }
+
+ public static final class ButtonScale.Companion {
+ method public androidx.tv.material3.ButtonScale getNone();
+ property public final androidx.tv.material3.ButtonScale None;
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ButtonShape {
@@ -80,17 +86,17 @@
}
public final class CardKt {
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Card(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ClassicCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void CompactCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.ui.graphics.Brush scrimBrush, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideClassicCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Card(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ClassicCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void CompactCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.ui.graphics.Brush scrimBrush, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideClassicCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit> subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardLayoutColors {
}
@androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardLayoutDefaults {
- method @androidx.compose.runtime.Composable public void ImageCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public void ImageCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardLayoutColors contentColor(optional long contentColor, optional long focusedContentColor, optional long pressedContentColor);
field public static final androidx.tv.material3.CardLayoutDefaults INSTANCE;
}
@@ -101,6 +107,12 @@
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardScale {
+ field public static final androidx.tv.material3.CardScale.Companion Companion;
+ }
+
+ public static final class CardScale.Companion {
+ method public androidx.tv.material3.CardScale getNone();
+ property public final androidx.tv.material3.CardScale None;
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardShape {
@@ -304,8 +316,8 @@
}
public final class IconButtonKt {
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void OutlinedIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void OutlinedIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
}
public final class IconKt {
@@ -450,8 +462,8 @@
public final class SurfaceKt {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(optional androidx.compose.ui.Modifier modifier, optional float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.NonInteractiveSurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional float tonalElevation, optional androidx.tv.material3.ToggleableSurfaceShape shape, optional androidx.tv.material3.ToggleableSurfaceColors colors, optional androidx.tv.material3.ToggleableSurfaceScale scale, optional androidx.tv.material3.ToggleableSurfaceBorder border, optional androidx.tv.material3.ToggleableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional float tonalElevation, optional androidx.tv.material3.ClickableSurfaceShape shape, optional androidx.tv.material3.ClickableSurfaceColors colors, optional androidx.tv.material3.ClickableSurfaceScale scale, optional androidx.tv.material3.ClickableSurfaceBorder border, optional androidx.tv.material3.ClickableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional float tonalElevation, optional androidx.tv.material3.ToggleableSurfaceShape shape, optional androidx.tv.material3.ToggleableSurfaceColors colors, optional androidx.tv.material3.ToggleableSurfaceScale scale, optional androidx.tv.material3.ToggleableSurfaceBorder border, optional androidx.tv.material3.ToggleableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional float tonalElevation, optional androidx.tv.material3.ClickableSurfaceShape shape, optional androidx.tv.material3.ClickableSurfaceColors colors, optional androidx.tv.material3.ClickableSurfaceScale scale, optional androidx.tv.material3.ClickableSurfaceBorder border, optional androidx.tv.material3.ClickableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> getLocalAbsoluteTonalElevation();
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> LocalAbsoluteTonalElevation;
}
@@ -524,6 +536,12 @@
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ToggleableSurfaceScale {
+ field public static final androidx.tv.material3.ToggleableSurfaceScale.Companion Companion;
+ }
+
+ public static final class ToggleableSurfaceScale.Companion {
+ method public androidx.tv.material3.ToggleableSurfaceScale getNone();
+ property public final androidx.tv.material3.ToggleableSurfaceScale None;
}
@androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ToggleableSurfaceShape {
@@ -578,8 +596,8 @@
}
public final class WideButtonKt {
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> background, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.WideButtonContentColor contentColor, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, 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 @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? subtitle, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> background, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.WideButtonContentColor contentColor, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> background, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.WideButtonContentColor contentColor, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, 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 @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? subtitle, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> background, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.WideButtonContentColor contentColor, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding);
}
}
diff --git a/tv/tv-material/build.gradle b/tv/tv-material/build.gradle
index 760e574..c215dc0 100644
--- a/tv/tv-material/build.gradle
+++ b/tv/tv-material/build.gradle
@@ -27,14 +27,14 @@
dependencies {
api(libs.kotlinStdlib)
- def composeVersion = '1.4.2'
+ def composeVersion = '1.4.3'
- api(project(":compose:animation:animation"))
+ api("androidx.compose.animation:animation:$composeVersion")
api("androidx.compose.material:material-icons-core:$composeVersion")
api(project(":tv:tv-foundation"))
implementation(libs.kotlinStdlibCommon)
- implementation("androidx.profileinstaller:profileinstaller:1.3.0")
+ implementation("androidx.profileinstaller:profileinstaller:1.3.1")
androidTestImplementation(libs.truth)
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/ButtonTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/ButtonTest.kt
index 70ba16f..5dcedbd 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/ButtonTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/ButtonTest.kt
@@ -24,7 +24,6 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.platform.testTag
@@ -56,7 +55,6 @@
@LargeTest
@OptIn(
ExperimentalTestApi::class,
- ExperimentalComposeUiApi::class,
ExperimentalTvMaterial3Api::class
)
@RunWith(AndroidJUnit4::class)
@@ -76,6 +74,27 @@
rule.onNodeWithTag(FilledButtonTag)
.assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertHasClickAction()
+ .assertIsEnabled()
+ }
+
+ @Test
+ fun filledButton_longClickSemantics() {
+ rule.setContent {
+ Box {
+ Button(
+ modifier = Modifier.testTag(FilledButtonTag),
+ onClick = {},
+ onLongClick = {}) {
+ Text("FilledButton")
+ }
+ }
+ }
+
+ rule.onNodeWithTag(FilledButtonTag)
+ .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertHasClickAction()
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
.assertIsEnabled()
}
@@ -120,6 +139,30 @@
}
@Test
+ fun filledButton_findByTag_andLongClick() {
+ var counter = 0
+ val onLongClick: () -> Unit = { ++counter }
+ val text = "FilledButtonText"
+
+ rule.setContent {
+ Box {
+ Button(
+ modifier = Modifier.testTag(FilledButtonTag),
+ onClick = {},
+ onLongClick = onLongClick) {
+ Text(text)
+ }
+ }
+ }
+ rule.onNodeWithTag(FilledButtonTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ rule.runOnIdle {
+ Truth.assertThat(counter).isEqualTo(1)
+ }
+ }
+
+ @Test
fun filledButton_canBeDisabled() {
rule.setContent {
var enabled by remember { mutableStateOf(true) }
@@ -277,6 +320,27 @@
rule.onNodeWithTag(OutlinedButtonTag)
.assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertHasClickAction()
+ .assertIsEnabled()
+ }
+
+ @Test
+ fun outlinedButton_longClickSemantics() {
+ rule.setContent {
+ Box {
+ OutlinedButton(
+ modifier = Modifier.testTag(OutlinedButtonTag),
+ onClick = {},
+ onLongClick = {}) {
+ Text("OutlinedButton")
+ }
+ }
+ }
+
+ rule.onNodeWithTag(OutlinedButtonTag)
+ .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertHasClickAction()
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
.assertIsEnabled()
}
@@ -321,6 +385,30 @@
}
@Test
+ fun outlinedButton_findByTag_andLongClick() {
+ var counter = 0
+ val onLongClick: () -> Unit = { ++counter }
+ val text = "OutlinedButtonText"
+
+ rule.setContent {
+ Box {
+ OutlinedButton(
+ modifier = Modifier.testTag(OutlinedButtonTag),
+ onClick = {},
+ onLongClick = onLongClick) {
+ Text(text)
+ }
+ }
+ }
+ rule.onNodeWithTag(OutlinedButtonTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ rule.runOnIdle {
+ Truth.assertThat(counter).isEqualTo(1)
+ }
+ }
+
+ @Test
fun outlinedButton_canBeDisabled() {
rule.setContent {
var enabled by remember { mutableStateOf(true) }
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardTest.kt
index 68be7c4..d05b79c 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardTest.kt
@@ -32,7 +32,6 @@
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.testutils.assertIsEqualTo
import androidx.compose.testutils.assertShape
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.key.Key
@@ -66,7 +65,6 @@
@OptIn(
ExperimentalTestApi::class,
- ExperimentalComposeUiApi::class,
ExperimentalTvMaterial3Api::class
)
@LargeTest
@@ -132,6 +130,33 @@
}
@Test
+ fun card_longClickSemantics() {
+ val count = mutableStateOf(0)
+ rule.setContent {
+ Card(
+ modifier = Modifier.testTag(CardTag),
+ onClick = { },
+ onLongClick = {
+ count.value += 1
+ }
+ ) {
+ Text("${count.value}")
+ Spacer(Modifier.size(30.dp))
+ }
+ }
+
+ rule.onNodeWithTag(CardTag)
+ .assertHasClickAction()
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
+ .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Role))
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .assertIsEnabled()
+ .assertTextEquals("0")
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ .assertTextEquals("1")
+ }
+
+ @Test
fun card_clickAction() {
val count = mutableStateOf(0f)
rule.setContent {
@@ -157,6 +182,33 @@
}
@Test
+ fun card_longClickAction() {
+ val count = mutableStateOf(0f)
+ rule.setContent {
+ Card(
+ modifier = Modifier.testTag(CardTag),
+ onClick = { },
+ onLongClick = {
+ count.value += 1
+ }
+ ) {
+ Text("${count.value}")
+ Spacer(Modifier.size(30.dp))
+ }
+ }
+
+ rule.onNodeWithTag(CardTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ Truth.assertThat(count.value).isEqualTo(1)
+
+ rule.onNodeWithTag(CardTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter, count = 2)
+ Truth.assertThat(count.value).isEqualTo(3)
+ }
+
+ @Test
fun card_interactionSource() {
val interactionSource = MutableInteractionSource()
@@ -221,6 +273,34 @@
}
@Test
+ fun classicCard_longClickSemantics() {
+ val count = mutableStateOf(0)
+ rule.setContent {
+ ClassicCard(
+ modifier = Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(ClassicCardTag),
+ image = { SampleImage() },
+ title = { Text("${count.value}") },
+ onClick = { },
+ onLongClick = {
+ count.value += 1
+ }
+ )
+ }
+
+ rule.onNodeWithTag(ClassicCardTag)
+ .assertHasClickAction()
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
+ .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Role))
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .assertIsEnabled()
+ .assertTextEquals("0")
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ .assertTextEquals("1")
+ }
+
+ @Test
fun classicCard_clickAction() {
val count = mutableStateOf(0f)
rule.setContent {
@@ -247,6 +327,34 @@
}
@Test
+ fun classicCard_longClickAction() {
+ val count = mutableStateOf(0f)
+ rule.setContent {
+ ClassicCard(
+ modifier = Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(ClassicCardTag),
+ image = { SampleImage() },
+ title = { Text("${count.value}") },
+ onClick = { },
+ onLongClick = {
+ count.value += 1
+ }
+ )
+ }
+
+ rule.onNodeWithTag(ClassicCardTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ Truth.assertThat(count.value).isEqualTo(1)
+
+ rule.onNodeWithTag(ClassicCardTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter, count = 2)
+ Truth.assertThat(count.value).isEqualTo(3)
+ }
+
+ @Test
fun classicCard_contentPadding() {
val contentPadding = PaddingValues(8.dp, 10.dp, 12.dp, 14.dp)
val cardTitleTag = "classic_card_title"
@@ -328,6 +436,34 @@
}
@Test
+ fun compactCard_longClickSemantics() {
+ val count = mutableStateOf(0)
+ rule.setContent {
+ CompactCard(
+ modifier = Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(CompactCardTag),
+ image = { SampleImage() },
+ title = { Text("${count.value}") },
+ onClick = { },
+ onLongClick = {
+ count.value += 1
+ }
+ )
+ }
+
+ rule.onNodeWithTag(CompactCardTag)
+ .assertHasClickAction()
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
+ .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Role))
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .assertIsEnabled()
+ .assertTextEquals("0")
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ .assertTextEquals("1")
+ }
+
+ @Test
fun compactCard_clickAction() {
val count = mutableStateOf(0f)
rule.setContent {
@@ -354,6 +490,34 @@
}
@Test
+ fun compactCard_longClickAction() {
+ val count = mutableStateOf(0f)
+ rule.setContent {
+ CompactCard(
+ modifier = Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(CompactCardTag),
+ image = { SampleImage() },
+ title = { Text("${count.value}") },
+ onClick = { },
+ onLongClick = {
+ count.value += 1
+ }
+ )
+ }
+
+ rule.onNodeWithTag(CompactCardTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ Truth.assertThat(count.value).isEqualTo(1)
+
+ rule.onNodeWithTag(CompactCardTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter, count = 2)
+ Truth.assertThat(count.value).isEqualTo(3)
+ }
+
+ @Test
fun wideClassicCard_semantics() {
val count = mutableStateOf(0)
rule.setContent {
@@ -378,6 +542,34 @@
}
@Test
+ fun wideClassicCard_longClickSemantics() {
+ val count = mutableStateOf(0)
+ rule.setContent {
+ WideClassicCard(
+ modifier = Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(WideClassicCardTag),
+ image = { SampleImage() },
+ title = { Text("${count.value}") },
+ onClick = { },
+ onLongClick = {
+ count.value += 1
+ }
+ )
+ }
+
+ rule.onNodeWithTag(WideClassicCardTag)
+ .assertHasClickAction()
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
+ .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Role))
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .assertIsEnabled()
+ .assertTextEquals("0")
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ .assertTextEquals("1")
+ }
+
+ @Test
fun wideClassicCard_clickAction() {
val count = mutableStateOf(0f)
rule.setContent {
@@ -404,6 +596,34 @@
}
@Test
+ fun wideClassicCard_longClickAction() {
+ val count = mutableStateOf(0f)
+ rule.setContent {
+ WideClassicCard(
+ modifier = Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(WideClassicCardTag),
+ image = { SampleImage() },
+ title = { Text("${count.value}") },
+ onClick = { },
+ onLongClick = {
+ count.value += 1
+ }
+ )
+ }
+
+ rule.onNodeWithTag(WideClassicCardTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ Truth.assertThat(count.value).isEqualTo(1)
+
+ rule.onNodeWithTag(WideClassicCardTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter, count = 2)
+ Truth.assertThat(count.value).isEqualTo(3)
+ }
+
+ @Test
fun wideClassicCard_contentPadding() {
val contentPadding = PaddingValues(8.dp, 10.dp, 12.dp, 14.dp)
val cardTitleTag = "wide_classic_card_title"
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonTest.kt
index 8e1fdc1..50b3b67 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonTest.kt
@@ -23,7 +23,6 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.platform.testTag
@@ -58,7 +57,6 @@
@OptIn(
ExperimentalTestApi::class,
- ExperimentalComposeUiApi::class,
ExperimentalTvMaterial3Api::class
)
@RunWith(AndroidJUnit4::class)
@@ -216,6 +214,31 @@
rule.onNodeWithTag(FilledIconButtonTag)
.assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertHasClickAction()
+ .assertIsEnabled()
+ }
+
+ @Test
+ fun filledIconButton_longClickSemantics() {
+ rule.setContent {
+ Box {
+ IconButton(
+ modifier = Modifier.testTag(FilledIconButtonTag),
+ onClick = {},
+ onLongClick = {}) {
+ Box(
+ modifier = Modifier
+ .size(IconButtonDefaults.MediumIconSize)
+ .semantics(mergeDescendants = true) {}
+ )
+ }
+ }
+ }
+
+ rule.onNodeWithTag(FilledIconButtonTag)
+ .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertHasClickAction()
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
.assertIsEnabled()
}
@@ -270,6 +293,34 @@
}
@Test
+ fun filledIconButton_findByTagAndLongClick() {
+ var counter = 0
+ val onLongClick: () -> Unit = { ++counter }
+
+ rule.setContent {
+ Box {
+ IconButton(
+ modifier = Modifier.testTag(FilledIconButtonTag),
+ onClick = {},
+ onLongClick = onLongClick
+ ) {
+ Box(
+ modifier = Modifier
+ .size(IconButtonDefaults.MediumIconSize)
+ .semantics(mergeDescendants = true) {}
+ )
+ }
+ }
+ }
+ rule.onNodeWithTag(FilledIconButtonTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ rule.runOnIdle {
+ Truth.assertThat(counter).isEqualTo(1)
+ }
+ }
+
+ @Test
fun filledIconButton_canBeDisabled() {
rule.setContent {
var enabled by remember { mutableStateOf(true) }
@@ -670,6 +721,32 @@
rule.onNodeWithTag(OutlinedIconButtonTag)
.assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertHasClickAction()
+ .assertIsEnabled()
+ }
+
+ @Test
+ fun outlinedIconButton_longClickSemantics() {
+ rule.setContent {
+ Box {
+ OutlinedIconButton(
+ modifier = Modifier.testTag(OutlinedIconButtonTag),
+ onClick = {},
+ onLongClick = {}
+ ) {
+ Box(
+ modifier = Modifier
+ .size(OutlinedIconButtonDefaults.MediumIconSize)
+ .semantics(mergeDescendants = true) {}
+ )
+ }
+ }
+ }
+
+ rule.onNodeWithTag(OutlinedIconButtonTag)
+ .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertHasClickAction()
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
.assertIsEnabled()
}
@@ -724,6 +801,34 @@
}
@Test
+ fun outlinedIconButton_findByTagAndLongClick() {
+ var counter = 0
+ val onLongClick: () -> Unit = { ++counter }
+
+ rule.setContent {
+ Box {
+ OutlinedIconButton(
+ modifier = Modifier.testTag(OutlinedIconButtonTag),
+ onClick = {},
+ onLongClick = onLongClick
+ ) {
+ Box(
+ modifier = Modifier
+ .size(OutlinedIconButtonDefaults.MediumIconSize)
+ .semantics(mergeDescendants = true) {}
+ )
+ }
+ }
+ }
+ rule.onNodeWithTag(OutlinedIconButtonTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ rule.runOnIdle {
+ Truth.assertThat(counter).isEqualTo(1)
+ }
+ }
+
+ @Test
fun outlinedIconButton_canBeDisabled() {
rule.setContent {
var enabled by remember { mutableStateOf(true) }
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/SurfaceTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/SurfaceTest.kt
index 9684230..2444592 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/SurfaceTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/SurfaceTest.kt
@@ -17,6 +17,8 @@
package androidx.tv.material3
import android.os.Build
+import android.os.SystemClock
+import android.view.KeyEvent
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.FocusInteraction
@@ -25,6 +27,7 @@
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
@@ -36,13 +39,13 @@
import androidx.compose.testutils.assertContainsColor
import androidx.compose.testutils.assertDoesNotContainColor
import androidx.compose.testutils.assertShape
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.nativeKeyCode
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.Role
@@ -52,23 +55,27 @@
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.assert
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsFocused
import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsNotFocused
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.performKeyPress
import androidx.compose.ui.test.performSemanticsAction
import androidx.compose.ui.test.pressKey
import androidx.compose.ui.unit.Dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
-import androidx.test.filters.MediumTest
+import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
import androidx.tv.material3.tokens.Elevation
import com.google.common.truth.Truth
@@ -83,11 +90,10 @@
Truth.assertThat(abs(a - b)).isLessThan(0.0001f)
@OptIn(
- ExperimentalComposeUiApi::class,
ExperimentalTestApi::class,
ExperimentalTvMaterial3Api::class
)
-@MediumTest
+@LargeTest
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
class SurfaceTest {
@@ -214,6 +220,31 @@
}
@Test
+ fun clickableOverload_longClickSemantics() {
+ val count = mutableStateOf(0)
+ rule.setContent {
+ Surface(
+ modifier = Modifier
+ .testTag("surface"),
+ onClick = { },
+ onLongClick = { count.value += 1 }
+ ) {
+ Text("${count.value}")
+ Spacer(Modifier.size(30.toDp()))
+ }
+ }
+ rule.onNodeWithTag("surface")
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .assertHasClickAction()
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
+ .assertIsEnabled()
+ // since we merge descendants we should have text on the same node
+ .assertTextEquals("0")
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ .assertTextEquals("1")
+ }
+
+ @Test
fun clickableOverload_customSemantics() {
val count = mutableStateOf(0)
rule.setContent {
@@ -262,6 +293,67 @@
}
@Test
+ fun clickableOverload_longClickAction() {
+ val count = mutableStateOf(0)
+
+ rule.setContent {
+ Surface(
+ modifier = Modifier
+ .testTag("surface"),
+ onClick = { },
+ onLongClick = { count.value += 1 }
+ ) {
+ Spacer(modifier = Modifier.size(30.toDp()))
+ }
+ }
+
+ rule.onNodeWithTag("surface")
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter, 1)
+ Truth.assertThat(count.value).isEqualTo(1)
+
+ rule.onNodeWithTag("surface")
+ .performLongKeyPress(rule, Key.DirectionCenter, 1, 2)
+ Truth.assertThat(count.value).isEqualTo(3)
+ }
+
+ @Test
+ fun clickableOverload_clickAction_withLongClick() {
+ val count1 = mutableStateOf(0)
+ val count2 = mutableStateOf(0)
+
+ rule.setContent {
+ Surface(
+ modifier = Modifier
+ .testTag("surface"),
+ onClick = { count1.value += 1 },
+ onLongClick = { count2.value += 1 }
+ ) {
+ Spacer(modifier = Modifier.size(30.toDp()))
+ }
+ }
+
+ rule.onNodeWithTag("surface")
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performKeyInput { pressKey(Key.DirectionCenter) }
+ .performLongKeyPress(rule, Key.DirectionCenter, 1)
+ Truth.assertThat(count1.value).isEqualTo(1)
+ Truth.assertThat(count2.value).isEqualTo(1)
+
+ rule.onNodeWithTag("surface")
+ .performKeyInput { pressKey(Key.DirectionCenter) }
+ .performKeyInput { pressKey(Key.DirectionCenter) }
+ Truth.assertThat(count1.value).isEqualTo(3)
+ Truth.assertThat(count2.value).isEqualTo(1)
+
+ rule.onNodeWithTag("surface")
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter, 1, 2)
+ Truth.assertThat(count1.value).isEqualTo(3)
+ Truth.assertThat(count2.value).isEqualTo(3)
+ }
+
+ @Test
fun clickableSurface_onDisable_clickFails() {
val count = mutableStateOf(0f)
val enabled = mutableStateOf(true)
@@ -369,6 +461,47 @@
Truth.assertThat(isPressed).isTrue()
}
+ @Test
+ fun clickableSurface_onFocusChange_releasesPressInteraction() {
+ val interactionSource = MutableInteractionSource()
+ var isPressed by mutableStateOf(false)
+
+ rule.setContent {
+ isPressed = interactionSource.collectIsPressedAsState().value
+ Column {
+ Surface(
+ modifier = Modifier
+ .testTag("surface-1")
+ .size(100.toDp()),
+ onClick = {},
+ interactionSource = interactionSource
+ ) {}
+ Surface(
+ modifier = Modifier
+ .testTag("surface-2")
+ .size(100.toDp()),
+ onClick = {}
+ ) {}
+ }
+ }
+
+ with(rule.onNodeWithTag("surface-1")) {
+ performSemanticsAction(SemanticsActions.RequestFocus)
+ assertIsFocused()
+ performKeyInput { keyDown(Key.DirectionCenter) }
+ }
+
+ rule.waitUntil(condition = { isPressed })
+
+ Truth.assertThat(isPressed).isTrue()
+
+ rule.onNodeWithTag("surface-1")
+ .performKeyInput { pressKey(Key.DirectionDown) }
+ .assertIsNotFocused()
+
+ Truth.assertThat(isPressed).isFalse()
+ }
+
@FlakyTest(bugId = 269229262)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
@@ -489,6 +622,32 @@
}
@Test
+ fun toggleable_longClickSemantics() {
+ var isChecked by mutableStateOf(false)
+ rule.setContent {
+ Surface(
+ checked = isChecked,
+ modifier = Modifier
+ .testTag("surface"),
+ onCheckedChange = { },
+ onLongClick = { isChecked = !isChecked }
+ ) {
+ Text("$isChecked")
+ Spacer(Modifier.size(30.toDp()))
+ }
+ }
+ rule.onNodeWithTag("surface")
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .assertHasClickAction()
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
+ .assertIsEnabled()
+ // since we merge descendants we should have text on the same node
+ .assertTextEquals("false")
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ .assertTextEquals("true")
+ }
+
+ @Test
fun toggleable_customSemantics() {
var isChecked by mutableStateOf(false)
rule.setContent {
@@ -538,6 +697,69 @@
}
@Test
+ fun toggleable_longClickAction() {
+ val count = mutableStateOf(0)
+
+ rule.setContent {
+ Surface(
+ checked = false,
+ modifier = Modifier
+ .testTag("surface"),
+ onCheckedChange = { },
+ onLongClick = { count.value += 1 }
+ ) {
+ Spacer(modifier = Modifier.size(30.toDp()))
+ }
+ }
+
+ rule.onNodeWithTag("surface")
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter, 1)
+ Truth.assertThat(count.value).isEqualTo(1)
+
+ rule.onNodeWithTag("surface")
+ .performLongKeyPress(rule, Key.DirectionCenter, 1, 2)
+ Truth.assertThat(count.value).isEqualTo(3)
+ }
+
+ @Test
+ fun toggleable_clickAction_withLongClick() {
+ val count1 = mutableStateOf(0)
+ val count2 = mutableStateOf(0)
+
+ rule.setContent {
+ Surface(
+ checked = false,
+ modifier = Modifier
+ .testTag("surface"),
+ onCheckedChange = { count1.value += 1 },
+ onLongClick = { count2.value += 1 }
+ ) {
+ Spacer(modifier = Modifier.size(30.toDp()))
+ }
+ }
+
+ rule.onNodeWithTag("surface")
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performKeyInput { pressKey(Key.DirectionCenter) }
+ .performLongKeyPress(rule, Key.DirectionCenter, 1)
+ Truth.assertThat(count1.value).isEqualTo(1)
+ Truth.assertThat(count2.value).isEqualTo(1)
+
+ rule.onNodeWithTag("surface")
+ .performKeyInput { pressKey(Key.DirectionCenter) }
+ .performKeyInput { pressKey(Key.DirectionCenter) }
+ Truth.assertThat(count1.value).isEqualTo(3)
+ Truth.assertThat(count2.value).isEqualTo(1)
+
+ rule.onNodeWithTag("surface")
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter, 1, 2)
+ Truth.assertThat(count1.value).isEqualTo(3)
+ Truth.assertThat(count2.value).isEqualTo(3)
+ }
+
+ @Test
fun toggleable_enabled_disabled() {
var isChecked by mutableStateOf(false)
var enabled by mutableStateOf(true)
@@ -647,6 +869,48 @@
Truth.assertThat(isPressed).isTrue()
}
+ @Test
+ fun toggleableSurface_onFocusChange_releasesPressInteraction() {
+ val interactionSource = MutableInteractionSource()
+ var isPressed by mutableStateOf(false)
+
+ rule.setContent {
+ isPressed = interactionSource.collectIsPressedAsState().value
+ Column {
+ Surface(
+ checked = false,
+ modifier = Modifier
+ .testTag("surface-1")
+ .size(100.toDp()),
+ onCheckedChange = {},
+ interactionSource = interactionSource
+ ) {}
+ Surface(
+ modifier = Modifier
+ .testTag("surface-2")
+ .size(100.toDp()),
+ onClick = {}
+ ) {}
+ }
+ }
+
+ with(rule.onNodeWithTag("surface-1")) {
+ performSemanticsAction(SemanticsActions.RequestFocus)
+ assertIsFocused()
+ performKeyInput { keyDown(Key.DirectionCenter) }
+ }
+
+ rule.waitUntil(condition = { isPressed })
+
+ Truth.assertThat(isPressed).isTrue()
+
+ rule.onNodeWithTag("surface-1")
+ .performKeyInput { pressKey(Key.DirectionDown) }
+ .assertIsNotFocused()
+
+ Truth.assertThat(isPressed).isFalse()
+ }
+
@FlakyTest(bugId = 269229262)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
@@ -793,3 +1057,37 @@
rule.onNodeWithTag("surface").captureToImage().assertContainsColor(Color.Red)
}
}
+
+internal fun SemanticsNodeInteraction.performLongKeyPress(
+ rule: ComposeContentTestRule,
+ key: Key,
+ keyRepeatCount: Int = 1,
+ count: Int = 1
+): SemanticsNodeInteraction {
+ repeat(count) {
+ // Trigger the first key down event to simulate key press
+ val firstKeyDownEvent = KeyEvent(
+ SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ KeyEvent.ACTION_DOWN, key.nativeKeyCode, 0, 0, 0, 0
+ )
+ this.performKeyPress(androidx.compose.ui.input.key.KeyEvent(firstKeyDownEvent))
+ rule.waitForIdle()
+
+ // Trigger multiple key down events with repeat count (>0) to simulate key long press
+ val repeatedKeyDownEvent = KeyEvent(
+ SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ KeyEvent.ACTION_DOWN, key.nativeKeyCode, keyRepeatCount, 0, 0, 0
+ )
+ this.performKeyPress(androidx.compose.ui.input.key.KeyEvent(repeatedKeyDownEvent))
+ rule.waitForIdle()
+
+ // Trigger the final key up event to simulate key release
+ val keyUpEvent = KeyEvent(
+ SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ KeyEvent.ACTION_UP, key.nativeKeyCode, 0, 0, 0, 0
+ )
+ this.performKeyPress(androidx.compose.ui.input.key.KeyEvent(keyUpEvent))
+ rule.waitForIdle()
+ }
+ return this
+}
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/TextTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/TextTest.kt
index 3969b0a..97f4fe5 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/TextTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/TextTest.kt
@@ -35,7 +35,7 @@
import androidx.compose.ui.unit.sp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
-import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -57,6 +57,27 @@
private val TestText = "TestText"
+ @OptIn(ExperimentalTvMaterial3Api::class)
+ @Test
+ fun testDefaultIncludeFontPadding() {
+ var localTextStyle: TextStyle? = null
+ var display1TextStyle: TextStyle? = null
+ rule.setContent {
+ MaterialTheme {
+ localTextStyle = LocalTextStyle.current
+ display1TextStyle = LocalTypography.current.displayMedium
+ }
+ }
+
+ assertThat(
+ localTextStyle?.platformStyle?.paragraphStyle?.includeFontPadding
+ ).isEqualTo(false)
+
+ assertThat(
+ display1TextStyle?.platformStyle?.paragraphStyle?.includeFontPadding
+ ).isEqualTo(false)
+ }
+
@Test
fun inheritsThemeTextStyle() {
var textColor: Color? = null
@@ -82,11 +103,11 @@
}
rule.runOnIdle {
- Truth.assertThat(textColor).isEqualTo(ExpectedTextStyle.color)
- Truth.assertThat(textAlign).isEqualTo(ExpectedTextStyle.textAlign)
- Truth.assertThat(fontSize).isEqualTo(ExpectedTextStyle.fontSize)
- Truth.assertThat(fontStyle).isEqualTo(ExpectedTextStyle.fontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(ExpectedTextStyle.letterSpacing)
+ assertThat(textColor).isEqualTo(ExpectedTextStyle.color)
+ assertThat(textAlign).isEqualTo(ExpectedTextStyle.textAlign)
+ assertThat(fontSize).isEqualTo(ExpectedTextStyle.fontSize)
+ assertThat(fontStyle).isEqualTo(ExpectedTextStyle.fontStyle)
+ assertThat(letterSpacing).isEqualTo(ExpectedTextStyle.letterSpacing)
}
}
@@ -123,11 +144,11 @@
}
rule.runOnIdle {
- Truth.assertThat(textColor).isEqualTo(testStyle.color)
- Truth.assertThat(textAlign).isEqualTo(testStyle.textAlign)
- Truth.assertThat(fontSize).isEqualTo(testStyle.fontSize)
- Truth.assertThat(fontStyle).isEqualTo(testStyle.fontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(testStyle.letterSpacing)
+ assertThat(textColor).isEqualTo(testStyle.color)
+ assertThat(textAlign).isEqualTo(testStyle.textAlign)
+ assertThat(fontSize).isEqualTo(testStyle.fontSize)
+ assertThat(fontStyle).isEqualTo(testStyle.fontStyle)
+ assertThat(letterSpacing).isEqualTo(testStyle.letterSpacing)
}
}
@@ -166,10 +187,10 @@
rule.runOnIdle {
// explicit parameters should override values from the style.
- Truth.assertThat(textAlign).isEqualTo(expectedTextAlign)
- Truth.assertThat(fontSize).isEqualTo(expectedFontSize)
- Truth.assertThat(fontStyle).isEqualTo(expectedFontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
+ assertThat(textAlign).isEqualTo(expectedTextAlign)
+ assertThat(fontSize).isEqualTo(expectedFontSize)
+ assertThat(fontStyle).isEqualTo(expectedFontStyle)
+ assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
}
}
@@ -210,10 +231,10 @@
rule.runOnIdle {
// explicit parameters should override values from the style.
- Truth.assertThat(textAlign).isEqualTo(expectedTextAlign)
- Truth.assertThat(fontSize).isEqualTo(expectedFontSize)
- Truth.assertThat(fontStyle).isEqualTo(expectedFontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
+ assertThat(textAlign).isEqualTo(expectedTextAlign)
+ assertThat(fontSize).isEqualTo(expectedFontSize)
+ assertThat(fontStyle).isEqualTo(expectedFontStyle)
+ assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
}
}
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/WideButtonTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/WideButtonTest.kt
index d7d9625..8fadae5 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/WideButtonTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/WideButtonTest.kt
@@ -25,7 +25,6 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.platform.testTag
@@ -55,7 +54,6 @@
import org.junit.runner.RunWith
@OptIn(
- ExperimentalComposeUiApi::class,
ExperimentalTestApi::class,
ExperimentalTvMaterial3Api::class
)
@@ -85,6 +83,32 @@
rule.onNodeWithTag(WideButtonTag)
.assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertHasClickAction()
+ .assertIsEnabled()
+ }
+
+ @Test
+ fun wideButton_longClickSemantics() {
+ rule.setContent {
+ Box {
+ WideButton(
+ onClick = { },
+ onLongClick = {},
+ modifier = Modifier
+ .testTag(WideButtonTag),
+ title = { Text(text = "Settings") },
+ icon = {
+ Icon(imageVector = Icons.Default.Settings, contentDescription = "")
+ },
+ subtitle = { Text(text = "Update device preferences") }
+ )
+ }
+ }
+
+ rule.onNodeWithTag(WideButtonTag)
+ .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertHasClickAction()
+ .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
.assertIsEnabled()
}
@@ -139,6 +163,35 @@
}
@Test
+ fun wideButton_findByTagAndLongClick() {
+ var counter = 0
+ val onLongClick: () -> Unit = { ++counter }
+
+ rule.setContent {
+ Box {
+ WideButton(
+ onClick = {},
+ onLongClick = onLongClick,
+ modifier = Modifier
+ .testTag(WideButtonTag),
+ title = { Text(text = "Settings") },
+ icon = {
+ Icon(imageVector = Icons.Default.Settings, contentDescription = "")
+ },
+ subtitle = { Text(text = "Update device preferences") }
+ )
+ }
+ }
+
+ rule.onNodeWithTag(WideButtonTag)
+ .performSemanticsAction(SemanticsActions.RequestFocus)
+ .performLongKeyPress(rule, Key.DirectionCenter)
+ rule.runOnIdle {
+ Truth.assertThat(counter).isEqualTo(1)
+ }
+ }
+
+ @Test
fun wideButton_canBeDisabled() {
rule.setContent {
var enabled by remember { mutableStateOf(true) }
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Button.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Button.kt
index 6d4dee9..19b95d4 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Button.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Button.kt
@@ -54,6 +54,7 @@
*
* @param onClick called when this button is clicked
* @param modifier the [Modifier] to be applied to this button
+ * @param onLongClick called when this button is long clicked (long-pressed).
* @param enabled controls the enabled state of this button. When `false`, this component will not
* respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
@@ -77,6 +78,7 @@
fun Button(
onClick: () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
enabled: Boolean = true,
scale: ButtonScale = ButtonDefaults.scale(),
glow: ButtonGlow = ButtonDefaults.glow(),
@@ -91,6 +93,7 @@
ButtonImpl(
onClick = onClick,
modifier = modifier,
+ onLongClick = onLongClick,
enabled = enabled,
scale = scale,
glow = glow,
@@ -124,6 +127,7 @@
*
* @param onClick called when this button is clicked
* @param modifier the [Modifier] to be applied to this button
+ * @param onLongClick called when this button is long clicked (long-pressed).
* @param enabled controls the enabled state of this button. When `false`, this component will not
* respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
@@ -147,6 +151,7 @@
fun OutlinedButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
enabled: Boolean = true,
scale: ButtonScale = OutlinedButtonDefaults.scale(),
glow: ButtonGlow = OutlinedButtonDefaults.glow(),
@@ -161,6 +166,7 @@
ButtonImpl(
onClick = onClick,
modifier = modifier,
+ onLongClick = onLongClick,
enabled = enabled,
scale = scale,
glow = glow,
@@ -179,6 +185,7 @@
private fun ButtonImpl(
onClick: () -> Unit,
modifier: Modifier,
+ onLongClick: (() -> Unit)? = null,
enabled: Boolean,
scale: ButtonScale,
glow: ButtonGlow,
@@ -193,6 +200,7 @@
Surface(
modifier = modifier.semantics { role = Role.Button },
onClick = onClick,
+ onLongClick = onLongClick,
enabled = enabled,
scale = scale.toClickableSurfaceScale(),
glow = glow.toClickableSurfaceGlow(),
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/ButtonStyles.kt b/tv/tv-material/src/main/java/androidx/tv/material3/ButtonStyles.kt
index 3661d23..554dea1 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/ButtonStyles.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/ButtonStyles.kt
@@ -203,6 +203,19 @@
return "ButtonScale(scale=$scale, focusedScale=$focusedScale, pressedScale=$pressedScale," +
" disabledScale=$disabledScale, focusedDisabledScale=$focusedDisabledScale)"
}
+
+ companion object {
+ /**
+ * Signifies the absence of a [ScaleIndication] in Button component.
+ */
+ val None = ButtonScale(
+ scale = 1f,
+ focusedScale = 1f,
+ pressedScale = 1f,
+ disabledScale = 1f,
+ focusedDisabledScale = 1f
+ )
+ }
}
/**
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
index 38550b6..8f84169 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
@@ -48,8 +48,9 @@
*
* @sample androidx.tv.samples.CardSample
*
- * @param onClick called when this card is clicked
- * @param modifier the [Modifier] to be applied to this card
+ * @param onClick called when this card is clicked.
+ * @param modifier the [Modifier] to be applied to this card.
+ * @param onLongClick called when this card is long clicked (long-pressed).
* @param shape [CardShape] defines the shape of this card's container in different interaction
* states. See [CardDefaults.shape].
* @param colors [CardColors] defines the background & content colors used in this card for
@@ -70,6 +71,7 @@
fun Card(
onClick: () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
shape: CardShape = CardDefaults.shape(),
colors: CardColors = CardDefaults.colors(),
scale: CardScale = CardDefaults.scale(),
@@ -80,6 +82,7 @@
) {
Surface(
onClick = onClick,
+ onLongClick = onLongClick,
modifier = modifier,
shape = shape.toClickableSurfaceShape(),
colors = colors.toClickableSurfaceColors(),
@@ -103,10 +106,11 @@
*
* @sample androidx.tv.samples.ClassicCardSample
*
- * @param onClick called when this card is clicked
+ * @param onClick called when this card is clicked.
* @param image defines the [Composable] image to be displayed on top of the Card.
* @param title defines the [Composable] title placed below the image in the Card.
* @param modifier the [Modifier] to be applied to this card.
+ * @param onLongClick called when this card is long clicked (long-pressed).
* @param subtitle defines the [Composable] supporting text placed below the title of the Card.
* @param description defines the [Composable] description placed below the subtitle of the Card.
* @param shape [CardShape] defines the shape of this card's container in different interaction
@@ -131,6 +135,7 @@
image: @Composable BoxScope.() -> Unit,
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
subtitle: @Composable () -> Unit = {},
description: @Composable () -> Unit = {},
shape: CardShape = CardDefaults.shape(),
@@ -143,6 +148,7 @@
) {
Card(
onClick = onClick,
+ onLongClick = onLongClick,
modifier = modifier,
interactionSource = interactionSource,
shape = shape,
@@ -181,10 +187,11 @@
*
* @sample androidx.tv.samples.CompactCardSample
*
- * @param onClick called when this card is clicked
+ * @param onClick called when this card is clicked.
* @param image defines the [Composable] image to be displayed on top of the Card.
* @param title defines the [Composable] title placed below the image in the Card.
* @param modifier the [Modifier] to be applied to this card.
+ * @param onLongClick called when this card is long clicked (long-pressed).
* @param subtitle defines the [Composable] supporting text placed below the title of the Card.
* @param description defines the [Composable] description placed below the subtitle of the Card.
* @param shape [CardShape] defines the shape of this card's container in different interaction
@@ -210,6 +217,7 @@
image: @Composable BoxScope.() -> Unit,
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
subtitle: @Composable () -> Unit = {},
description: @Composable () -> Unit = {},
shape: CardShape = CardDefaults.shape(),
@@ -222,6 +230,7 @@
) {
Card(
onClick = onClick,
+ onLongClick = onLongClick,
modifier = modifier,
interactionSource = interactionSource,
shape = shape,
@@ -264,10 +273,11 @@
*
* @sample androidx.tv.samples.WideClassicCardSample
*
- * @param onClick called when this card is clicked
+ * @param onClick called when this card is clicked.
* @param image defines the [Composable] image to be displayed on top of the Card.
* @param title defines the [Composable] title placed below the image in the Card.
* @param modifier the [Modifier] to be applied to this card.
+ * @param onLongClick called when this card is long clicked (long-pressed).
* @param subtitle defines the [Composable] supporting text placed below the title of the Card.
* @param description defines the [Composable] description placed below the subtitle of the Card.
* @param shape [CardShape] defines the shape of this card's container in different interaction
@@ -292,6 +302,7 @@
image: @Composable BoxScope.() -> Unit,
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
subtitle: @Composable () -> Unit = {},
description: @Composable () -> Unit = {},
shape: CardShape = CardDefaults.shape(),
@@ -304,6 +315,7 @@
) {
Card(
onClick = onClick,
+ onLongClick = onLongClick,
modifier = modifier,
interactionSource = interactionSource,
shape = shape,
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/CardLayout.kt b/tv/tv-material/src/main/java/androidx/tv/material3/CardLayout.kt
index df431a3..29c82d3 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/CardLayout.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/CardLayout.kt
@@ -195,11 +195,12 @@
*
* This Card handles click events, calling its [onClick] lambda.
*
- * @param onClick called when this card is clicked
+ * @param onClick called when this card is clicked.
* @param interactionSource the [MutableInteractionSource] representing the stream of
* [Interaction]s for this card. When using with the CardLayout(s), it is recommended to
* pass in the interaction state obtained from the parent lambda.
- * @param modifier the [Modifier] to be applied to this card
+ * @param modifier the [Modifier] to be applied to this card.
+ * @param onLongClick called when this card is long clicked (long-pressed).
* @param shape [CardShape] defines the shape of this card's container in different interaction
* states. See [CardDefaults.shape].
* @param colors [CardColors] defines the background & content colors used in this card for
@@ -217,6 +218,7 @@
onClick: () -> Unit,
interactionSource: MutableInteractionSource,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
shape: CardShape = CardDefaults.shape(),
colors: CardColors = CardDefaults.colors(),
scale: CardScale = CardDefaults.scale(),
@@ -226,6 +228,7 @@
) {
Card(
onClick = onClick,
+ onLongClick = onLongClick,
modifier = modifier,
shape = shape,
colors = colors,
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/CardStyles.kt b/tv/tv-material/src/main/java/androidx/tv/material3/CardStyles.kt
index 6df86c2..6856416 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/CardStyles.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/CardStyles.kt
@@ -143,6 +143,17 @@
override fun toString(): String {
return "CardScale(scale=$scale, focusedScale=$focusedScale, pressedScale=$pressedScale)"
}
+
+ companion object {
+ /**
+ * Signifies the absence of a [ScaleIndication] in Card component.
+ */
+ val None = CardScale(
+ scale = 1f,
+ focusedScale = 1f,
+ pressedScale = 1f
+ )
+ }
}
/**
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt
index dc403a6..e811d70 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt
@@ -224,6 +224,10 @@
doAutoScroll: Boolean,
onAutoScrollChange: (isAutoScrollActive: Boolean) -> Unit = {},
) {
+ if (autoScrollDurationMillis == Long.MAX_VALUE || autoScrollDurationMillis < 0) {
+ return
+ }
+
// Needed to ensure that the code within LaunchedEffect receives updates to the itemCount.
val updatedItemCount by rememberUpdatedState(newValue = itemCount)
if (doAutoScroll) {
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/IconButton.kt b/tv/tv-material/src/main/java/androidx/tv/material3/IconButton.kt
index bc0b098..b5c27f2 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/IconButton.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/IconButton.kt
@@ -44,8 +44,9 @@
*
* @sample androidx.tv.samples.IconButtonSample
*
- * @param onClick called when this button is clicked
- * @param modifier the [Modifier] to be applied to this button
+ * @param onClick called when this button is clicked.
+ * @param modifier the [Modifier] to be applied to this button.
+ * @param onLongClick called when this button is long clicked (long-pressed).
* @param enabled controls the enabled state of this button. When `false`, this component will not
* respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
@@ -65,6 +66,7 @@
fun IconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
enabled: Boolean = true,
scale: ButtonScale = IconButtonDefaults.scale(),
glow: ButtonGlow = IconButtonDefaults.glow(),
@@ -79,6 +81,7 @@
.semantics { role = Role.Button }
.size(IconButtonDefaults.MediumButtonSize),
onClick = onClick,
+ onLongClick = onLongClick,
enabled = enabled,
shape = shape.toClickableSurfaceShape(),
colors = colors.toClickableSurfaceColors(),
@@ -110,8 +113,9 @@
*
* @sample androidx.tv.samples.OutlinedIconButtonSample
*
- * @param onClick called when this button is clicked
- * @param modifier the [Modifier] to be applied to this button
+ * @param onClick called when this button is clicked.
+ * @param modifier the [Modifier] to be applied to this button.
+ * @param onLongClick called when this card is long clicked (long-pressed).
* @param enabled controls the enabled state of this button. When `false`, this component will not
* respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
@@ -131,6 +135,7 @@
fun OutlinedIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
enabled: Boolean = true,
scale: ButtonScale = OutlinedIconButtonDefaults.scale(),
glow: ButtonGlow = OutlinedIconButtonDefaults.glow(),
@@ -145,6 +150,7 @@
.semantics { role = Role.Button }
.size(OutlinedIconButtonDefaults.MediumButtonSize),
onClick = onClick,
+ onLongClick = onLongClick,
enabled = enabled,
shape = shape.toClickableSurfaceShape(),
colors = colors.toClickableSurfaceColors(),
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt
index f21b2bf..fb71e65 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt
@@ -38,6 +38,7 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.drawWithCache
+import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
@@ -49,6 +50,7 @@
import androidx.compose.ui.platform.debugInspectorInfo
import androidx.compose.ui.semantics.disabled
import androidx.compose.ui.semantics.onClick
+import androidx.compose.ui.semantics.onLongClick
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
@@ -108,6 +110,7 @@
* @param onClick callback to be called when the surface is clicked. Note: DPad Enter button won't
* work if this value is null
* @param modifier Modifier to be applied to the layout corresponding to the surface
+ * @param onLongClick callback to be called when the surface is long clicked (long-pressed).
* @param enabled Controls the enabled state of the surface. When `false`, this Surface will not be
* clickable or focusable.
* @param tonalElevation When [color] is [ColorScheme.surface], a higher the elevation will result
@@ -129,6 +132,7 @@
fun Surface(
onClick: () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
enabled: Boolean = true,
tonalElevation: Dp = 0.dp,
shape: ClickableSurfaceShape = ClickableSurfaceDefaults.shape(),
@@ -145,6 +149,7 @@
modifier = modifier.tvClickable(
enabled = enabled,
onClick = onClick,
+ onLongClick = onLongClick,
interactionSource = interactionSource,
),
checked = false,
@@ -206,8 +211,10 @@
* To manually retrieve the content color inside a surface, use [LocalContentColor].
*
* @param checked whether or not this Surface is toggled on or off
- * @param onCheckedChange callback to be invoked when the toggleable Surface is clicked
- * @param modifier Modifier to be applied to the layout corresponding to the surface
+ * @param onCheckedChange callback to be invoked when the toggleable Surface is clicked.
+ * @param modifier [Modifier] to be applied to the layout corresponding to the surface
+ * @param onLongClick callback to be called when the toggleable surface is long clicked
+ * (long-pressed).
* @param enabled Controls the enabled state of the surface. When `false`, this Surface will not be
* clickable or focusable.
* @param tonalElevation When [color] is [ColorScheme.surface], a higher the elevation will result
@@ -231,6 +238,7 @@
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
+ onLongClick: (() -> Unit)? = null,
tonalElevation: Dp = Elevation.Level0,
shape: ToggleableSurfaceShape = ToggleableSurfaceDefaults.shape(),
colors: ToggleableSurfaceColors = ToggleableSurfaceDefaults.colors(),
@@ -249,6 +257,7 @@
checked = checked,
onCheckedChange = onCheckedChange,
interactionSource = interactionSource,
+ onLongClick = onLongClick
),
checked = checked,
enabled = enabled,
@@ -408,18 +417,21 @@
/**
* This modifier handles click, press, and focus events for a TV composable.
* @param enabled decides whether [onClick] is executed
- * @param onClick executes the provided lambda
+ * @param onClick executes the provided lambda on click.
+ * @param onLongClick executes the provided lambda on long press.
* @param interactionSource used to emit [PressInteraction] events
*/
private fun Modifier.tvClickable(
enabled: Boolean,
onClick: (() -> Unit)?,
+ onLongClick: (() -> Unit)?,
interactionSource: MutableInteractionSource
) = handleDPadEnter(
- enabled = enabled,
- interactionSource = interactionSource,
- onClick = onClick
-)
+ enabled = enabled,
+ interactionSource = interactionSource,
+ onClick = onClick,
+ onLongClick = onLongClick
+ )
// We are not using "clickable" modifier here because if we set "enabled" to false
// then the Surface won't be focusable as well. But, in TV use case, a disabled surface
// should be focusable
@@ -432,6 +444,13 @@
}
false
}
+ onLongClick {
+ onLongClick?.let { nnOnLongClick ->
+ nnOnLongClick()
+ return@onLongClick true
+ }
+ false
+ }
if (!enabled) {
disabled()
}
@@ -441,29 +460,40 @@
* This modifier handles click, press, and focus events for a TV composable.
* @param enabled decides whether [onCheckedChange] is executed
* @param checked differentiates whether the current item is checked or unchecked
- * @param onCheckedChange executes the provided lambda while returning the inverse state of
- * [checked]
+ * @param onCheckedChange executes the provided lambda on click, while returning the inverse state
+ * of [checked].
+ * @param onLongClick executes the provided lambda on long press.
+ * @param interactionSource used to emit [PressInteraction] events
*/
private fun Modifier.tvToggleable(
enabled: Boolean,
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
+ onLongClick: (() -> Unit)?,
interactionSource: MutableInteractionSource,
) = handleDPadEnter(
- enabled = enabled,
- interactionSource = interactionSource,
- checked = checked,
- onCheckedChanged = onCheckedChange
-)
+ enabled = enabled,
+ interactionSource = interactionSource,
+ checked = checked,
+ onCheckedChanged = onCheckedChange,
+ onLongClick = onLongClick
+ )
// We are not using "toggleable" modifier here because if we set "enabled" to false
// then the Surface won't be focusable as well. But, in TV use case, a disabled surface
// should be focusable
- .focusable(enabled = enabled, interactionSource = interactionSource)
+ .focusable(interactionSource = interactionSource)
.semantics(mergeDescendants = true) {
onClick {
onCheckedChange(!checked)
true
}
+ onLongClick {
+ onLongClick?.let { nnOnLongClick ->
+ nnOnLongClick()
+ return@onLongClick true
+ }
+ false
+ }
if (!enabled) {
disabled()
}
@@ -475,6 +505,7 @@
* @param enabled if this is false, the D-PAD enter event is ignored
* @param interactionSource used to emit [PressInteraction] events
* @param onClick this lambda will be triggered on D-PAD enter event
+ * @param onLongClick this lambda will be triggered when D-PAD enter is long pressed.
* @param checked differentiates whether the current item is checked or unchecked
* @param onCheckedChanged executes the provided lambda while returning the inverse state of
* [checked]
@@ -483,6 +514,7 @@
enabled: Boolean,
interactionSource: MutableInteractionSource,
onClick: (() -> Unit)? = null,
+ onLongClick: (() -> Unit)? = null,
checked: Boolean = false,
onCheckedChanged: ((Boolean) -> Unit)? = null
) = composed(
@@ -491,40 +523,65 @@
properties["enabled"] = enabled
properties["interactionSource"] = interactionSource
properties["onClick"] = onClick
+ properties["onLongClick"] = onLongClick
properties["checked"] = checked
properties["onCheckedChanged"] = onCheckedChanged
}
) {
+ if (!enabled) return@composed this
+
val coroutineScope = rememberCoroutineScope()
val pressInteraction = remember { PressInteraction.Press(Offset.Zero) }
- var isPressed by remember { mutableStateOf(false) }
- onKeyEvent { keyEvent ->
- if (AcceptableKeys.any { keyEvent.nativeKeyEvent.keyCode == it } && enabled) {
- when (keyEvent.nativeKeyEvent.action) {
- NativeKeyEvent.ACTION_DOWN -> {
- if (!isPressed) {
- isPressed = true
- coroutineScope.launch {
- interactionSource.emit(pressInteraction)
- }
- }
- }
+ var isLongClick by remember { mutableStateOf(false) }
+ val isPressed by interactionSource.collectIsPressedAsState()
- NativeKeyEvent.ACTION_UP -> {
- if (isPressed) {
- isPressed = false
- coroutineScope.launch {
- interactionSource.emit(PressInteraction.Release(pressInteraction))
- }
- onClick?.invoke()
- onCheckedChanged?.invoke(!checked)
- }
+ this
+ .onFocusChanged {
+ if (!it.isFocused && isPressed) {
+ coroutineScope.launch {
+ interactionSource.emit(PressInteraction.Release(pressInteraction))
}
}
- return@onKeyEvent KeyEventPropagation.StopPropagation
}
- KeyEventPropagation.ContinuePropagation
- }
+ .onKeyEvent { keyEvent ->
+ if (AcceptableKeys.contains(keyEvent.nativeKeyEvent.keyCode)) {
+ when (keyEvent.nativeKeyEvent.action) {
+ NativeKeyEvent.ACTION_DOWN -> {
+ when (keyEvent.nativeKeyEvent.repeatCount) {
+ 0 ->
+ coroutineScope.launch {
+ interactionSource.emit(pressInteraction)
+ }
+
+ 1 ->
+ onLongClick?.let {
+ isLongClick = true
+ coroutineScope.launch {
+ interactionSource.emit(
+ PressInteraction.Release(
+ pressInteraction
+ )
+ )
+ }
+ it.invoke()
+ }
+ }
+ }
+
+ NativeKeyEvent.ACTION_UP -> {
+ if (!isLongClick) {
+ coroutineScope.launch {
+ interactionSource.emit(PressInteraction.Release(pressInteraction))
+ }
+ onClick?.invoke()
+ onCheckedChanged?.invoke(!checked)
+ } else isLongClick = false
+ }
+ }
+ return@onKeyEvent KeyEventPropagation.StopPropagation
+ }
+ KeyEventPropagation.ContinuePropagation
+ }
}
@Composable
@@ -573,7 +630,7 @@
* calculating surface tonal colors, and is *not* used for drawing the shadow in a [SurfaceImpl].
*/
val LocalAbsoluteTonalElevation = compositionLocalOf { 0.dp }
-private val AcceptableKeys = listOf(
+private val AcceptableKeys = hashSetOf(
NativeKeyEvent.KEYCODE_DPAD_CENTER,
NativeKeyEvent.KEYCODE_ENTER,
NativeKeyEvent.KEYCODE_NUMPAD_ENTER
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt b/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt
index 2da15cf..e915cd0 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt
@@ -390,6 +390,24 @@
"selectedDisabledScale=$selectedDisabledScale, " +
"focusedSelectedDisabledScale=$focusedSelectedDisabledScale)"
}
+
+ companion object {
+ /**
+ * Signifies the absence of a [ScaleIndication] in toggleable surface.
+ */
+ val None = ToggleableSurfaceScale(
+ scale = 1f,
+ focusedScale = 1f,
+ pressedScale = 1f,
+ selectedScale = 1f,
+ disabledScale = 1f,
+ focusedSelectedScale = 1f,
+ focusedDisabledScale = 1f,
+ pressedSelectedScale = 1f,
+ selectedDisabledScale = 1f,
+ focusedSelectedDisabledScale = 1f
+ )
+ }
}
/**
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/WideButton.kt b/tv/tv-material/src/main/java/androidx/tv/material3/WideButton.kt
index 5e59fbc..e167c56 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/WideButton.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/WideButton.kt
@@ -52,6 +52,7 @@
*
* @param onClick called when this button is clicked
* @param modifier the [Modifier] to be applied to this button
+ * @param onLongClick called when this button is long clicked (long-pressed).
* @param enabled controls the enabled state of this button. When `false`, this component will not
* respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
@@ -76,6 +77,7 @@
fun WideButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
background: @Composable () -> Unit = {
@@ -95,6 +97,7 @@
) {
WideButtonImpl(
onClick = onClick,
+ onLongClick = onLongClick,
enabled = enabled,
scale = scale,
glow = glow,
@@ -121,6 +124,7 @@
* @param onClick called when this button is clicked
* @param title the title content of the button, typically a [Text]
* @param modifier the [Modifier] to be applied to this button
+ * @param onLongClick called when this button is long clicked (long-pressed).
* @param enabled controls the enabled state of this button. When `false`, this component will not
* respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
@@ -147,6 +151,7 @@
onClick: () -> Unit,
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
enabled: Boolean = true,
icon: (@Composable () -> Unit)? = null,
subtitle: (@Composable () -> Unit)? = null,
@@ -168,6 +173,7 @@
WideButtonImpl(
onClick = onClick,
+ onLongClick = onLongClick,
enabled = enabled,
scale = scale,
glow = glow,
@@ -231,6 +237,7 @@
interactionSource: MutableInteractionSource,
background: @Composable () -> Unit,
modifier: Modifier = Modifier,
+ onLongClick: (() -> Unit)? = null,
minHeight: Dp = BaseWideButtonDefaults.MinHeight,
content: @Composable RowScope.() -> Unit
) {
@@ -241,6 +248,7 @@
Surface(
modifier = modifier.semantics { role = Role.Button },
onClick = onClick,
+ onLongClick = onLongClick,
enabled = enabled,
scale = scale.toClickableSurfaceScale(),
glow = glow.toClickableSurfaceGlow(),
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/tokens/TypographyTokens.kt b/tv/tv-material/src/main/java/androidx/tv/material3/tokens/TypographyTokens.kt
index 6e5b366..1491946 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/tokens/TypographyTokens.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/tokens/TypographyTokens.kt
@@ -143,7 +143,7 @@
)
}
-private const val DefaultIncludeFontPadding = true
+private const val DefaultIncludeFontPadding = false
@Suppress("DEPRECATION")
internal val DefaultTextStyle = TextStyle.Default.copy(
diff --git a/viewpager2/viewpager2/api/1.1.0-beta02.txt b/viewpager2/viewpager2/api/1.1.0-beta02.txt
index 997ce2a..2aabc06 100644
--- a/viewpager2/viewpager2/api/1.1.0-beta02.txt
+++ b/viewpager2/viewpager2/api/1.1.0-beta02.txt
@@ -2,8 +2,8 @@
package androidx.viewpager2.adapter {
public abstract class FragmentStateAdapter extends androidx.recyclerview.widget.RecyclerView.Adapter<androidx.viewpager2.adapter.FragmentViewHolder> implements androidx.viewpager2.adapter.StatefulAdapter {
- ctor public FragmentStateAdapter(androidx.fragment.app.FragmentActivity);
ctor public FragmentStateAdapter(androidx.fragment.app.Fragment);
+ ctor public FragmentStateAdapter(androidx.fragment.app.FragmentActivity);
ctor public FragmentStateAdapter(androidx.fragment.app.FragmentManager, androidx.lifecycle.Lifecycle);
method public boolean containsItem(long);
method public abstract androidx.fragment.app.Fragment createFragment(int);
@@ -19,11 +19,15 @@
method public void unregisterFragmentTransactionCallback(androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback);
}
+ @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.WARNING) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface FragmentStateAdapter.ExperimentalFragmentStateAdapterApi {
+ }
+
public abstract static class FragmentStateAdapter.FragmentTransactionCallback {
ctor public FragmentStateAdapter.FragmentTransactionCallback();
method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentMaxLifecyclePreUpdated(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreAdded(androidx.fragment.app.Fragment);
method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreRemoved(androidx.fragment.app.Fragment);
+ method @androidx.viewpager2.adapter.FragmentStateAdapter.ExperimentalFragmentStateAdapterApi public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreSavedInstanceState(androidx.fragment.app.Fragment);
}
public static interface FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener {
diff --git a/viewpager2/viewpager2/api/1.1.0-beta03.txt b/viewpager2/viewpager2/api/1.1.0-beta03.txt
new file mode 100644
index 0000000..2aabc06
--- /dev/null
+++ b/viewpager2/viewpager2/api/1.1.0-beta03.txt
@@ -0,0 +1,118 @@
+// Signature format: 4.0
+package androidx.viewpager2.adapter {
+
+ public abstract class FragmentStateAdapter extends androidx.recyclerview.widget.RecyclerView.Adapter<androidx.viewpager2.adapter.FragmentViewHolder> implements androidx.viewpager2.adapter.StatefulAdapter {
+ ctor public FragmentStateAdapter(androidx.fragment.app.Fragment);
+ ctor public FragmentStateAdapter(androidx.fragment.app.FragmentActivity);
+ ctor public FragmentStateAdapter(androidx.fragment.app.FragmentManager, androidx.lifecycle.Lifecycle);
+ method public boolean containsItem(long);
+ method public abstract androidx.fragment.app.Fragment createFragment(int);
+ method public final void onBindViewHolder(androidx.viewpager2.adapter.FragmentViewHolder, int);
+ method public final androidx.viewpager2.adapter.FragmentViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+ method public final boolean onFailedToRecycleView(androidx.viewpager2.adapter.FragmentViewHolder);
+ method public final void onViewAttachedToWindow(androidx.viewpager2.adapter.FragmentViewHolder);
+ method public final void onViewRecycled(androidx.viewpager2.adapter.FragmentViewHolder);
+ method public void registerFragmentTransactionCallback(androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback);
+ method public final void restoreState(android.os.Parcelable);
+ method public final android.os.Parcelable saveState();
+ method public final void setHasStableIds(boolean);
+ method public void unregisterFragmentTransactionCallback(androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback);
+ }
+
+ @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.WARNING) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface FragmentStateAdapter.ExperimentalFragmentStateAdapterApi {
+ }
+
+ public abstract static class FragmentStateAdapter.FragmentTransactionCallback {
+ ctor public FragmentStateAdapter.FragmentTransactionCallback();
+ method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentMaxLifecyclePreUpdated(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
+ method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreAdded(androidx.fragment.app.Fragment);
+ method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreRemoved(androidx.fragment.app.Fragment);
+ method @androidx.viewpager2.adapter.FragmentStateAdapter.ExperimentalFragmentStateAdapterApi public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreSavedInstanceState(androidx.fragment.app.Fragment);
+ }
+
+ public static interface FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener {
+ method public void onPost();
+ }
+
+ public final class FragmentViewHolder extends androidx.recyclerview.widget.RecyclerView.ViewHolder {
+ }
+
+ public interface StatefulAdapter {
+ method public void restoreState(android.os.Parcelable);
+ method public android.os.Parcelable saveState();
+ }
+
+}
+
+package androidx.viewpager2.widget {
+
+ public final class CompositePageTransformer implements androidx.viewpager2.widget.ViewPager2.PageTransformer {
+ ctor public CompositePageTransformer();
+ method public void addTransformer(androidx.viewpager2.widget.ViewPager2.PageTransformer);
+ method public void removeTransformer(androidx.viewpager2.widget.ViewPager2.PageTransformer);
+ method public void transformPage(android.view.View, float);
+ }
+
+ public final class MarginPageTransformer implements androidx.viewpager2.widget.ViewPager2.PageTransformer {
+ ctor public MarginPageTransformer(@Px int);
+ method public void transformPage(android.view.View, float);
+ }
+
+ public final class ViewPager2 extends android.view.ViewGroup {
+ ctor public ViewPager2(android.content.Context);
+ ctor public ViewPager2(android.content.Context, android.util.AttributeSet?);
+ ctor public ViewPager2(android.content.Context, android.util.AttributeSet?, int);
+ ctor @RequiresApi(21) public ViewPager2(android.content.Context, android.util.AttributeSet?, int, int);
+ method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
+ method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration, int);
+ method public boolean beginFakeDrag();
+ method public boolean endFakeDrag();
+ method public boolean fakeDragBy(@Px float);
+ method public androidx.recyclerview.widget.RecyclerView.Adapter? getAdapter();
+ method public int getCurrentItem();
+ method public androidx.recyclerview.widget.RecyclerView.ItemDecoration getItemDecorationAt(int);
+ method public int getItemDecorationCount();
+ method public int getOffscreenPageLimit();
+ method public int getOrientation();
+ method public int getScrollState();
+ method public void invalidateItemDecorations();
+ method public boolean isFakeDragging();
+ method public boolean isUserInputEnabled();
+ method public void registerOnPageChangeCallback(androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback);
+ method public void removeItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
+ method public void removeItemDecorationAt(int);
+ method public void requestTransform();
+ method public void setAdapter(androidx.recyclerview.widget.RecyclerView.Adapter?);
+ method public void setCurrentItem(int);
+ method public void setCurrentItem(int, boolean);
+ method public void setOffscreenPageLimit(int);
+ method public void setOrientation(int);
+ method public void setPageTransformer(androidx.viewpager2.widget.ViewPager2.PageTransformer?);
+ method public void setUserInputEnabled(boolean);
+ method public void unregisterOnPageChangeCallback(androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback);
+ field public static final int OFFSCREEN_PAGE_LIMIT_DEFAULT = -1; // 0xffffffff
+ field public static final int ORIENTATION_HORIZONTAL = 0; // 0x0
+ field public static final int ORIENTATION_VERTICAL = 1; // 0x1
+ field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
+ field public static final int SCROLL_STATE_IDLE = 0; // 0x0
+ field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
+ }
+
+ public abstract static class ViewPager2.OnPageChangeCallback {
+ ctor public ViewPager2.OnPageChangeCallback();
+ method public void onPageScrollStateChanged(int);
+ method public void onPageScrolled(int, float, @Px int);
+ method public void onPageSelected(int);
+ }
+
+ public static interface ViewPager2.PageTransformer {
+ method public void transformPage(android.view.View, float);
+ }
+
+ public final class WindowInsetsApplier implements androidx.core.view.OnApplyWindowInsetsListener {
+ method public static boolean install(androidx.viewpager2.widget.ViewPager2);
+ method public androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ }
+
+}
+
diff --git a/viewpager2/viewpager2/api/public_plus_experimental_1.1.0-beta02.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.1.0-beta02.txt
deleted file mode 100644
index 997ce2a..0000000
--- a/viewpager2/viewpager2/api/public_plus_experimental_1.1.0-beta02.txt
+++ /dev/null
@@ -1,114 +0,0 @@
-// Signature format: 4.0
-package androidx.viewpager2.adapter {
-
- public abstract class FragmentStateAdapter extends androidx.recyclerview.widget.RecyclerView.Adapter<androidx.viewpager2.adapter.FragmentViewHolder> implements androidx.viewpager2.adapter.StatefulAdapter {
- ctor public FragmentStateAdapter(androidx.fragment.app.FragmentActivity);
- ctor public FragmentStateAdapter(androidx.fragment.app.Fragment);
- ctor public FragmentStateAdapter(androidx.fragment.app.FragmentManager, androidx.lifecycle.Lifecycle);
- method public boolean containsItem(long);
- method public abstract androidx.fragment.app.Fragment createFragment(int);
- method public final void onBindViewHolder(androidx.viewpager2.adapter.FragmentViewHolder, int);
- method public final androidx.viewpager2.adapter.FragmentViewHolder onCreateViewHolder(android.view.ViewGroup, int);
- method public final boolean onFailedToRecycleView(androidx.viewpager2.adapter.FragmentViewHolder);
- method public final void onViewAttachedToWindow(androidx.viewpager2.adapter.FragmentViewHolder);
- method public final void onViewRecycled(androidx.viewpager2.adapter.FragmentViewHolder);
- method public void registerFragmentTransactionCallback(androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback);
- method public final void restoreState(android.os.Parcelable);
- method public final android.os.Parcelable saveState();
- method public final void setHasStableIds(boolean);
- method public void unregisterFragmentTransactionCallback(androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback);
- }
-
- public abstract static class FragmentStateAdapter.FragmentTransactionCallback {
- ctor public FragmentStateAdapter.FragmentTransactionCallback();
- method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentMaxLifecyclePreUpdated(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
- method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreAdded(androidx.fragment.app.Fragment);
- method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreRemoved(androidx.fragment.app.Fragment);
- }
-
- public static interface FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener {
- method public void onPost();
- }
-
- public final class FragmentViewHolder extends androidx.recyclerview.widget.RecyclerView.ViewHolder {
- }
-
- public interface StatefulAdapter {
- method public void restoreState(android.os.Parcelable);
- method public android.os.Parcelable saveState();
- }
-
-}
-
-package androidx.viewpager2.widget {
-
- public final class CompositePageTransformer implements androidx.viewpager2.widget.ViewPager2.PageTransformer {
- ctor public CompositePageTransformer();
- method public void addTransformer(androidx.viewpager2.widget.ViewPager2.PageTransformer);
- method public void removeTransformer(androidx.viewpager2.widget.ViewPager2.PageTransformer);
- method public void transformPage(android.view.View, float);
- }
-
- public final class MarginPageTransformer implements androidx.viewpager2.widget.ViewPager2.PageTransformer {
- ctor public MarginPageTransformer(@Px int);
- method public void transformPage(android.view.View, float);
- }
-
- public final class ViewPager2 extends android.view.ViewGroup {
- ctor public ViewPager2(android.content.Context);
- ctor public ViewPager2(android.content.Context, android.util.AttributeSet?);
- ctor public ViewPager2(android.content.Context, android.util.AttributeSet?, int);
- ctor @RequiresApi(21) public ViewPager2(android.content.Context, android.util.AttributeSet?, int, int);
- method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
- method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration, int);
- method public boolean beginFakeDrag();
- method public boolean endFakeDrag();
- method public boolean fakeDragBy(@Px float);
- method public androidx.recyclerview.widget.RecyclerView.Adapter? getAdapter();
- method public int getCurrentItem();
- method public androidx.recyclerview.widget.RecyclerView.ItemDecoration getItemDecorationAt(int);
- method public int getItemDecorationCount();
- method public int getOffscreenPageLimit();
- method public int getOrientation();
- method public int getScrollState();
- method public void invalidateItemDecorations();
- method public boolean isFakeDragging();
- method public boolean isUserInputEnabled();
- method public void registerOnPageChangeCallback(androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback);
- method public void removeItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
- method public void removeItemDecorationAt(int);
- method public void requestTransform();
- method public void setAdapter(androidx.recyclerview.widget.RecyclerView.Adapter?);
- method public void setCurrentItem(int);
- method public void setCurrentItem(int, boolean);
- method public void setOffscreenPageLimit(int);
- method public void setOrientation(int);
- method public void setPageTransformer(androidx.viewpager2.widget.ViewPager2.PageTransformer?);
- method public void setUserInputEnabled(boolean);
- method public void unregisterOnPageChangeCallback(androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback);
- field public static final int OFFSCREEN_PAGE_LIMIT_DEFAULT = -1; // 0xffffffff
- field public static final int ORIENTATION_HORIZONTAL = 0; // 0x0
- field public static final int ORIENTATION_VERTICAL = 1; // 0x1
- field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
- field public static final int SCROLL_STATE_IDLE = 0; // 0x0
- field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
- }
-
- public abstract static class ViewPager2.OnPageChangeCallback {
- ctor public ViewPager2.OnPageChangeCallback();
- method public void onPageScrollStateChanged(int);
- method public void onPageScrolled(int, float, @Px int);
- method public void onPageSelected(int);
- }
-
- public static interface ViewPager2.PageTransformer {
- method public void transformPage(android.view.View, float);
- }
-
- public final class WindowInsetsApplier implements androidx.core.view.OnApplyWindowInsetsListener {
- method public static boolean install(androidx.viewpager2.widget.ViewPager2);
- method public androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
- }
-
-}
-
diff --git a/viewpager2/viewpager2/api/res-1.1.0-beta03.txt b/viewpager2/viewpager2/api/res-1.1.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/viewpager2/viewpager2/api/res-1.1.0-beta03.txt
diff --git a/viewpager2/viewpager2/api/restricted_1.1.0-beta02.txt b/viewpager2/viewpager2/api/restricted_1.1.0-beta02.txt
index 4aab4bd..7a5c625 100644
--- a/viewpager2/viewpager2/api/restricted_1.1.0-beta02.txt
+++ b/viewpager2/viewpager2/api/restricted_1.1.0-beta02.txt
@@ -2,8 +2,8 @@
package androidx.viewpager2.adapter {
public abstract class FragmentStateAdapter extends androidx.recyclerview.widget.RecyclerView.Adapter<androidx.viewpager2.adapter.FragmentViewHolder> implements androidx.viewpager2.adapter.StatefulAdapter {
- ctor public FragmentStateAdapter(androidx.fragment.app.FragmentActivity);
ctor public FragmentStateAdapter(androidx.fragment.app.Fragment);
+ ctor public FragmentStateAdapter(androidx.fragment.app.FragmentActivity);
ctor public FragmentStateAdapter(androidx.fragment.app.FragmentManager, androidx.lifecycle.Lifecycle);
method public boolean containsItem(long);
method public abstract androidx.fragment.app.Fragment createFragment(int);
@@ -19,11 +19,15 @@
method public void unregisterFragmentTransactionCallback(androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback);
}
+ @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.WARNING) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface FragmentStateAdapter.ExperimentalFragmentStateAdapterApi {
+ }
+
public abstract static class FragmentStateAdapter.FragmentTransactionCallback {
ctor public FragmentStateAdapter.FragmentTransactionCallback();
method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentMaxLifecyclePreUpdated(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreAdded(androidx.fragment.app.Fragment);
method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreRemoved(androidx.fragment.app.Fragment);
+ method @androidx.viewpager2.adapter.FragmentStateAdapter.ExperimentalFragmentStateAdapterApi public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreSavedInstanceState(androidx.fragment.app.Fragment);
}
public static interface FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener {
diff --git a/viewpager2/viewpager2/api/restricted_1.1.0-beta03.txt b/viewpager2/viewpager2/api/restricted_1.1.0-beta03.txt
new file mode 100644
index 0000000..7a5c625
--- /dev/null
+++ b/viewpager2/viewpager2/api/restricted_1.1.0-beta03.txt
@@ -0,0 +1,127 @@
+// Signature format: 4.0
+package androidx.viewpager2.adapter {
+
+ public abstract class FragmentStateAdapter extends androidx.recyclerview.widget.RecyclerView.Adapter<androidx.viewpager2.adapter.FragmentViewHolder> implements androidx.viewpager2.adapter.StatefulAdapter {
+ ctor public FragmentStateAdapter(androidx.fragment.app.Fragment);
+ ctor public FragmentStateAdapter(androidx.fragment.app.FragmentActivity);
+ ctor public FragmentStateAdapter(androidx.fragment.app.FragmentManager, androidx.lifecycle.Lifecycle);
+ method public boolean containsItem(long);
+ method public abstract androidx.fragment.app.Fragment createFragment(int);
+ method public final void onBindViewHolder(androidx.viewpager2.adapter.FragmentViewHolder, int);
+ method public final androidx.viewpager2.adapter.FragmentViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+ method public final boolean onFailedToRecycleView(androidx.viewpager2.adapter.FragmentViewHolder);
+ method public final void onViewAttachedToWindow(androidx.viewpager2.adapter.FragmentViewHolder);
+ method public final void onViewRecycled(androidx.viewpager2.adapter.FragmentViewHolder);
+ method public void registerFragmentTransactionCallback(androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback);
+ method public final void restoreState(android.os.Parcelable);
+ method public final android.os.Parcelable saveState();
+ method public final void setHasStableIds(boolean);
+ method public void unregisterFragmentTransactionCallback(androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback);
+ }
+
+ @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.WARNING) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface FragmentStateAdapter.ExperimentalFragmentStateAdapterApi {
+ }
+
+ public abstract static class FragmentStateAdapter.FragmentTransactionCallback {
+ ctor public FragmentStateAdapter.FragmentTransactionCallback();
+ method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentMaxLifecyclePreUpdated(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
+ method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreAdded(androidx.fragment.app.Fragment);
+ method public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreRemoved(androidx.fragment.app.Fragment);
+ method @androidx.viewpager2.adapter.FragmentStateAdapter.ExperimentalFragmentStateAdapterApi public androidx.viewpager2.adapter.FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener onFragmentPreSavedInstanceState(androidx.fragment.app.Fragment);
+ }
+
+ public static interface FragmentStateAdapter.FragmentTransactionCallback.OnPostEventListener {
+ method public void onPost();
+ }
+
+ public final class FragmentViewHolder extends androidx.recyclerview.widget.RecyclerView.ViewHolder {
+ }
+
+ public interface StatefulAdapter {
+ method public void restoreState(android.os.Parcelable);
+ method public android.os.Parcelable saveState();
+ }
+
+}
+
+package androidx.viewpager2.widget {
+
+ public final class CompositePageTransformer implements androidx.viewpager2.widget.ViewPager2.PageTransformer {
+ ctor public CompositePageTransformer();
+ method public void addTransformer(androidx.viewpager2.widget.ViewPager2.PageTransformer);
+ method public void removeTransformer(androidx.viewpager2.widget.ViewPager2.PageTransformer);
+ method public void transformPage(android.view.View, float);
+ }
+
+ public final class MarginPageTransformer implements androidx.viewpager2.widget.ViewPager2.PageTransformer {
+ ctor public MarginPageTransformer(@Px int);
+ method public void transformPage(android.view.View, float);
+ }
+
+ public final class ViewPager2 extends android.view.ViewGroup {
+ ctor public ViewPager2(android.content.Context);
+ ctor public ViewPager2(android.content.Context, android.util.AttributeSet?);
+ ctor public ViewPager2(android.content.Context, android.util.AttributeSet?, int);
+ ctor @RequiresApi(21) public ViewPager2(android.content.Context, android.util.AttributeSet?, int, int);
+ method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
+ method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration, int);
+ method public boolean beginFakeDrag();
+ method public boolean endFakeDrag();
+ method public boolean fakeDragBy(@Px float);
+ method public androidx.recyclerview.widget.RecyclerView.Adapter? getAdapter();
+ method public int getCurrentItem();
+ method public androidx.recyclerview.widget.RecyclerView.ItemDecoration getItemDecorationAt(int);
+ method public int getItemDecorationCount();
+ method @androidx.viewpager2.widget.ViewPager2.OffscreenPageLimit public int getOffscreenPageLimit();
+ method @androidx.viewpager2.widget.ViewPager2.Orientation public int getOrientation();
+ method @androidx.viewpager2.widget.ViewPager2.ScrollState public int getScrollState();
+ method public void invalidateItemDecorations();
+ method public boolean isFakeDragging();
+ method public boolean isUserInputEnabled();
+ method public void registerOnPageChangeCallback(androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback);
+ method public void removeItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
+ method public void removeItemDecorationAt(int);
+ method public void requestTransform();
+ method public void setAdapter(androidx.recyclerview.widget.RecyclerView.Adapter?);
+ method public void setCurrentItem(int);
+ method public void setCurrentItem(int, boolean);
+ method public void setOffscreenPageLimit(@androidx.viewpager2.widget.ViewPager2.OffscreenPageLimit int);
+ method public void setOrientation(@androidx.viewpager2.widget.ViewPager2.Orientation int);
+ method public void setPageTransformer(androidx.viewpager2.widget.ViewPager2.PageTransformer?);
+ method public void setUserInputEnabled(boolean);
+ method public void unregisterOnPageChangeCallback(androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback);
+ field public static final int OFFSCREEN_PAGE_LIMIT_DEFAULT = -1; // 0xffffffff
+ field public static final int ORIENTATION_HORIZONTAL = 0; // 0x0
+ field public static final int ORIENTATION_VERTICAL = 1; // 0x1
+ field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
+ field public static final int SCROLL_STATE_IDLE = 0; // 0x0
+ field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
+ }
+
+ @IntDef({androidx.viewpager2.widget.ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT}) @IntRange(from=1) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewPager2.OffscreenPageLimit {
+ }
+
+ public abstract static class ViewPager2.OnPageChangeCallback {
+ ctor public ViewPager2.OnPageChangeCallback();
+ method public void onPageScrollStateChanged(@androidx.viewpager2.widget.ViewPager2.ScrollState int);
+ method public void onPageScrolled(int, float, @Px int);
+ method public void onPageSelected(int);
+ }
+
+ @IntDef({androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL, androidx.viewpager2.widget.ViewPager2.ORIENTATION_VERTICAL}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewPager2.Orientation {
+ }
+
+ public static interface ViewPager2.PageTransformer {
+ method public void transformPage(android.view.View, float);
+ }
+
+ @IntDef({androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_IDLE, androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_DRAGGING, androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_SETTLING}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewPager2.ScrollState {
+ }
+
+ public final class WindowInsetsApplier implements androidx.core.view.OnApplyWindowInsetsListener {
+ method public static boolean install(androidx.viewpager2.widget.ViewPager2);
+ method public androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ }
+
+}
+
diff --git a/viewpager2/viewpager2/build.gradle b/viewpager2/viewpager2/build.gradle
index fcba271..4a9b7c7 100644
--- a/viewpager2/viewpager2/build.gradle
+++ b/viewpager2/viewpager2/build.gradle
@@ -27,7 +27,7 @@
api("androidx.annotation:annotation-experimental:1.3.0")
implementation("androidx.core:core:1.3.2")
api("androidx.fragment:fragment:1.1.0")
- api(project(":recyclerview:recyclerview")) // TODO(191302495): pin to RV 1.3.1 once in prebuilts
+ api("androidx.recyclerview:recyclerview:1.3.1-rc01")
implementation("androidx.collection:collection:1.1.0")
androidTestImplementation(libs.multidex)
diff --git a/wear/compose/compose-foundation/api/current.ignore b/wear/compose/compose-foundation/api/current.ignore
deleted file mode 100644
index 714dc1c..0000000
--- a/wear/compose/compose-foundation/api/current.ignore
+++ /dev/null
@@ -1,5 +0,0 @@
-// Baseline format: 1.0
-RemovedClass: androidx.wear.compose.foundation.CurvedModifierKt:
- Removed class androidx.wear.compose.foundation.CurvedModifierKt
-RemovedClass: androidx.wear.compose.foundation.CurvedTextStyleKt:
- Removed class androidx.wear.compose.foundation.CurvedTextStyleKt
diff --git a/wear/compose/compose-foundation/api/restricted_current.ignore b/wear/compose/compose-foundation/api/restricted_current.ignore
deleted file mode 100644
index 714dc1c..0000000
--- a/wear/compose/compose-foundation/api/restricted_current.ignore
+++ /dev/null
@@ -1,5 +0,0 @@
-// Baseline format: 1.0
-RemovedClass: androidx.wear.compose.foundation.CurvedModifierKt:
- Removed class androidx.wear.compose.foundation.CurvedModifierKt
-RemovedClass: androidx.wear.compose.foundation.CurvedTextStyleKt:
- Removed class androidx.wear.compose.foundation.CurvedTextStyleKt
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 1b894ff..693c194 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
@@ -46,6 +46,7 @@
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -349,6 +350,7 @@
}
}
+ @Ignore("b/283960419")
@Test
fun itemsCorrectScrollPastStartEndAutoCenterItemZeroOddHeightViewportOddHeightItems() {
visibleItemsAreCorrectAfterScrollingPastEndOfItems(0, 41, false)
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 724c367..a386e82 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
@@ -16,7 +16,10 @@
package androidx.wear.compose.foundation
+import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.tween
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -44,6 +47,16 @@
import kotlin.math.roundToInt
/**
+ * Standard animation length in milliseconds.
+ */
+internal const val STANDARD_ANIMATION = 300
+
+/**
+ * Quick animation length in milliseconds.
+ */
+internal const val QUICK_ANIMATION = 250
+
+/**
* Different values which the swipeable modifier can be configured to.
*/
@ExperimentalWearFoundationApi
@@ -267,14 +280,13 @@
undoAction: (@Composable RevealScope.() -> Unit)? = null,
content: @Composable () -> Unit
) {
- // Initialise to zero, updated when the size changes
val revealScope = remember(state) { RevealScopeImpl(state) }
Box(
modifier = modifier
.swipeableV2(
state = state.swipeableState,
orientation = Orientation.Horizontal,
- enabled = true,
+ enabled = state.currentValue != RevealValue.Revealed,
)
.swipeAnchors(
state = state.swipeableState,
@@ -296,29 +308,53 @@
val availableWidth = if (state.offset.isNaN()) 0.dp
else with(density) { abs(state.offset).toDp() }
+ // Determines whether the additional action will be visible based on the current
+ // reveal offset
+ val showAdditionalAction by remember {
+ derivedStateOf {
+ abs(state.offset) <= revealScope.revealOffset
+ }
+ }
+ // Animate weight for additional action slot.
+ val additionalActionWeight = animateFloatAsState(
+ targetValue = if (showAdditionalAction) 1f else 0f,
+ animationSpec = tween(durationMillis = QUICK_ANIMATION),
+ label = "AdditionalActionAnimationSpec"
+ )
+
Row(
modifier = Modifier.matchParentSize(),
horizontalArrangement = Arrangement.Absolute.Right
) {
- if (swipeCompleted && undoAction != null) {
- Row(
- modifier = Modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.Center
- ) {
- ActionSlot(revealScope, content = undoAction)
- }
- } else {
- Row(
- modifier = Modifier.width(availableWidth),
- horizontalArrangement = Arrangement.Absolute.Right
- ) {
- if (additionalAction != null &&
- abs(state.offset) <= revealScope.revealOffset) {
- Spacer(Modifier.size(SwipeToRevealDefaults.padding))
- ActionSlot(revealScope, content = additionalAction)
+ Crossfade(
+ targetState = swipeCompleted && undoAction != null,
+ animationSpec = tween(durationMillis = STANDARD_ANIMATION),
+ label = "CrossFadeS2R"
+ ) { displayUndo ->
+ if (displayUndo) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.Center
+ ) {
+ ActionSlot(revealScope, content = undoAction!!)
}
- Spacer(Modifier.size(SwipeToRevealDefaults.padding))
- ActionSlot(revealScope, content = action)
+ } else {
+ Row(
+ modifier = Modifier.width(availableWidth),
+ horizontalArrangement = Arrangement.Absolute.Right
+ ) {
+ // weight cannot be 0 so remove the composable when weight becomes 0
+ if (additionalAction != null && additionalActionWeight.value > 0) {
+ Spacer(Modifier.size(SwipeToRevealDefaults.padding))
+ ActionSlot(
+ revealScope,
+ content = additionalAction,
+ weight = additionalActionWeight.value
+ )
+ }
+ Spacer(Modifier.size(SwipeToRevealDefaults.padding))
+ ActionSlot(revealScope, content = action)
+ }
}
}
}
@@ -358,7 +394,8 @@
) : RevealScope {
/**
- * The total width of the overlay content in float.
+ * The total width of the overlay content in pixels. Initialise to zero,
+ * updated when the width changes.
*/
val width = mutableFloatStateOf(0.0f)
@@ -386,10 +423,11 @@
private fun RowScope.ActionSlot(
revealScope: RevealScope,
modifier: Modifier = Modifier,
+ weight: Float = 1f,
content: @Composable RevealScope.() -> Unit
) {
Box(
- modifier = modifier.fillMaxHeight().weight(1f),
+ modifier = modifier.fillMaxHeight().weight(weight),
contentAlignment = Alignment.Center
) {
with(revealScope) {
diff --git a/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/StepperTest.kt b/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/StepperTest.kt
new file mode 100644
index 0000000..338c9c4
--- /dev/null
+++ b/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/StepperTest.kt
@@ -0,0 +1,449 @@
+/*
+ * 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.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.ProvidedValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.assertContentDescriptionContains
+import androidx.compose.ui.test.assertHasNoClickAction
+import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.click
+import androidx.compose.ui.test.getUnclippedBoundsInRoot
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onChild
+import androidx.compose.ui.test.onChildAt
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onParent
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.height
+import androidx.test.filters.SdkSuppress
+import com.google.common.truth.Truth
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+
+public class StepperTest {
+ @get:Rule
+ public val rule = createComposeRule()
+
+ @Test
+ public fun supports_testtag() {
+ rule.setContent {
+ StepperWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ ) {}
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertExists()
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ public fun throws_when_steps_negative() {
+ rule.setContent {
+ StepperWithDefaults(
+ steps = -1
+ ) {}
+ }
+ }
+
+ @Test
+ public fun decreases_value_by_clicking_bottom() {
+ val state = mutableStateOf(2f)
+ val range = 1f..4f
+
+ rule.initDefaultStepper(state, range, 2)
+
+ rule.onNodeWithContentDescription(DECREASE).performClick()
+
+ rule.runOnIdle {
+ Truth.assertThat(state.value).isWithin(0.001f).of(1f)
+ }
+ }
+
+ @Test
+ public fun increases_value_by_clicking_top() {
+ val state = mutableStateOf(2f)
+ val range = 1f..4f
+
+ rule.initDefaultStepper(state, range, 2)
+
+ // The clickable area for an increase button takes top 35% of the screen
+ rule.onNodeWithTag(TEST_TAG).performTouchInput { click(Offset(width / 2f, 15f)) }
+
+ rule.runOnIdle {
+ Truth.assertThat(state.value).isWithin(0.001f).of(3f)
+ }
+ }
+
+ @Test
+ public fun reaches_min_clicking_bottom() {
+ // Start one step above the minimum.
+ val state = mutableStateOf(2f)
+ val range = 1f..4f
+
+ rule.initDefaultStepper(state, range, 2)
+
+ // The clickable area for a decrease button takes bottom 35% of the screen
+ rule.onNodeWithTag(TEST_TAG).performTouchInput { click(Offset(width / 2f, height - 15f)) }
+
+ rule.runOnIdle {
+ Truth.assertThat(state.value).isWithin(0.001f).of(1f)
+ }
+ }
+
+ @Test
+ public fun reaches_max_clicking_top() {
+ // Start one step below the maximum.
+ val state = mutableStateOf(3f)
+ val range = 1f..4f
+
+ rule.initDefaultStepper(state, range, 2)
+
+ // The clickable area for an increase button takes top 35% of the screen
+ rule.onNodeWithTag(TEST_TAG).performTouchInput { click(Offset(width / 2f, 15f)) }
+
+ rule.runOnIdle {
+ Truth.assertThat(state.value).isWithin(0.001f).of(4f)
+ }
+ }
+
+ @Test
+ public fun disables_decrease_when_minimum_value_reached() {
+ val state = mutableStateOf(1f)
+ val range = 1f..4f
+
+ rule.initDefaultStepper(state, range, 2)
+
+ rule.onNodeWithContentDescription(DECREASE).onParent().assertHasNoClickAction()
+ }
+
+ @Test
+ public fun disables_increase_when_maximum_value_reached() {
+ val state = mutableStateOf(4f)
+ val range = 1f..4f
+
+ rule.initDefaultStepper(state, range, 2)
+
+ rule.onNodeWithContentDescription(INCREASE).onParent().assertHasNoClickAction()
+ }
+
+ @Test
+ public fun checks_decrease_icon_position() {
+ rule.setContent {
+ StepperWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ ) {}
+ }
+ val unclippedBoundsInRoot = rule.onRoot().getUnclippedBoundsInRoot()
+
+ rule.waitForIdle()
+ rule.onNodeWithTag(DECREASE, true)
+ .assertExists()
+ .assertTopPositionInRootIsEqualTo(
+ unclippedBoundsInRoot.height -
+ BorderVerticalMargin - DefaultIconHeight
+ )
+ }
+
+ @Test
+ public fun sets_custom_decrease_icon() {
+ val iconTag = "iconTag_test"
+
+ rule.setContent {
+ StepperWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG),
+ decreaseIcon = {
+ TestImage(Modifier.size(24.dp), iconTag)
+ }
+ ) {}
+ }
+
+ rule.waitForIdle()
+ rule.onNodeWithTag(iconTag, true)
+ .assertExists()
+ }
+
+ @Test
+ public fun sets_custom_increase_icon() {
+ val iconTag = "iconTag_test"
+
+ rule.setContent {
+ StepperWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG),
+ increaseIcon = {
+ TestImage(Modifier.size(24.dp), iconTag)
+ }
+ ) {}
+ }
+ rule.waitForIdle()
+ rule.onNodeWithTag(iconTag, true)
+ .assertExists()
+ .assertTopPositionInRootIsEqualTo(BorderVerticalMargin)
+ }
+
+ @Test
+ public fun sets_content() {
+ val contentTag = "contentTag_test"
+
+ rule.setContent {
+ StepperWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG),
+ ) {
+ TestText(
+ "Testing",
+ modifier = Modifier
+ .testTag(contentTag)
+ .fillMaxHeight()
+ )
+ }
+ }
+
+ val rootHeight = rule.onRoot().getUnclippedBoundsInRoot().height
+
+ rule.waitForIdle()
+ rule.onNodeWithTag(contentTag, true)
+ .assertExists()
+ .assertTopPositionInRootIsEqualTo(
+ // Position of the content is a weight(35%) of (top button minus 2 spacers 8dp each)
+ // plus 1 spacer
+ (rootHeight - VerticalMargin * 2) * ButtonWeight + VerticalMargin
+ )
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ public fun sets_background_color() {
+ val testColor = Color.Blue
+ val backgroundThreshold = 50.0f
+ rule.setContent {
+ StepperWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG),
+ backgroundColor = testColor
+ ) {}
+ }
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertContainsColor(testColor, backgroundThreshold)
+ }
+
+ @Test
+ public fun sets_custom_description_for_increase_icon() {
+ val testContentDescription = "testContentDescription"
+
+ rule.setContent {
+ StepperWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = 0f,
+ steps = 5,
+ increaseIcon = {
+ TestImage(Modifier.size(24.dp), testContentDescription)
+ }
+ ) {}
+ }
+
+ rule.waitForIdle()
+ rule.onNodeWithTag(TEST_TAG, true)
+ // 0 is the index of increase button, 1 - decrease button, content is empty
+ .onChildAt(0)
+ .onChild()
+ .assertContentDescriptionContains(testContentDescription)
+ }
+
+ @Test
+ public fun sets_custom_description_for_decrease_icon() {
+ val testContentDescription = "testContentDescription"
+
+ rule.setContent {
+ StepperWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = 0f,
+ steps = 5,
+ decreaseIcon = {
+ TestImage(Modifier.size(24.dp), testContentDescription)
+ }
+ ) {}
+ }
+
+ rule.waitForIdle()
+ rule.onNodeWithTag(TEST_TAG, true)
+ // 0 is the index of increase button, 1 - decrease button, content is empty
+ .onChildAt(1)
+ .onChild()
+ .assertContentDescriptionContains(testContentDescription)
+ }
+
+ @Test
+ public fun sets_button_provider_values_correctly_for_minimum_value() {
+ verifyButtonProviderValues(
+ value = 1f,
+ valueRange = 1f..4f,
+ steps = 3,
+ expectedIncreaseIconData = +1,
+ expectedDecreaseIconData = -1,
+ enabledButtonProviderValues = arrayOf(
+ LocalContentTestData provides +1
+ ),
+ disabledButtonProviderValues = arrayOf(
+ LocalContentTestData provides -1
+ )
+ )
+ }
+
+ @Test
+ public fun sets_button_provider_values_correctly_for_maximum_value() {
+ verifyButtonProviderValues(
+ value = 4f,
+ valueRange = 1f..4f,
+ steps = 3,
+ expectedIncreaseIconData = -1,
+ expectedDecreaseIconData = +1,
+ enabledButtonProviderValues = arrayOf(
+ LocalContentTestData provides +1
+ ),
+ disabledButtonProviderValues = arrayOf(
+ LocalContentTestData provides -1
+ )
+ )
+ }
+
+ @Test
+ public fun sets_button_provider_values_correctly_for_value_between_min_and_max() {
+ verifyButtonProviderValues(
+ value = 2f,
+ valueRange = 1f..4f,
+ steps = 3,
+ expectedIncreaseIconData = +1,
+ expectedDecreaseIconData = +1,
+ enabledButtonProviderValues = arrayOf(
+ LocalContentTestData provides +1
+ ),
+ disabledButtonProviderValues = arrayOf(
+ LocalContentTestData provides -1
+ )
+ )
+ }
+
+ private val BorderVerticalMargin = 22.dp
+ private val VerticalMargin = 8.dp
+ private val ButtonWeight = .35f
+ private val DefaultIconHeight = 24.dp
+
+ @Composable
+ internal fun StepperWithDefaults(
+ modifier: Modifier = Modifier,
+ value: Float = 1f,
+ onValueChange: (Float) -> Unit = {},
+ steps: Int = 5,
+ decreaseIcon: @Composable () -> Unit = {
+ TestImage(
+ modifier = Modifier.size(24.dp),
+ iconLabel = DECREASE
+ )
+ },
+ increaseIcon: @Composable () -> Unit = {
+ TestImage(
+ modifier = Modifier.size(24.dp),
+ iconLabel = INCREASE
+ )
+ },
+ valueRange: ClosedFloatingPointRange<Float> = 0f..5f,
+ backgroundColor: Color = Color.Black,
+ enabledButtonProviderValues: Array<ProvidedValue<*>> = arrayOf(),
+ disabledButtonProviderValues: Array<ProvidedValue<*>> = arrayOf(),
+ content: @Composable BoxScope.() -> Unit
+ ) = Stepper(
+ modifier = modifier,
+ value = value,
+ onValueChange = onValueChange,
+ steps = steps,
+ increaseIcon = increaseIcon,
+ decreaseIcon = decreaseIcon,
+ valueRange = valueRange,
+ backgroundColor = backgroundColor,
+ enabledButtonProviderValues = enabledButtonProviderValues,
+ disabledButtonProviderValues = disabledButtonProviderValues,
+ content = content,
+ )
+
+ private fun verifyButtonProviderValues(
+ value: Float,
+ valueRange: ClosedFloatingPointRange<Float>,
+ steps: Int,
+ expectedIncreaseIconData: Int,
+ expectedDecreaseIconData: Int,
+ enabledButtonProviderValues: Array<ProvidedValue<*>> = arrayOf(),
+ disabledButtonProviderValues: Array<ProvidedValue<*>> = arrayOf()
+ ) {
+ var increaseIconData = 0
+ var decreaseIconData = 0
+ rule.setContent {
+ StepperWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = value,
+ steps = steps,
+ valueRange = valueRange,
+ backgroundColor = Color.Transparent,
+ enabledButtonProviderValues = enabledButtonProviderValues,
+ disabledButtonProviderValues = disabledButtonProviderValues,
+ decreaseIcon = {
+ decreaseIconData = LocalContentTestData.current
+ },
+ increaseIcon = {
+ increaseIconData = LocalContentTestData.current
+ }
+ ) {}
+ }
+
+ Assert.assertEquals(increaseIconData, expectedIncreaseIconData)
+ Assert.assertEquals(decreaseIconData, expectedDecreaseIconData)
+ }
+
+ private fun ComposeContentTestRule.initDefaultStepper(
+ state: MutableState<Float>,
+ valueRange: ClosedFloatingPointRange<Float>,
+ steps: Int
+ ) {
+ setContent {
+ StepperWithDefaults(
+ value = state.value,
+ onValueChange = { state.value = it },
+ valueRange = valueRange,
+ steps = steps,
+ modifier = Modifier.testTag(TEST_TAG)
+ ) {}
+ }
+ }
+
+ private val INCREASE = "increase"
+ private val DECREASE = "decrease"
+}
diff --git a/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/RangeDefaults.kt b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/RangeDefaults.kt
new file mode 100644
index 0000000..7aff03b
--- /dev/null
+++ b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/RangeDefaults.kt
@@ -0,0 +1,81 @@
+/*
+ * 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 androidx.annotation.RestrictTo
+import androidx.compose.material.icons.materialIcon
+import androidx.compose.material.icons.materialPath
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.util.lerp
+import kotlin.math.roundToInt
+
+/**
+ * Icons which are used by Range controls like slider and stepper
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public object RangeIcons {
+
+ /**
+ * An [ImageVector] with a minus sign.
+ */
+ val Minus: ImageVector
+ get() = if (_minus != null) _minus!!
+ else {
+ _minus = materialIcon(name = "MinusIcon") {
+ materialPath {
+ moveTo(19.0f, 13.0f)
+ horizontalLineTo(5.0f)
+ verticalLineToRelative(-2.0f)
+ horizontalLineToRelative(14.0f)
+ verticalLineToRelative(2.0f)
+ close()
+ }
+ }
+ _minus!!
+ }
+
+ private var _minus: ImageVector? = null
+}
+
+/**
+ * Defaults used by range controls like slider and stepper
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public object RangeDefaults {
+ /**
+ * Calculates value of [currentStep] in [valueRange] depending on number of [steps]
+ */
+ fun calculateCurrentStepValue(
+ currentStep: Int,
+ steps: Int,
+ valueRange: ClosedFloatingPointRange<Float>
+ ): Float = lerp(
+ valueRange.start, valueRange.endInclusive,
+ currentStep.toFloat() / (steps + 1).toFloat()
+ ).coerceIn(valueRange)
+
+ /**
+ * Snaps [value] to the closest [step] in the [valueRange]
+ */
+ fun snapValueToStep(
+ value: Float,
+ valueRange: ClosedFloatingPointRange<Float>,
+ steps: Int
+ ): Int = ((value - valueRange.start) /
+ (valueRange.endInclusive - valueRange.start) * (steps + 1))
+ .roundToInt().coerceIn(0, steps + 1)
+}
diff --git a/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/Stepper.kt b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/Stepper.kt
new file mode 100644
index 0000000..a82c450
--- /dev/null
+++ b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/Stepper.kt
@@ -0,0 +1,180 @@
+/*
+ * 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 androidx.annotation.RestrictTo
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.indication
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentWidth
+import androidx.compose.material.ripple.rememberRipple
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.ProvidedValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.unit.dp
+
+/**
+ * [Stepper] allows users to make a selection from a range of values.
+ * It's a full-screen control with increase button on the top, decrease button on the bottom and
+ * a slot (expected to have either [Text] or [Chip]) in the middle.
+ * Value can be increased and decreased by clicking on the increase and decrease buttons.
+ * Buttons can have custom icons - [decreaseIcon] and [increaseIcon].
+ * Step value is calculated as the difference between min and max values divided by [steps]+1.
+ * Stepper itself doesn't show the current value but can be displayed via the content slot or
+ * [PositionIndicator] if required.
+ * If [value] is not equal to any step value, then it will be coerced to the closest step value.
+ * However, the [value] itself will not be changed and [onValueChange] in this case will
+ * not be triggered.
+ *
+ * @param value Current value of the Stepper. If outside of [valueRange] provided, value will be
+ * coerced to this range.
+ * @param onValueChange Lambda in which value should be updated
+ * @param steps Specifies the number of discrete values, excluding min and max values, evenly
+ * distributed across the whole value range. Must not be negative. If 0, stepper will have only
+ * min and max values and no steps in between
+ * @param decreaseIcon A slot for an icon which is placed on the decrease (bottom) button
+ * @param increaseIcon A slot for an icon which is placed on the increase (top) button
+ * @param modifier Modifiers for the Stepper layout
+ * @param valueRange Range of values that Stepper value can take. Passed [value] will be coerced to
+ * this range
+ * @param backgroundColor [Color] representing the background color for the stepper.
+ * @param enabledButtonProviderValues Values of CompositionLocal providers for enabled button such
+ * as LocalContentColor, LocalContentAlpha, LocalTextStyle which are dependent on a specific
+ * material design version and are not part of this material-agnostic library.
+ * @param disabledButtonProviderValues Values of CompositionLocal providers for disabled button such
+ * as LocalContentColor, LocalContentAlpha, LocalTextStyle which are dependent on a specific
+ * material design version and are not part of this material-agnostic library.
+ * @param content Content body for the Stepper.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@Composable
+public fun Stepper(
+ value: Float,
+ onValueChange: (Float) -> Unit,
+ steps: Int,
+ decreaseIcon: @Composable () -> Unit,
+ increaseIcon: @Composable () -> Unit,
+ modifier: Modifier,
+ valueRange: ClosedFloatingPointRange<Float>,
+ backgroundColor: Color,
+ enabledButtonProviderValues: Array<ProvidedValue<*>>,
+ disabledButtonProviderValues: Array<ProvidedValue<*>>,
+ content: @Composable BoxScope.() -> Unit
+) {
+ require(steps >= 0) { "steps should be >= 0" }
+ val currentStep = remember(value, valueRange, steps) {
+ RangeDefaults.snapValueToStep(
+ value, valueRange, steps
+ )
+ }
+
+ val updateValue: (Int) -> Unit = { stepDiff ->
+ val newValue =
+ RangeDefaults.calculateCurrentStepValue(currentStep + stepDiff, steps, valueRange)
+ if (newValue != value) onValueChange(newValue)
+ }
+
+ Column(
+ modifier = modifier
+ .fillMaxSize()
+ .background(backgroundColor),
+ verticalArrangement = Arrangement.spacedBy(8.dp)
+ ) {
+ val increaseButtonEnabled = currentStep < steps + 1
+ val decreaseButtonEnabled = currentStep > 0
+
+ // Increase button.
+ FullScreenButton(
+ onClick = { updateValue(1) },
+ contentAlignment = Alignment.TopCenter,
+ paddingValues = PaddingValues(top = StepperDefaults.BorderPadding),
+ enabled = increaseButtonEnabled,
+ buttonProviderValues = if (increaseButtonEnabled) enabledButtonProviderValues
+ else disabledButtonProviderValues,
+ content = increaseIcon
+ )
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .weight(StepperDefaults.ContentWeight),
+ contentAlignment = Alignment.Center,
+ content = content
+ )
+ // Decrease button.
+ FullScreenButton(
+ onClick = { updateValue(-1) },
+ contentAlignment = Alignment.BottomCenter,
+ paddingValues = PaddingValues(bottom = StepperDefaults.BorderPadding),
+ enabled = decreaseButtonEnabled,
+ buttonProviderValues = if (decreaseButtonEnabled) enabledButtonProviderValues
+ else disabledButtonProviderValues,
+ content = decreaseIcon
+ )
+ }
+}
+
+@Composable
+private fun ColumnScope.FullScreenButton(
+ onClick: () -> Unit,
+ contentAlignment: Alignment,
+ paddingValues: PaddingValues,
+ enabled: Boolean,
+ buttonProviderValues: Array<ProvidedValue<*>>,
+ content: @Composable () -> Unit
+) {
+ val interactionSource = remember { MutableInteractionSource() }
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .weight(StepperDefaults.ButtonWeight)
+ .clickable(
+ interactionSource, null, onClick = onClick, enabled = enabled, role = Role.Button
+ )
+ .wrapContentWidth()
+ .indication(interactionSource, rememberRipple(bounded = false))
+ .padding(paddingValues),
+ contentAlignment = contentAlignment,
+ ) {
+ CompositionLocalProvider(
+ values = buttonProviderValues, content = content
+ )
+ }
+}
+
+/**
+ * Defaults used by stepper
+ */
+private object StepperDefaults {
+ const val ButtonWeight = 0.35f
+ const val ContentWeight = 0.3f
+ val BorderPadding = 22.dp
+}
diff --git a/wear/compose/compose-material/api/current.ignore b/wear/compose/compose-material/api/current.ignore
deleted file mode 100644
index 68a4999..0000000
--- a/wear/compose/compose-material/api/current.ignore
+++ /dev/null
@@ -1,27 +0,0 @@
-// Baseline format: 1.0
-ChangedValue: androidx.wear.compose.material.TimeTextDefaults#TimeFormat12Hours:
- Field androidx.wear.compose.material.TimeTextDefaults.TimeFormat12Hours has changed value from h:mm a to h:mm
-
-
-ParameterNameChange: androidx.wear.compose.material.SwipeToDismissKeys#valueOf(String) parameter #0:
- Attempted to change parameter name from name to value in method androidx.wear.compose.material.SwipeToDismissKeys.valueOf
-ParameterNameChange: androidx.wear.compose.material.SwipeToDismissValue#valueOf(String) parameter #0:
- Attempted to change parameter name from name to value in method androidx.wear.compose.material.SwipeToDismissValue.valueOf
-
-
-RemovedClass: androidx.wear.compose.material.AnimationKt:
- Removed class androidx.wear.compose.material.AnimationKt
-RemovedClass: androidx.wear.compose.material.DefaultTimeSourceKt:
- Removed class androidx.wear.compose.material.DefaultTimeSourceKt
-RemovedClass: androidx.wear.compose.material.MaterialTextSelectionColorsKt:
- Removed class androidx.wear.compose.material.MaterialTextSelectionColorsKt
-RemovedClass: androidx.wear.compose.material.RangeDefaultsKt:
- Removed class androidx.wear.compose.material.RangeDefaultsKt
-RemovedClass: androidx.wear.compose.material.Resources_androidKt:
- Removed class androidx.wear.compose.material.Resources_androidKt
-RemovedClass: androidx.wear.compose.material.ScalingLazyColumnMeasureKt:
- Removed class androidx.wear.compose.material.ScalingLazyColumnMeasureKt
-RemovedClass: androidx.wear.compose.material.ShapesKt:
- Removed class androidx.wear.compose.material.ShapesKt
-RemovedClass: androidx.wear.compose.material.TypographyKt:
- Removed class androidx.wear.compose.material.TypographyKt
diff --git a/wear/compose/compose-material/api/restricted_current.ignore b/wear/compose/compose-material/api/restricted_current.ignore
deleted file mode 100644
index 68a4999..0000000
--- a/wear/compose/compose-material/api/restricted_current.ignore
+++ /dev/null
@@ -1,27 +0,0 @@
-// Baseline format: 1.0
-ChangedValue: androidx.wear.compose.material.TimeTextDefaults#TimeFormat12Hours:
- Field androidx.wear.compose.material.TimeTextDefaults.TimeFormat12Hours has changed value from h:mm a to h:mm
-
-
-ParameterNameChange: androidx.wear.compose.material.SwipeToDismissKeys#valueOf(String) parameter #0:
- Attempted to change parameter name from name to value in method androidx.wear.compose.material.SwipeToDismissKeys.valueOf
-ParameterNameChange: androidx.wear.compose.material.SwipeToDismissValue#valueOf(String) parameter #0:
- Attempted to change parameter name from name to value in method androidx.wear.compose.material.SwipeToDismissValue.valueOf
-
-
-RemovedClass: androidx.wear.compose.material.AnimationKt:
- Removed class androidx.wear.compose.material.AnimationKt
-RemovedClass: androidx.wear.compose.material.DefaultTimeSourceKt:
- Removed class androidx.wear.compose.material.DefaultTimeSourceKt
-RemovedClass: androidx.wear.compose.material.MaterialTextSelectionColorsKt:
- Removed class androidx.wear.compose.material.MaterialTextSelectionColorsKt
-RemovedClass: androidx.wear.compose.material.RangeDefaultsKt:
- Removed class androidx.wear.compose.material.RangeDefaultsKt
-RemovedClass: androidx.wear.compose.material.Resources_androidKt:
- Removed class androidx.wear.compose.material.Resources_androidKt
-RemovedClass: androidx.wear.compose.material.ScalingLazyColumnMeasureKt:
- Removed class androidx.wear.compose.material.ScalingLazyColumnMeasureKt
-RemovedClass: androidx.wear.compose.material.ShapesKt:
- Removed class androidx.wear.compose.material.ShapesKt
-RemovedClass: androidx.wear.compose.material.TypographyKt:
- Removed class androidx.wear.compose.material.TypographyKt
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/CurvedTextTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/CurvedTextTest.kt
new file mode 100644
index 0000000..83d68ee
--- /dev/null
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/CurvedTextTest.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.wear.compose.material
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.testutils.assertContainsColor
+import androidx.compose.testutils.assertDoesNotContainColor
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.wear.compose.foundation.CurvedLayout
+import androidx.wear.compose.foundation.CurvedTextStyle
+import androidx.wear.compose.foundation.curvedRow
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RequiresApi(Build.VERSION_CODES.O)
+class CurvedTextTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ private val testText = "TestText"
+
+ @Test
+ fun color_parameter_overrides_styleColor() {
+ rule.setContent {
+ CurvedLayout {
+ curvedRow {
+ curvedText(
+ text = testText,
+ color = Color.Red,
+ style = CurvedTextStyle(
+ color = Color.Blue
+ )
+ )
+ }
+ }
+ }
+
+ val curvedTextImage = rule.onNodeWithContentDescription(testText).captureToImage()
+ curvedTextImage.assertContainsColor(Color.Red)
+ curvedTextImage.assertDoesNotContainColor(Color.Blue)
+ }
+
+ @Test
+ fun styleColor_overrides_LocalContentColor() {
+ rule.setContent {
+ CompositionLocalProvider(LocalContentColor provides Color.Yellow) {
+ CurvedLayout {
+ curvedRow {
+ curvedText(
+ text = testText,
+ style = CurvedTextStyle(
+ color = Color.Blue
+ )
+ )
+ }
+ }
+ }
+ }
+
+ val curvedTextImage = rule.onNodeWithContentDescription(testText).captureToImage()
+ curvedTextImage.assertContainsColor(Color.Blue)
+ curvedTextImage.assertDoesNotContainColor(Color.Yellow)
+ }
+
+ @Test
+ fun uses_LocalContentColor_as_fallback() {
+ rule.setContent {
+ CompositionLocalProvider(LocalContentColor provides Color.Yellow) {
+ CurvedLayout {
+ curvedRow {
+ curvedText(
+ text = testText,
+ )
+ }
+ }
+ }
+ }
+
+ rule.onNodeWithContentDescription(testText).captureToImage()
+ .assertContainsColor(Color.Yellow)
+ }
+}
\ No newline at end of file
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToDismissBoxScreenshotTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToDismissBoxScreenshotTest.kt
index f6c528c..cc0f06d 100644
--- a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToDismissBoxScreenshotTest.kt
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToDismissBoxScreenshotTest.kt
@@ -18,7 +18,9 @@
import android.os.Build
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.testutils.assertAgainstGolden
import androidx.compose.ui.Alignment
@@ -78,25 +80,57 @@
verifySwipedScreenshot(LayoutDirection.Rtl, 0.5f)
}
+ @Test
+ fun on_dismiss_overload_swiped_to_right_25_percent_ltr() {
+ verifySwipedScreenshot(LayoutDirection.Ltr, 0.25f, true,
+ "swiped_to_right_25_percent_ltr")
+ }
+
+ @Test
+ fun on_dismiss_overload_swiped_to_right_25_percent_rtl() {
+ verifySwipedScreenshot(LayoutDirection.Rtl, 0.25f, true,
+ "swiped_to_right_25_percent_rtl")
+ }
+
+ @Test
+ fun on_dismiss_overload_swiped_to_right_50_percent_ltr() {
+ verifySwipedScreenshot(LayoutDirection.Ltr, 0.5f, true,
+ "swiped_to_right_50_percent_ltr")
+ }
+
+ @Test
+ fun on_dismiss_overload_swiped_to_right_50_percent_rtl() {
+ verifySwipedScreenshot(LayoutDirection.Rtl, 0.5f, true,
+ "swiped_to_right_50_percent_rtl")
+ }
+
private fun verifySwipedScreenshot(
layoutDirection: LayoutDirection,
swipedPercentage: Float,
+ isOnDismissOverload: Boolean = false,
+ goldenIdentifier: String = testName.methodName
) {
rule.setContentWithTheme {
CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
val state = rememberSwipeToDismissBoxState()
- SwipeToDismissBox(
- modifier = Modifier.testTag(TEST_TAG).size(106.dp),
- state = state
- ) { isBackground ->
- if (isBackground) {
- Box(modifier = Modifier.align(Alignment.Center)) {
- Text(color = Color.White, text = "Background")
- }
- } else {
- Box(modifier = Modifier.align(Alignment.Center)) {
- Text(color = Color.White, text = "Foreground")
- }
+ if (isOnDismissOverload) {
+ SwipeToDismissBox(
+ onDismissed = {},
+ modifier = Modifier
+ .testTag(TEST_TAG)
+ .size(106.dp),
+ state = state
+ ) { isBackground ->
+ boxContent(isBackground = isBackground)
+ }
+ } else {
+ SwipeToDismissBox(
+ modifier = Modifier
+ .testTag(TEST_TAG)
+ .size(106.dp),
+ state = state
+ ) { isBackground ->
+ boxContent(isBackground = isBackground)
}
}
}
@@ -108,6 +142,19 @@
rule.onNodeWithTag(TEST_TAG)
.captureToImage()
- .assertAgainstGolden(screenshotRule, testName.methodName)
+ .assertAgainstGolden(screenshotRule, goldenIdentifier)
+ }
+
+ @Composable
+ private fun BoxScope.boxContent(isBackground: Boolean) {
+ if (isBackground) {
+ Box(modifier = Modifier.align(Alignment.Center)) {
+ Text(color = Color.White, text = "Background")
+ }
+ } else {
+ Box(modifier = Modifier.align(Alignment.Center)) {
+ Text(color = Color.White, text = "Foreground")
+ }
+ }
}
}
\ No newline at end of file
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/TextTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/TextTest.kt
index 06bf851..e96362a 100644
--- a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/TextTest.kt
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/TextTest.kt
@@ -62,6 +62,26 @@
private val TestText = "TestText"
@Test
+ fun testDefaultIncludeFontPadding() {
+ var localTextStyle: TextStyle? = null
+ var display1TextStyle: TextStyle? = null
+ rule.setContent {
+ MaterialTheme {
+ localTextStyle = LocalTextStyle.current
+ display1TextStyle = LocalTypography.current.display1
+ }
+ }
+
+ assertThat(
+ localTextStyle?.platformStyle?.paragraphStyle?.includeFontPadding
+ ).isEqualTo(true)
+
+ assertThat(
+ display1TextStyle?.platformStyle?.paragraphStyle?.includeFontPadding
+ ).isEqualTo(true)
+ }
+
+ @Test
fun validateGreaterMinLinesResultsGreaterSize() {
var size1: Int = 0
var size2: Int = 0
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/TimeTextTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/TimeTextTest.kt
index e9644a6..ae16c7b 100644
--- a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/TimeTextTest.kt
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/TimeTextTest.kt
@@ -16,6 +16,7 @@
package androidx.wear.compose.material
+import android.os.Build
import android.text.format.DateFormat
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
@@ -32,8 +33,10 @@
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.sp
+import androidx.test.filters.SdkSuppress
import androidx.wear.compose.foundation.curvedComposable
import java.util.Calendar
+import java.util.Locale
import java.util.TimeZone
import org.junit.Assert.assertEquals
import org.junit.Rule
@@ -503,7 +506,8 @@
rule.setContent {
MaterialTheme(
typography = MaterialTheme.typography.copy(
- caption1 = testTextStyle)
+ caption1 = testTextStyle
+ )
) {
ConfiguredShapeScreen(false) {
TimeText(
@@ -558,6 +562,23 @@
}
assertEquals(expectedTime, actualTime)
}
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
+ @Test
+ fun formats_current_time_12H_french_locale() {
+ val currentTimeInMillis = 1631544258000L // 2021-09-13 14:44:18
+ val expectedTime = "2 h 44"
+ TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
+
+ var actualTime: String? = null
+ Locale.setDefault(Locale.CANADA_FRENCH)
+
+ rule.setContentWithTheme {
+ val format = TimeTextDefaults.timeFormat()
+ actualTime = currentTime({ currentTimeInMillis }, format).value
+ }
+ assertEquals(expectedTime, actualTime)
+ }
}
private const val LINEAR_ITEM_TAG = "LINEAR_ITEM_TAG"
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/RangeDefaults.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/RangeDefaults.kt
index cba5570..4406742 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/RangeDefaults.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/RangeDefaults.kt
@@ -106,4 +106,16 @@
valueRange, steps
)
+internal fun Modifier.rangeSemantics(
+ value: Float,
+ enabled: Boolean,
+ onValueChange: (Float) -> Unit,
+ valueRange: ClosedFloatingPointRange<Float>,
+ steps: Int
+): Modifier {
+ val currentStep = RangeDefaults.snapValueToStep(value, valueRange, steps)
+
+ return rangeSemantics(currentStep, enabled, onValueChange, valueRange, steps)
+}
+
internal fun IntProgression.stepsNumber(): Int = (last - first) / step - 1
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Stepper.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Stepper.kt
index ac33051..0b28d50 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Stepper.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Stepper.kt
@@ -16,34 +16,14 @@
package androidx.wear.compose.material
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.indication
-import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.ColumnScope
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
-import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.semantics.Role
-import androidx.compose.ui.unit.dp
-import androidx.wear.compose.material.RangeDefaults.calculateCurrentStepValue
-import androidx.wear.compose.material.RangeDefaults.snapValueToStep
import kotlin.math.roundToInt
/**
@@ -98,54 +78,35 @@
enableRangeSemantics: Boolean = true,
content: @Composable BoxScope.() -> Unit
) {
- require(steps >= 0) { "steps should be >= 0" }
- val currentStep =
- remember(value, valueRange, steps) { snapValueToStep(value, valueRange, steps) }
-
- val updateValue: (Int) -> Unit = { stepDiff ->
- val newValue = calculateCurrentStepValue(currentStep + stepDiff, steps, valueRange)
- if (newValue != value) onValueChange(newValue)
- }
-
- Column(
- modifier = modifier.fillMaxSize().background(backgroundColor).then(
- if (enableRangeSemantics) {
- Modifier.rangeSemantics(
- currentStep, true, onValueChange, valueRange, steps
- )
- } else {
- Modifier
- }
- ), verticalArrangement = Arrangement.spacedBy(8.dp)
+ androidx.wear.compose.materialcore.Stepper(
+ value = value,
+ onValueChange = onValueChange,
+ steps = steps,
+ decreaseIcon = decreaseIcon,
+ increaseIcon = increaseIcon,
+ valueRange = valueRange,
+ modifier = if (enableRangeSemantics) {
+ modifier.rangeSemantics(
+ value, true, onValueChange, valueRange, steps
+ )
+ } else {
+ modifier
+ },
+ backgroundColor = backgroundColor,
+ enabledButtonProviderValues = arrayOf(
+ LocalContentColor provides iconColor,
+ LocalContentAlpha provides iconColor.alpha
+ ),
+ disabledButtonProviderValues = arrayOf(
+ LocalContentColor provides iconColor.copy(alpha = ContentAlpha.disabled),
+ LocalContentAlpha provides iconColor.copy(alpha = ContentAlpha.disabled).alpha
+ ),
) {
- // Increase button.
- FullScreenButton(
- onClick = { updateValue(1) },
- contentAlignment = Alignment.TopCenter,
- paddingValues = PaddingValues(top = StepperDefaults.BorderPadding),
- iconColor = iconColor,
- enabled = currentStep < steps + 1,
- content = increaseIcon
- )
- Box(
- modifier = Modifier.fillMaxWidth().weight(StepperDefaults.ContentWeight),
- contentAlignment = Alignment.Center,
+ CompositionLocalProvider(
+ LocalContentColor provides contentColor
) {
- CompositionLocalProvider(
- LocalContentColor provides contentColor,
- ) {
- content()
- }
+ content()
}
- // Decrease button.
- FullScreenButton(
- onClick = { updateValue(-1) },
- contentAlignment = Alignment.BottomCenter,
- paddingValues = PaddingValues(bottom = StepperDefaults.BorderPadding),
- iconColor = iconColor,
- enabled = currentStep > 0,
- content = decreaseIcon
- )
}
}
@@ -351,51 +312,13 @@
* Defaults used by stepper
*/
public object StepperDefaults {
- internal const val ButtonWeight = 0.35f
- internal const val ContentWeight = 0.3f
- internal val BorderPadding = 22.dp
-
/**
* Decrease [ImageVector]
*/
- public val Decrease = RangeIcons.Minus
+ public val Decrease = androidx.wear.compose.materialcore.RangeIcons.Minus
/**
* Increase [ImageVector]
*/
public val Increase = Icons.Filled.Add
}
-
-@Composable
-private fun ColumnScope.FullScreenButton(
- onClick: () -> Unit,
- contentAlignment: Alignment,
- paddingValues: PaddingValues,
- iconColor: Color,
- enabled: Boolean,
- content: @Composable () -> Unit
-) {
- val interactionSource = remember { MutableInteractionSource() }
- val contentColor = if (enabled) iconColor else iconColor.copy(alpha = ContentAlpha.disabled)
- Box(
- modifier = Modifier
- .fillMaxWidth()
- .weight(StepperDefaults.ButtonWeight)
- .clickable(
- interactionSource,
- null,
- onClick = onClick,
- enabled = enabled,
- role = Role.Button
- )
- .wrapContentWidth()
- .indication(interactionSource, rememberRipple(bounded = false))
- .padding(paddingValues),
- contentAlignment = contentAlignment,
- ) {
- CompositionLocalProvider(
- LocalContentColor provides contentColor,
- LocalContentAlpha provides contentColor.alpha,
- content = content)
- }
-}
\ No newline at end of file
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/SwipeToDismissBox.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/SwipeToDismissBox.kt
index 5430358..204985b 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/SwipeToDismissBox.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/SwipeToDismissBox.kt
@@ -38,7 +38,6 @@
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
-import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
@@ -258,7 +257,7 @@
modifier: Modifier = Modifier,
state: SwipeToDismissBoxState = rememberSwipeToDismissBoxState(),
backgroundScrimColor: Color = MaterialTheme.colors.background,
- contentScrimColor: Color = contentColorFor(backgroundScrimColor),
+ contentScrimColor: Color = MaterialTheme.colors.background,
backgroundKey: Any = SwipeToDismissKeys.Background,
contentKey: Any = SwipeToDismissKeys.Content,
hasBackground: Boolean = true,
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/TimeText.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/TimeText.kt
index 4834be9..5dea0bbb 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/TimeText.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/TimeText.kt
@@ -57,6 +57,7 @@
import androidx.wear.compose.material.TimeTextDefaults.TextSeparator
import androidx.wear.compose.material.TimeTextDefaults.timeFormat
import java.util.Calendar
+import java.util.Locale
/**
* Layout to show the current time and a label at the top of the screen.
@@ -186,7 +187,11 @@
* 12h or 24h format
*/
@Composable
- public fun timeFormat(): String = if (is24HourFormat()) TimeFormat24Hours else TimeFormat12Hours
+ public fun timeFormat(): String {
+ val format = if (is24HourFormat()) TimeFormat24Hours else TimeFormat12Hours
+ return DateFormat.getBestDateTimePattern(Locale.getDefault(), format)
+ .replace("a", "").trim()
+ }
/**
* Creates a [TextStyle] with default parameters used for showing time
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 3959dbc..0343958 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
@@ -93,7 +93,7 @@
* guide.
*
* @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 onCheckedChange Callback to be invoked when this buttons checked/selected status changes
* @param label A slot for providing the chip's main label. The contents are expected to be text
* which is "start" aligned.
* @param toggleControl A slot for providing the chip's toggle controls(s). The contents are
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Typography.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Typography.kt
index 28a45ac..420b834 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Typography.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Typography.kt
@@ -257,20 +257,13 @@
return if (fontFamily != null) this else copy(fontFamily = default)
}
-internal val DefaultTextStyle = TextStyle.Default.copy(
- platformStyle = defaultPlatformTextStyle()
-)
-
private const val DefaultIncludeFontPadding = true
-@Suppress("DEPRECATION")
-private val DefaultPlatformTextStyle = PlatformTextStyle(
- includeFontPadding = DefaultIncludeFontPadding
+internal val DefaultTextStyle = TextStyle.Default.copy(
+ platformStyle = PlatformTextStyle(
+ includeFontPadding = DefaultIncludeFontPadding
+ )
)
-/**
- * Returns Default [PlatformTextStyle].
- */
-internal fun defaultPlatformTextStyle(): PlatformTextStyle = DefaultPlatformTextStyle
/**
* This Ambient holds on to the current definition of typography for this application as described
diff --git a/wear/compose/compose-material3/api/current.txt b/wear/compose/compose-material3/api/current.txt
index 0dd7042..2142a1b 100644
--- a/wear/compose/compose-material3/api/current.txt
+++ b/wear/compose/compose-material3/api/current.txt
@@ -141,6 +141,10 @@
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> LocalContentColor;
}
+ public final class CurvedTextKt {
+ method public static void curvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional long background, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontSynthesis? fontSynthesis, optional androidx.wear.compose.foundation.CurvedTextStyle? style, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional int overflow);
+ }
+
@kotlin.RequiresOptIn(message="This Wear Material3 API is experimental and is likely to change or to be removed in" + " the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalWearMaterial3Api {
}
diff --git a/wear/compose/compose-material3/api/restricted_current.txt b/wear/compose/compose-material3/api/restricted_current.txt
index 0dd7042..2142a1b 100644
--- a/wear/compose/compose-material3/api/restricted_current.txt
+++ b/wear/compose/compose-material3/api/restricted_current.txt
@@ -141,6 +141,10 @@
property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> LocalContentColor;
}
+ public final class CurvedTextKt {
+ method public static void curvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional long background, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontSynthesis? fontSynthesis, optional androidx.wear.compose.foundation.CurvedTextStyle? style, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional int overflow);
+ }
+
@kotlin.RequiresOptIn(message="This Wear Material3 API is experimental and is likely to change or to be removed in" + " the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalWearMaterial3Api {
}
diff --git a/wear/compose/compose-material3/integration-tests/build.gradle b/wear/compose/compose-material3/integration-tests/build.gradle
new file mode 100644
index 0000000..fcaddc1
--- /dev/null
+++ b/wear/compose/compose-material3/integration-tests/build.gradle
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+import androidx.build.Publish
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("AndroidXComposePlugin")
+ id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+ implementation(libs.kotlinStdlib)
+
+ implementation(project(":compose:animation:animation"))
+ implementation(project(":compose:foundation:foundation"))
+ implementation(project(":compose:foundation:foundation-layout"))
+ implementation(project(":compose:runtime:runtime"))
+ implementation(project(":compose:ui:ui"))
+ implementation(project(":compose:ui:ui-text"))
+
+ implementation(project(':wear:compose:compose-foundation'))
+ implementation(project(':wear:compose:compose-material3'))
+ implementation(project(':wear:compose:compose-material3-samples'))
+ implementation(project(':wear:compose:integration-tests:demos:common'))
+}
+
+androidx {
+ name = "AndroidX Wear Compose Material3 Components Demos"
+ publish = Publish.NONE
+ inceptionYear = "2023"
+ description = "Contains the demo code for the AndroidX Wear Compose Material 3 components."
+}
+
+android {
+ defaultConfig {
+ minSdkVersion 25
+ }
+ namespace "androidx.wear.compose.material3.demos"
+}
\ No newline at end of file
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ButtonDemo.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ButtonDemo.kt
new file mode 100644
index 0000000..9817801
--- /dev/null
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ButtonDemo.kt
@@ -0,0 +1,19 @@
+/*
+ * 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
+
+// Add Button demos here
\ No newline at end of file
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
new file mode 100644
index 0000000..3379ab2
--- /dev/null
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.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.wear.compose.material3.demos
+
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+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.samples.ButtonSample
+import androidx.wear.compose.material3.samples.ChildButtonSample
+import androidx.wear.compose.material3.samples.FilledTonalButtonSample
+import androidx.wear.compose.material3.samples.FixedFontSize
+import androidx.wear.compose.material3.samples.OutlinedButtonSample
+import androidx.wear.compose.material3.samples.SimpleButtonSample
+import androidx.wear.compose.material3.samples.SimpleChildButtonSample
+import androidx.wear.compose.material3.samples.SimpleFilledTonalButtonSample
+import androidx.wear.compose.material3.samples.SimpleOutlinedButtonSample
+
+val WearMaterial3Demos = DemoCategory(
+ "Material3",
+ listOf(
+ DemoCategory(
+ "Button",
+ listOf(
+ DemoCategory(
+ "Samples",
+ listOf(
+ ComposableDemo("Button") {
+ Centralize {
+ SimpleButtonSample()
+ Spacer(Modifier.height(4.dp))
+ ButtonSample()
+ }
+ },
+ ComposableDemo("FilledTonalButton") {
+ Centralize {
+ SimpleFilledTonalButtonSample()
+ Spacer(Modifier.height(4.dp))
+ FilledTonalButtonSample()
+ }
+ },
+ ComposableDemo("OutlinedButton") {
+ Centralize {
+ SimpleOutlinedButtonSample()
+ Spacer(Modifier.height(4.dp))
+ OutlinedButtonSample()
+ }
+ },
+ ComposableDemo("ChildButton") {
+ Centralize {
+ SimpleChildButtonSample()
+ Spacer(Modifier.height(4.dp))
+ ChildButtonSample()
+ }
+ },
+ )
+ ),
+ DemoCategory(
+ "Demos",
+ listOf(
+ // Add button demos here
+ )
+ )
+ )
+ ),
+ DemoCategory(
+ "Theme",
+ listOf(
+ ComposableDemo(
+ title = "Fixed Font Size",
+ description =
+ "Display1 font size not impacted by changes to user font selection",
+ ) { Centralize { FixedFontSize() } },
+ )
+ )
+ )
+)
\ No newline at end of file
diff --git a/wear/compose/compose-material3/samples/build.gradle b/wear/compose/compose-material3/samples/build.gradle
index 05583d0..527c408 100644
--- a/wear/compose/compose-material3/samples/build.gradle
+++ b/wear/compose/compose-material3/samples/build.gradle
@@ -24,6 +24,12 @@
}
dependencies {
+ compileOnly(project(":annotation:annotation-sampled"))
+
+ implementation("androidx.compose.material:material-icons-core:1.4.2")
+ implementation(project(":compose:runtime:runtime"))
+ implementation(project(":wear:compose:compose-foundation"))
+ implementation(project(":wear:compose:compose-material3"))
}
android {
diff --git a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ButtonSample.kt b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ButtonSample.kt
new file mode 100644
index 0000000..955bd2b
--- /dev/null
+++ b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ButtonSample.kt
@@ -0,0 +1,135 @@
+/*
+ * 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.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Favorite
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.wear.compose.material3.Button
+import androidx.wear.compose.material3.ButtonDefaults
+import androidx.wear.compose.material3.ChildButton
+import androidx.wear.compose.material3.FilledTonalButton
+import androidx.wear.compose.material3.Icon
+import androidx.wear.compose.material3.OutlinedButton
+import androidx.wear.compose.material3.Text
+
+@Sampled
+@Composable
+fun SimpleButtonSample() {
+ Button(
+ onClick = { /* Do something */ },
+ label = { Text("Simple Button") }
+ )
+}
+
+@Sampled
+@Composable
+fun ButtonSample() {
+ Button(
+ onClick = { /* Do something */ },
+ label = { Text("Button with icon") },
+ secondaryLabel = { Text("Secondary label") },
+ icon = {
+ Icon(
+ Icons.Filled.Favorite,
+ contentDescription = "Localized description",
+ modifier = Modifier.size(ButtonDefaults.IconSize)
+ )
+ }
+ )
+}
+
+@Sampled
+@Composable
+fun SimpleFilledTonalButtonSample() {
+ FilledTonalButton(
+ onClick = { /* Do something */ },
+ label = { Text("Simple FilledTonalButton") }
+ )
+}
+
+@Sampled
+@Composable
+fun FilledTonalButtonSample() {
+ FilledTonalButton(
+ onClick = { /* Do something */ },
+ label = { Text("FilledTonalButton") },
+ secondaryLabel = { Text("Secondary label") },
+ icon = {
+ Icon(
+ Icons.Filled.Favorite,
+ contentDescription = "Localized description",
+ modifier = Modifier.size(ButtonDefaults.IconSize)
+ )
+ }
+ )
+}
+
+@Sampled
+@Composable
+fun SimpleOutlinedButtonSample() {
+ OutlinedButton(
+ onClick = { /* Do something */ },
+ label = { Text("Simple OutlinedButton") }
+ )
+}
+
+@Sampled
+@Composable
+fun OutlinedButtonSample() {
+ OutlinedButton(
+ onClick = { /* Do something */ },
+ label = { Text("OutlinedButton") },
+ secondaryLabel = { Text("Secondary label") },
+ icon = {
+ Icon(
+ Icons.Filled.Favorite,
+ contentDescription = "Localized description",
+ modifier = Modifier.size(ButtonDefaults.IconSize)
+ )
+ }
+ )
+}
+
+@Sampled
+@Composable
+fun SimpleChildButtonSample() {
+ ChildButton(
+ onClick = { /* Do something */ },
+ label = { Text("Simple ChildButton") }
+ )
+}
+
+@Sampled
+@Composable
+fun ChildButtonSample() {
+ ChildButton(
+ onClick = { /* Do something */ },
+ label = { Text("ChildButton") },
+ secondaryLabel = { Text("Secondary label") },
+ icon = {
+ Icon(
+ Icons.Filled.Favorite,
+ contentDescription = "Localized description",
+ modifier = Modifier.size(ButtonDefaults.IconSize)
+ )
+ }
+ )
+}
diff --git a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/MaterialThemeSample.kt b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/MaterialThemeSample.kt
new file mode 100644
index 0000000..71069fd
--- /dev/null
+++ b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/MaterialThemeSample.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ * 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.runtime.Composable
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.material3.MaterialTheme
+import androidx.wear.compose.material3.Text
+
+@Sampled
+@Composable
+fun FixedFontSize() {
+ val typography = MaterialTheme.typography.copy(
+ displayLarge = MaterialTheme.typography.displayLarge.copy(
+ fontSize = with(LocalDensity.current) { 40.dp.toSp() }
+ )
+ )
+ MaterialTheme(typography = typography) {
+ Text(
+ text = "Fixed Font",
+ maxLines = 1,
+ style = MaterialTheme.typography.displayLarge,
+ color = MaterialTheme.colorScheme.onBackground,
+ )
+ }
+}
\ No newline at end of file
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/CurvedTextTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/CurvedTextTest.kt
new file mode 100644
index 0000000..2a7c118
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/CurvedTextTest.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.wear.compose.material3
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.testutils.assertContainsColor
+import androidx.compose.testutils.assertDoesNotContainColor
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.wear.compose.foundation.CurvedLayout
+import androidx.wear.compose.foundation.CurvedTextStyle
+import androidx.wear.compose.foundation.curvedRow
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RequiresApi(Build.VERSION_CODES.O)
+class CurvedTextTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ private val testText = "TestText"
+
+ @Test
+ fun color_parameter_overrides_styleColor() {
+ rule.setContent {
+ CurvedLayout {
+ curvedRow {
+ curvedText(
+ text = testText,
+ color = Color.Red,
+ style = CurvedTextStyle(
+ color = Color.Blue
+ )
+ )
+ }
+ }
+ }
+
+ val curvedTextImage = rule.onNodeWithContentDescription(testText).captureToImage()
+ curvedTextImage.assertContainsColor(Color.Red)
+ curvedTextImage.assertDoesNotContainColor(Color.Blue)
+ }
+
+ @Test
+ fun styleColor_overrides_LocalContentColor() {
+ rule.setContent {
+ CompositionLocalProvider(LocalContentColor provides Color.Yellow) {
+ CurvedLayout {
+ curvedRow {
+ curvedText(
+ text = testText,
+ style = CurvedTextStyle(
+ color = Color.Blue
+ )
+ )
+ }
+ }
+ }
+ }
+
+ val curvedTextImage = rule.onNodeWithContentDescription(testText).captureToImage()
+ curvedTextImage.assertContainsColor(Color.Blue)
+ curvedTextImage.assertDoesNotContainColor(Color.Yellow)
+ }
+
+ @Test
+ fun uses_LocalContentColor_as_fallback() {
+ rule.setContent {
+ CompositionLocalProvider(LocalContentColor provides Color.Yellow) {
+ CurvedLayout {
+ curvedRow {
+ curvedText(
+ text = testText,
+ )
+ }
+ }
+ }
+ }
+
+ rule.onNodeWithContentDescription(testText).captureToImage()
+ .assertContainsColor(Color.Yellow)
+ }
+}
\ No newline at end of file
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextTest.kt
index 2596530..7287e5a 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextTest.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextTest.kt
@@ -34,7 +34,7 @@
import androidx.compose.ui.unit.sp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertThat
import java.lang.IllegalArgumentException
import org.junit.Rule
import org.junit.Test
@@ -61,6 +61,26 @@
private val TestText = "TestText"
@Test
+ fun testDefaultIncludeFontPadding() {
+ var localTextStyle: TextStyle? = null
+ var displayMediumTextStyle: TextStyle? = null
+ rule.setContent {
+ MaterialTheme {
+ localTextStyle = LocalTextStyle.current
+ displayMediumTextStyle = LocalTypography.current.displayMedium
+ }
+ }
+
+ assertThat(
+ localTextStyle?.platformStyle?.paragraphStyle?.includeFontPadding
+ ).isEqualTo(true)
+
+ assertThat(
+ displayMediumTextStyle?.platformStyle?.paragraphStyle?.includeFontPadding
+ ).isEqualTo(true)
+ }
+
+ @Test
fun validateGreaterMinLinesResultsGreaterSize() {
var size1 = 0
var size2 = 0
@@ -90,7 +110,7 @@
}
rule.runOnIdle {
- Truth.assertThat(size2).isGreaterThan(size1)
+ assertThat(size2).isGreaterThan(size1)
}
}
@@ -137,7 +157,7 @@
}
rule.runOnIdle {
- Truth.assertThat(textColor).isEqualTo(expectedColor)
+ assertThat(textColor).isEqualTo(expectedColor)
}
}
@@ -161,7 +181,7 @@
}
rule.runOnIdle {
- Truth.assertThat(textColor).isEqualTo(ExpectedTextStyle.color)
+ assertThat(textColor).isEqualTo(ExpectedTextStyle.color)
}
}
@@ -183,7 +203,7 @@
}
rule.runOnIdle {
- Truth.assertThat(textColor).isEqualTo(Color.Blue)
+ assertThat(textColor).isEqualTo(Color.Blue)
}
}
@@ -217,13 +237,13 @@
}
rule.runOnIdle {
- Truth.assertThat(fontSize).isEqualTo(ExpectedTextStyle.fontSize)
- Truth.assertThat(fontStyle).isEqualTo(ExpectedTextStyle.fontStyle)
- Truth.assertThat(fontWeight).isEqualTo(ExpectedTextStyle.fontWeight)
- Truth.assertThat(fontFamily).isEqualTo(ExpectedTextStyle.fontFamily)
- Truth.assertThat(letterSpacing).isEqualTo(ExpectedTextStyle.letterSpacing)
- Truth.assertThat(textDecoration).isEqualTo(ExpectedTextStyle.textDecoration)
- Truth.assertThat(textAlign).isEqualTo(ExpectedTextStyle.textAlign)
+ assertThat(fontSize).isEqualTo(ExpectedTextStyle.fontSize)
+ assertThat(fontStyle).isEqualTo(ExpectedTextStyle.fontStyle)
+ assertThat(fontWeight).isEqualTo(ExpectedTextStyle.fontWeight)
+ assertThat(fontFamily).isEqualTo(ExpectedTextStyle.fontFamily)
+ assertThat(letterSpacing).isEqualTo(ExpectedTextStyle.letterSpacing)
+ assertThat(textDecoration).isEqualTo(ExpectedTextStyle.textDecoration)
+ assertThat(textAlign).isEqualTo(ExpectedTextStyle.textAlign)
}
}
@@ -262,10 +282,10 @@
}
rule.runOnIdle {
- Truth.assertThat(textAlign).isEqualTo(expectedTextAlign)
- Truth.assertThat(fontSize).isEqualTo(expectedFontSize)
- Truth.assertThat(fontStyle).isEqualTo(expectedFontStyle)
- Truth.assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
+ assertThat(textAlign).isEqualTo(expectedTextAlign)
+ assertThat(fontSize).isEqualTo(expectedFontSize)
+ assertThat(fontStyle).isEqualTo(expectedFontStyle)
+ assertThat(letterSpacing).isEqualTo(expectedLetterSpacing)
}
}
}
\ No newline at end of file
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Button.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Button.kt
index 4523dc5..4322d1f 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Button.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Button.kt
@@ -59,7 +59,10 @@
*
* Button can be enabled or disabled. A disabled button will not respond to click events.
*
- * TODO(b/261838497) Add Material3 samples and UX guidance links
+ * TODO(b/261838497) Add Material3 UX guidance links
+ *
+ * Example of a [Button]:
+ * @sample androidx.wear.compose.material3.samples.SimpleButtonSample
*
* @param onClick Will be called when the user clicks the button
* @param modifier Modifier to be applied to the button
@@ -130,7 +133,10 @@
*
* Button can be enabled or disabled. A disabled button will not respond to click events.
*
- * TODO(b/261838497) Add Material3 samples and UX guidance links
+ * TODO(b/261838497) Add Material3 UX guidance links
+ *
+ * Example of a [FilledTonalButton]:
+ * @sample androidx.wear.compose.material3.samples.SimpleFilledTonalButtonSample
*
* @param onClick Will be called when the user clicks the button
* @param modifier Modifier to be applied to the button
@@ -185,7 +191,10 @@
*
* Button can be enabled or disabled. A disabled button will not respond to click events.
*
- * TODO(b/261838497) Add Material3 samples and UX guidance links
+ * TODO(b/261838497) Add Material3 UX guidance links
+ *
+ * Example of an [OutlinedButton]:
+ * @sample androidx.wear.compose.material3.samples.SimpleOutlinedButtonSample
*
* @param onClick Will be called when the user clicks the button
* @param modifier Modifier to be applied to the button
@@ -240,7 +249,10 @@
*
* Button can be enabled or disabled. A disabled button will not respond to click events.
*
- * TODO(b/261838497) Add Material3 samples and UX guidance links
+ * TODO(b/261838497) Add Material3 UX guidance links
+ *
+ * Example of a [ChildButton]:
+ * @sample androidx.wear.compose.material3.samples.SimpleChildButtonSample
*
* @param onClick Will be called when the user clicks the button
* @param modifier Modifier to be applied to the button
@@ -299,7 +311,10 @@
*
* [Button] can be enabled or disabled. A disabled button will not respond to click events.
*
- * TODO(b/261838497) Add Material3 samples and UX guidance links
+ * TODO(b/261838497) Add Material3 UX guidance links
+ *
+ * Example of a [Button] with an icon and secondary label:
+ * @sample androidx.wear.compose.material3.samples.ButtonSample
*
* @param onClick Will be called when the user clicks the button
* @param modifier Modifier to be applied to the button
@@ -398,7 +413,10 @@
* [FilledTonalButton] can be enabled or disabled. A disabled button will not respond to
* click events.
*
- * TODO(b/261838497) Add Material3 samples and UX guidance links
+ * TODO(b/261838497) Add Material3 UX guidance links
+ *
+ * Example of a [FilledTonalButton] with an icon and secondary label:
+ * @sample androidx.wear.compose.material3.samples.FilledTonalButtonSample
*
* @param onClick Will be called when the user clicks the button
* @param modifier Modifier to be applied to the button
@@ -479,7 +497,10 @@
*
* [OutlinedButton] can be enabled or disabled. A disabled button will not respond to click events.
*
- * TODO(b/261838497) Add Material3 samples and UX guidance links
+ * TODO(b/261838497) Add Material3 UX guidance links
+ *
+ * Example of an [OutlinedButton] with an icon and secondary label:
+ * @sample androidx.wear.compose.material3.samples.OutlinedButtonSample
*
* @param onClick Will be called when the user clicks the button
* @param modifier Modifier to be applied to the button
@@ -559,7 +580,10 @@
*
* [Button] can be enabled or disabled. A disabled button will not respond to click events.
*
- * TODO(b/261838497) Add Material3 samples and UX guidance links
+ * TODO(b/261838497) Add Material3 UX guidance links
+ *
+ * Example of a [ChildButton] with an icon and secondary label:
+ * @sample androidx.wear.compose.material3.samples.ChildButtonSample
*
* @param onClick Will be called when the user clicks the button
* @param modifier Modifier to be applied to the button
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CurvedText.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CurvedText.kt
new file mode 100644
index 0000000..b4d0231
--- /dev/null
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CurvedText.kt
@@ -0,0 +1,120 @@
+/*
+ * 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.ui.graphics.Color
+import androidx.compose.ui.graphics.takeOrElse
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.text.font.FontSynthesis
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.TextUnit
+import androidx.wear.compose.foundation.CurvedDirection
+import androidx.wear.compose.foundation.CurvedLayout
+import androidx.wear.compose.foundation.CurvedModifier
+import androidx.wear.compose.foundation.CurvedScope
+import androidx.wear.compose.foundation.CurvedTextStyle
+import androidx.wear.compose.foundation.basicCurvedText
+import androidx.wear.compose.foundation.curvedRow
+
+/**
+ * CurvedText is a component allowing developers to easily write curved text following
+ * the curvature a circle (usually at the edge of a circular screen).
+ * CurvedText can be only created within the CurvedLayout to ensure the best experience, like being
+ * able to specify to positioning.
+ *
+ * The default [style] uses the [LocalTextStyle] provided by the [MaterialTheme] / components,
+ * converting it to a [CurvedTextStyle]. Note that not all parameters are used by [curvedText].
+ *
+ * If you are setting your own style, you may want to consider first retrieving [LocalTextStyle],
+ * and using [TextStyle.copy] to keep any theme defined attributes, only modifying the specific
+ * attributes you want to override, then convert to [CurvedTextStyle]
+ *
+ * For ease of use, commonly used parameters from [CurvedTextStyle] are also present here. The
+ * order of precedence is as follows:
+ * - If a parameter is explicitly set here (i.e, it is _not_ `null` or [TextUnit.Unspecified]),
+ * then this parameter will always be used.
+ * - If a parameter is _not_ set, (`null` or [TextUnit.Unspecified]), then the corresponding value
+ * from [style] will be used instead.
+ *
+ * Additionally, for [color], if [color] is not set, and [style] does not have a color, then
+ * [LocalContentColor] will be used with an alpha of [LocalContentAlpha]- this allows this
+ * [curvedText] or element containing this [curvedText] to adapt to different background colors and
+ * still maintain contrast and accessibility.
+ *
+ * For samples explicitly specifying style see:
+ * TODO(b/283777480): Add CurvedText samples
+ *
+ * For examples using CompositionLocal to specify the style, see:
+ * TODO(b/283777480): Add CurvedText samples
+ *
+ * For more information, see the
+ * [Curved Text](https://developer.android.com/training/wearables/compose/curved-text)
+ * guide.
+ *
+ * @param text The text to display
+ * @param modifier The [CurvedModifier] to apply to this curved text.
+ * @param background The background color for the text.
+ * @param color [Color] to apply to the text. If [Color.Unspecified], and [style] has no color set,
+ * this will be [LocalContentColor].
+ * @param fontSize The size of glyphs to use when painting the text. See [TextStyle.fontSize].
+ * @param fontFamily The font family to be used when rendering the text.
+ * @param fontWeight The thickness of the glyphs, in a range of [1, 1000]. see [FontWeight]
+ * @param fontStyle The typeface variant to use when drawing the letters (e.g. italic).
+ * @param fontSynthesis Whether to synthesize font weight and/or style when the requested weight
+ * or style cannot be found in the provided font family.
+ * @param style Specifies the style to use.
+ * @param angularDirection Specify if the text is laid out clockwise or anti-clockwise, and if
+ * those needs to be reversed in a Rtl layout.
+ * If not specified, it will be inherited from the enclosing [curvedRow] or [CurvedLayout]
+ * See [CurvedDirection.Angular].
+ * @param overflow How visual overflow should be handled.
+ */
+public fun CurvedScope.curvedText(
+ text: String,
+ modifier: CurvedModifier = CurvedModifier,
+ background: Color = Color.Unspecified,
+ color: Color = Color.Unspecified,
+ fontSize: TextUnit = TextUnit.Unspecified,
+ fontFamily: FontFamily? = null,
+ fontWeight: FontWeight? = null,
+ fontStyle: FontStyle? = null,
+ fontSynthesis: FontSynthesis? = null,
+ style: CurvedTextStyle? = null,
+ angularDirection: CurvedDirection.Angular? = null,
+ overflow: TextOverflow = TextOverflow.Clip,
+) = basicCurvedText(text, modifier, angularDirection, overflow) {
+ val baseStyle = style ?: CurvedTextStyle(LocalTextStyle.current)
+ val textColor = color.takeOrElse {
+ baseStyle.color.takeOrElse {
+ LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
+ }
+ }
+ baseStyle.merge(
+ CurvedTextStyle(
+ color = textColor,
+ fontSize = fontSize,
+ fontFamily = fontFamily,
+ fontWeight = fontWeight,
+ fontStyle = fontStyle,
+ fontSynthesis = fontSynthesis,
+ background = background
+ )
+ )
+}
\ No newline at end of file
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/DefaultPlatformTextStyle.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/DefaultPlatformTextStyle.kt
deleted file mode 100644
index 65dd2202..0000000
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/DefaultPlatformTextStyle.kt
+++ /dev/null
@@ -1,27 +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.ui.text.PlatformTextStyle
-
-private const val DefaultIncludeFontPadding = true
-
-@Suppress("DEPRECATION")
-private val DefaultPlatformTextStyle = PlatformTextStyle(
- includeFontPadding = DefaultIncludeFontPadding
-)
-internal fun defaultPlatformTextStyle(): PlatformTextStyle = DefaultPlatformTextStyle
\ No newline at end of file
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TextButton.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TextButton.kt
index e3c916a..6c9e8b7 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TextButton.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TextButton.kt
@@ -178,12 +178,10 @@
fun textButtonColors(
containerColor: Color = Color.Transparent,
contentColor: Color = MaterialTheme.colorScheme.onBackground,
- disabledContainerColor: Color = MaterialTheme.colorScheme.onSurface.copy(
- alpha = DisabledBorderAndContainerAlpha
+ disabledContainerColor: Color = MaterialTheme.colorScheme.onSurface.toDisabledColor(
+ disabledAlpha = DisabledBorderAndContainerAlpha
),
- disabledContentColor: Color = MaterialTheme.colorScheme.onSurface.copy(
- alpha = ContentAlpha.disabled
- )
+ disabledContentColor: Color = MaterialTheme.colorScheme.onSurface.toDisabledColor()
): TextButtonColors = TextButtonColors(
containerColor = containerColor,
contentColor = contentColor,
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 96e3f33..2197873 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
@@ -29,8 +29,8 @@
* The text styles in this typography are scaled according to the user's preferred font size in
* the system settings. Larger font sizes can be fixed if necessary in order to avoid pressure on
* screen space, because they are already sufficiently accessible.
- * Here is an example of fixing the font size for Display1:
- * @sample androidx.wear.compose.material.samples.FixedFontSize
+ * Here is an example of fixing the font size for DisplayLarge:
+ * @sample androidx.wear.compose.material3.samples.FixedFontSize
*
* TODO(b/273526150) Review documentation for typography, add examples for each size.
* @property displayExtraLarge DisplayExtraLarge is the largest headline. Displays are the
@@ -293,11 +293,15 @@
return if (fontFamily != null) this else copy(fontFamily = default)
}
+private const val DefaultIncludeFontPadding = true
+
/**
* Returns theme default [TextStyle] with default [PlatformTextStyle].
*/
internal val DefaultTextStyle = TextStyle.Default.copy(
- platformStyle = defaultPlatformTextStyle()
+ platformStyle = PlatformTextStyle(
+ includeFontPadding = DefaultIncludeFontPadding
+ )
)
/**
diff --git a/wear/compose/integration-tests/demos/build.gradle b/wear/compose/integration-tests/demos/build.gradle
index 478b99e..0d46a1e 100644
--- a/wear/compose/integration-tests/demos/build.gradle
+++ b/wear/compose/integration-tests/demos/build.gradle
@@ -63,6 +63,8 @@
implementation(project(":wear:compose:compose-foundation-samples"))
implementation(project(':wear:compose:compose-material'))
implementation(project(":wear:compose:compose-material-samples"))
+ implementation(project(':wear:compose:integration-tests:demos:common'))
+ implementation(project(":wear:compose:compose-material3-integration-tests"))
androidTestImplementation(project(":compose:ui:ui-test-junit4"))
androidTestImplementation(project(":emoji2:emoji2"))
diff --git a/wear/compose/integration-tests/demos/common/build.gradle b/wear/compose/integration-tests/demos/common/build.gradle
new file mode 100644
index 0000000..9e6cd01e
--- /dev/null
+++ b/wear/compose/integration-tests/demos/common/build.gradle
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+plugins {
+ id("AndroidXPlugin")
+ id("AndroidXComposePlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+ implementation(libs.kotlinStdlib)
+
+ api("androidx.activity:activity:1.2.0")
+ implementation(project(':wear:compose:compose-material'))
+
+}
+
+android {
+ defaultConfig {
+ minSdkVersion 25
+ }
+ namespace "androidx.wear.compose.integration.demos.common"
+}
diff --git a/wear/compose/integration-tests/demos/common/src/main/java/androidx/wear/compose/integration/demos/common/Demo.kt b/wear/compose/integration-tests/demos/common/src/main/java/androidx/wear/compose/integration/demos/common/Demo.kt
new file mode 100644
index 0000000..56fa2c7
--- /dev/null
+++ b/wear/compose/integration-tests/demos/common/src/main/java/androidx/wear/compose/integration/demos/common/Demo.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.wear.compose.integration.demos.common
+
+import android.app.Activity
+import androidx.activity.ComponentActivity
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.wear.compose.material.SwipeToDismissBoxState
+import kotlin.reflect.KClass
+
+/**
+ * Generic demo with a [title] that will be displayed in the list of demos.
+ */
+sealed class Demo(val title: String, val description: String? = null) {
+ override fun toString() = title
+}
+
+/**
+ * Demo that launches an [Activity] when selected.
+ *
+ * This should only be used for demos that need to customize the activity, the large majority of
+ * demos should just use [ComposableDemo] instead.
+ *
+ * @property activityClass the KClass (Foo::class) of the activity that will be launched when
+ * this demo is selected.
+ */
+class ActivityDemo<T : ComponentActivity>(title: String, val activityClass: KClass<T>) : Demo(title)
+
+/**
+ * A category of [Demo]s, that will display a list of [demos] when selected.
+ */
+class DemoCategory(
+ title: String,
+ val demos: List<Demo>
+) : Demo(title)
+
+/**
+ * Parameters which are used by [Demo] screens.
+ */
+class DemoParameters(
+ val navigateBack: () -> Unit,
+ val swipeToDismissBoxState: SwipeToDismissBoxState
+)
+
+/**
+ * Demo that displays [Composable] [content] when selected,
+ * with a method to navigate back to the parent.
+ */
+class ComposableDemo(
+ title: String,
+ description: String? = null,
+ val content: @Composable (params: DemoParameters) -> Unit,
+) : Demo(title, description)
+
+@Composable
+fun Centralize(modifier: Modifier = Modifier, content: @Composable ColumnScope.() -> Unit) {
+ Column(
+ modifier = modifier.fillMaxSize(),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally,
+ content = content
+ )
+}
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 9fe82bca..646addf 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
@@ -28,10 +28,10 @@
import androidx.test.espresso.Espresso
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
-import androidx.wear.compose.integration.demos.Demo
import androidx.wear.compose.integration.demos.DemoActivity
-import androidx.wear.compose.integration.demos.DemoCategory
import androidx.wear.compose.integration.demos.WearComposeDemos
+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
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoActivity.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoActivity.kt
index 361fb0e..7de734f 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoActivity.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoActivity.kt
@@ -36,6 +36,9 @@
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalView
import androidx.core.app.ActivityCompat
+import androidx.wear.compose.integration.demos.common.ActivityDemo
+import androidx.wear.compose.integration.demos.common.Demo
+import androidx.wear.compose.integration.demos.common.DemoCategory
import androidx.wear.compose.material.MaterialTheme
/**
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt
index 108b9ad..7e6aa69 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt
@@ -32,7 +32,6 @@
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.focus.FocusRequester
@@ -49,6 +48,11 @@
import androidx.wear.compose.foundation.lazy.ScalingLazyListState
import androidx.wear.compose.foundation.lazy.ScalingParams
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
+import androidx.wear.compose.integration.demos.common.ActivityDemo
+import androidx.wear.compose.integration.demos.common.ComposableDemo
+import androidx.wear.compose.integration.demos.common.Demo
+import androidx.wear.compose.integration.demos.common.DemoCategory
+import androidx.wear.compose.integration.demos.common.DemoParameters
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.ChipDefaults
import androidx.wear.compose.material.ListHeader
@@ -154,13 +158,13 @@
modifier = Modifier.fillMaxWidth()
)
}
- if (demo.description != null) {
+ demo.description?.let { description ->
item {
CompositionLocalProvider(
LocalTextStyle provides MaterialTheme.typography.caption3
) {
Text(
- text = demo.description,
+ text = description,
modifier = Modifier.fillMaxWidth().align(Alignment.Center),
textAlign = TextAlign.Center
)
@@ -187,7 +191,6 @@
internal data class TimestampedDelta(val time: Long, val delta: Float)
-@OptIn(ExperimentalComposeUiApi::class)
@Suppress("ComposableModifierFactory")
@Composable
fun Modifier.rsbScroll(
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoComponents.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoComponents.kt
index ea5174c..c82c27b 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoComponents.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoComponents.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * 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.
@@ -16,14 +16,8 @@
package androidx.wear.compose.integration.demos
-import android.app.Activity
-import androidx.activity.ComponentActivity
import androidx.compose.foundation.Image
-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.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.size
@@ -43,53 +37,7 @@
import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.LocalContentAlpha
import androidx.wear.compose.material.MaterialTheme
-import androidx.wear.compose.material.SwipeToDismissBoxState
import androidx.wear.compose.material.Text
-import kotlin.reflect.KClass
-
-/**
- * Generic demo with a [title] that will be displayed in the list of demos.
- */
-sealed class Demo(val title: String, val description: String? = null) {
- override fun toString() = title
-}
-
-/**
- * Demo that launches an [Activity] when selected.
- *
- * This should only be used for demos that need to customize the activity, the large majority of
- * demos should just use [ComposableDemo] instead.
- *
- * @property activityClass the KClass (Foo::class) of the activity that will be launched when
- * this demo is selected.
- */
-class ActivityDemo<T : ComponentActivity>(title: String, val activityClass: KClass<T>) : Demo(title)
-
-/**
- * A category of [Demo]s, that will display a list of [demos] when selected.
- */
-class DemoCategory(
- title: String,
- val demos: List<Demo>
-) : Demo(title)
-
-/**
- * Parameters which are used by [Demo] screens.
- */
-class DemoParameters(
- val navigateBack: () -> Unit,
- val swipeToDismissBoxState: SwipeToDismissBoxState
-)
-
-/**
- * Demo that displays [Composable] [content] when selected,
- * with a method to navigate back to the parent.
- */
-class ComposableDemo(
- title: String,
- description: String? = null,
- val content: @Composable (params: DemoParameters) -> Unit,
-) : Demo(title, description)
/**
* A simple [Icon] with default size
@@ -162,16 +110,6 @@
}
}
-@Composable
-fun Centralize(modifier: Modifier = Modifier, content: @Composable ColumnScope.() -> Unit) {
- Column(
- modifier = modifier.fillMaxSize(),
- verticalArrangement = Arrangement.Center,
- horizontalAlignment = Alignment.CenterHorizontally,
- content = content
- )
-}
-
public val DemoListTag = "DemoListTag"
public val AlternatePrimaryColor1 = Color(0x7F, 0xCF, 0xFF)
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/Demos.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/Demos.kt
index 6fa889e..8efc582 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/Demos.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/Demos.kt
@@ -23,7 +23,10 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
+import androidx.wear.compose.integration.demos.common.ComposableDemo
+import androidx.wear.compose.integration.demos.common.DemoCategory
import androidx.wear.compose.material.Text
+import androidx.wear.compose.material3.demos.WearMaterial3Demos
val Info = DemoCategory(
"App Info",
@@ -56,6 +59,7 @@
listOf(
WearFoundationDemos,
WearMaterialDemos,
+ WearMaterial3Demos,
Info
)
)
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/FoundationDemos.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/FoundationDemos.kt
index c54950a..730a272 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/FoundationDemos.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/FoundationDemos.kt
@@ -34,6 +34,8 @@
import androidx.wear.compose.foundation.samples.SimpleScalingLazyColumnWithContentPadding
import androidx.wear.compose.foundation.samples.SimpleScalingLazyColumnWithSnap
import androidx.wear.compose.foundation.samples.SwipeToRevealWithExpandables
+import androidx.wear.compose.integration.demos.common.ComposableDemo
+import androidx.wear.compose.integration.demos.common.DemoCategory
val WearFoundationDemos = DemoCategory(
"Foundation",
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/MaterialDemos.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/MaterialDemos.kt
index 205da0d..c4ab979 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/MaterialDemos.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/MaterialDemos.kt
@@ -27,6 +27,9 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
+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.material.samples.AlertDialogSample
import androidx.wear.compose.material.samples.AlertWithButtons
import androidx.wear.compose.material.samples.AlertWithChips
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ScrollingWithRotaryInputDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ScrollingWithRotaryInputDemo.kt
index 7153372..33c1b57 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ScrollingWithRotaryInputDemo.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ScrollingWithRotaryInputDemo.kt
@@ -26,6 +26,7 @@
import androidx.compose.ui.samples.PreRotaryEventSample
import androidx.compose.ui.samples.RotaryEventSample
import androidx.compose.ui.unit.dp
+import androidx.wear.compose.integration.demos.common.ComposableDemo
import androidx.wear.compose.material.Text
internal val RotaryInputDemos = listOf(
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 0d06716..6c5270e 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
@@ -25,6 +25,7 @@
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
@@ -86,6 +87,8 @@
SwipeToRevealChipExpandable(
expandableState = currentState
)
+ } else {
+ Spacer(modifier = Modifier.width(200.dp))
}
}
}
@@ -123,12 +126,8 @@
from = currentFrom,
email = currentEmail
)
- }
-
- LaunchedEffect(currentState.expanded) {
- if (!currentState.expanded) {
- emailMap.remove(currentFrom)
- }
+ } else {
+ Spacer(modifier = Modifier.width(200.dp))
}
}
}
@@ -155,12 +154,11 @@
if (state.currentValue == RevealValue.Revealed) {
delay(2000)
expandableState.expanded = false
- state.snapTo(RevealValue.Covered)
}
}
Box(
contentAlignment = Alignment.Center,
- modifier = Modifier.size(width = 200.dp, height = 50.dp)
+ modifier = Modifier.size(width = 200.dp, height = 52.dp)
) {
SwipeToRevealWithDefaultButtons(
shape = CircleShape,
@@ -191,11 +189,10 @@
if (state.currentValue == RevealValue.Revealed) {
delay(2000)
expandableState.expanded = false
- state.snapTo(RevealValue.Covered)
}
}
SwipeToRevealWithDefaultButtons(
- shape = RoundedCornerShape(10.dp),
+ shape = RoundedCornerShape(30.dp),
state = state
) {
AppCard(
@@ -313,6 +310,8 @@
)
}
}
+ } else {
+ Spacer(modifier = Modifier.width(200.dp))
}
LaunchedEffect(state.currentValue) {
if (state.currentValue == RevealValue.Revealed) {
diff --git a/wear/compose/integration-tests/macrobenchmark-target/build.gradle b/wear/compose/integration-tests/macrobenchmark-target/build.gradle
index f5c9d71e..af518ce 100644
--- a/wear/compose/integration-tests/macrobenchmark-target/build.gradle
+++ b/wear/compose/integration-tests/macrobenchmark-target/build.gradle
@@ -28,7 +28,8 @@
release {
minifyEnabled true
shrinkResources true
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
+ proguardFiles(getDefaultProguardFile('proguard-android-optimize.txt'),
+ "proguard-benchmark.pro")
}
}
}
@@ -48,6 +49,9 @@
implementation project(path: ':wear:compose:compose-foundation')
implementation project(path: ':wear:compose:compose-material')
implementation project(path: ':wear:compose:compose-navigation')
+ implementation(project(path:':compose:runtime:runtime-tracing'))
+ implementation(project(path:':tracing:tracing-perfetto'))
+ implementation(project(path:':tracing:tracing-perfetto-binary'))
}
android.defaultConfig.minSdkVersion 25
\ No newline at end of file
diff --git a/wear/compose/integration-tests/macrobenchmark-target/proguard-benchmark.pro b/wear/compose/integration-tests/macrobenchmark-target/proguard-benchmark.pro
new file mode 100644
index 0000000..ef6c30b
--- /dev/null
+++ b/wear/compose/integration-tests/macrobenchmark-target/proguard-benchmark.pro
@@ -0,0 +1,12 @@
+# Preserve the line number information for debugging stack traces.
+-keepattributes SourceFile,LineNumberTable
+
+# Uncomment this to hide the original source file name.
+-renamesourcefileattribute SourceFile
+
+# Repackage classes into the top-level.
+-repackageclasses
+
+# When generating the baseline profile we want the proper names of
+# the methods and classes
+-dontobfuscate
diff --git a/wear/compose/integration-tests/macrobenchmark/build.gradle b/wear/compose/integration-tests/macrobenchmark/build.gradle
index 414dd2b..61090b4 100644
--- a/wear/compose/integration-tests/macrobenchmark/build.gradle
+++ b/wear/compose/integration-tests/macrobenchmark/build.gradle
@@ -23,6 +23,7 @@
android {
defaultConfig {
minSdkVersion 29
+ testInstrumentationRunnerArguments["androidx.benchmark.fullTracing.enable"] = "true"
}
namespace "androidx.wear.compose.integration.macrobenchmark"
targetProjectPath = ":wear:compose:integration-tests:macrobenchmark-target"
@@ -31,9 +32,12 @@
// Create a release build type and make sure it's the only one enabled.
// This is needed because we benchmark the release build type only.
-android.buildTypes { release {} }
+android.buildTypes {
+ release {
+ proguardFiles("proguard-benchmark.pro")
+ }
+}
androidComponents { beforeVariants(selector().all()) { enabled = buildType == 'release' } }
-
dependencies {
implementation(project(":benchmark:benchmark-junit4"))
implementation(project(":benchmark:benchmark-macro-junit4"))
@@ -43,4 +47,5 @@
implementation(libs.testCore)
implementation(libs.testRunner)
implementation(libs.testUiautomator)
+ implementation project(path: ':wear:compose:compose-material')
}
diff --git a/wear/compose/integration-tests/macrobenchmark/proguard-benchmark.pro b/wear/compose/integration-tests/macrobenchmark/proguard-benchmark.pro
new file mode 100644
index 0000000..ef6c30b
--- /dev/null
+++ b/wear/compose/integration-tests/macrobenchmark/proguard-benchmark.pro
@@ -0,0 +1,12 @@
+# Preserve the line number information for debugging stack traces.
+-keepattributes SourceFile,LineNumberTable
+
+# Uncomment this to hide the original source file name.
+-renamesourcefileattribute SourceFile
+
+# Repackage classes into the top-level.
+-repackageclasses
+
+# When generating the baseline profile we want the proper names of
+# the methods and classes
+-dontobfuscate
diff --git a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/CompositionMetric.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/CompositionMetric.kt
new file mode 100644
index 0000000..eddb34a
--- /dev/null
+++ b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/CompositionMetric.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.wear.compose.integration.macrobenchmark
+
+import androidx.benchmark.macro.ExperimentalMetricApi
+import androidx.benchmark.macro.TraceMetric
+import androidx.benchmark.perfetto.ExperimentalPerfettoTraceProcessorApi
+import androidx.benchmark.perfetto.PerfettoTraceProcessor
+import kotlin.time.Duration.Companion.nanoseconds
+import kotlin.time.DurationUnit
+
+@OptIn(ExperimentalMetricApi::class)
+internal class CompositionMetric(private val composable: String) : TraceMetric() {
+ @OptIn(ExperimentalMetricApi::class, ExperimentalPerfettoTraceProcessorApi::class)
+ override fun getResult(
+ captureInfo: CaptureInfo,
+ traceSession: PerfettoTraceProcessor.Session
+ ): List<Measurement> {
+ val shortName = composable.substringAfterLast(".")
+
+ val durationsNs = traceSession.query(
+ """
+ SELECT * FROM slice
+ INNER JOIN thread_track on slice.track_id = thread_track.id
+ INNER JOIN thread USING(utid)
+ INNER JOIN process USING(upid)
+ WHERE process.name LIKE "${captureInfo.targetPackageName}"
+ AND slice.name LIKE "$composable (%)"
+ """.trimIndent()
+ ).map { it.long("dur") }
+
+ return listOf(
+ Measurement(
+ "${shortName}RecomposeDurMs",
+ durationsNs.sumOf { it }.nanoseconds.toDouble(DurationUnit.MILLISECONDS)
+ ),
+ Measurement("${shortName}RecomposeCount", durationsNs.count().toDouble())
+ )
+ }
+}
\ No newline at end of file
diff --git a/wear/protolayout/protolayout-expression-pipeline/api/current.txt b/wear/protolayout/protolayout-expression-pipeline/api/current.txt
index cc787d5..ed2965a 100644
--- a/wear/protolayout/protolayout-expression-pipeline/api/current.txt
+++ b/wear/protolayout/protolayout-expression-pipeline/api/current.txt
@@ -25,8 +25,8 @@
method public androidx.wear.protolayout.expression.pipeline.QuotaManager? getAnimationQuotaManager();
method public androidx.wear.protolayout.expression.pipeline.QuotaManager? getDynamicTypesQuotaManager();
method public java.util.Map<androidx.wear.protolayout.expression.PlatformDataKey<?>!,androidx.wear.protolayout.expression.pipeline.PlatformDataProvider!> getPlatformDataProviders();
+ method public androidx.wear.protolayout.expression.pipeline.PlatformTimeUpdateNotifier? getPlatformTimeUpdateNotifier();
method public androidx.wear.protolayout.expression.pipeline.StateStore? getStateStore();
- method public androidx.wear.protolayout.expression.pipeline.TimeGateway? getTimeGateway();
}
public static final class DynamicTypeEvaluator.Config.Builder {
@@ -35,8 +35,8 @@
method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config build();
method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config.Builder setAnimationQuotaManager(androidx.wear.protolayout.expression.pipeline.QuotaManager);
method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config.Builder setDynamicTypesQuotaManager(androidx.wear.protolayout.expression.pipeline.QuotaManager);
+ method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config.Builder setPlatformTimeUpdateNotifier(androidx.wear.protolayout.expression.pipeline.PlatformTimeUpdateNotifier);
method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config.Builder setStateStore(androidx.wear.protolayout.expression.pipeline.StateStore);
- method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config.Builder setTimeGateway(androidx.wear.protolayout.expression.pipeline.TimeGateway);
}
public static class DynamicTypeEvaluator.EvaluationException extends java.lang.Exception {
@@ -49,8 +49,8 @@
}
public interface PlatformDataProvider {
- method public void registerForData(java.util.concurrent.Executor, androidx.wear.protolayout.expression.pipeline.PlatformDataReceiver);
- method public void unregisterForData();
+ method public void clearReceiver();
+ method public void setReceiver(java.util.concurrent.Executor, androidx.wear.protolayout.expression.pipeline.PlatformDataReceiver);
}
public interface PlatformDataReceiver {
@@ -58,26 +58,21 @@
method public void onInvalidated(java.util.Set<androidx.wear.protolayout.expression.PlatformDataKey<?>!>);
}
+ public interface PlatformTimeUpdateNotifier {
+ method public void clearReceiver();
+ method public void setReceiver(java.util.concurrent.Callable<com.google.common.util.concurrent.ListenableFuture<java.lang.Void!>!>);
+ }
+
public interface QuotaManager {
method public void releaseQuota(int);
method public boolean tryAcquireQuota(int);
}
- public class StateStore {
+ public final class StateStore {
method public static androidx.wear.protolayout.expression.pipeline.StateStore create(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
method public static int getMaxStateEntryCount();
method @UiThread public void setAppStateEntryValues(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
}
- public interface TimeGateway {
- method public void registerForUpdates(java.util.concurrent.Executor, androidx.wear.protolayout.expression.pipeline.TimeGateway.TimeCallback);
- method public void unregisterForUpdates(androidx.wear.protolayout.expression.pipeline.TimeGateway.TimeCallback);
- }
-
- public static interface TimeGateway.TimeCallback {
- method public void onData();
- method public void onPreUpdate();
- }
-
}
diff --git a/wear/protolayout/protolayout-expression-pipeline/api/restricted_current.txt b/wear/protolayout/protolayout-expression-pipeline/api/restricted_current.txt
index a61bc5f..739af49 100644
--- a/wear/protolayout/protolayout-expression-pipeline/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-expression-pipeline/api/restricted_current.txt
@@ -25,8 +25,8 @@
method public androidx.wear.protolayout.expression.pipeline.QuotaManager? getAnimationQuotaManager();
method public androidx.wear.protolayout.expression.pipeline.QuotaManager? getDynamicTypesQuotaManager();
method public java.util.Map<androidx.wear.protolayout.expression.PlatformDataKey<?>!,androidx.wear.protolayout.expression.pipeline.PlatformDataProvider!> getPlatformDataProviders();
+ method public androidx.wear.protolayout.expression.pipeline.PlatformTimeUpdateNotifier? getPlatformTimeUpdateNotifier();
method public androidx.wear.protolayout.expression.pipeline.StateStore? getStateStore();
- method public androidx.wear.protolayout.expression.pipeline.TimeGateway? getTimeGateway();
}
public static final class DynamicTypeEvaluator.Config.Builder {
@@ -35,8 +35,8 @@
method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config build();
method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config.Builder setAnimationQuotaManager(androidx.wear.protolayout.expression.pipeline.QuotaManager);
method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config.Builder setDynamicTypesQuotaManager(androidx.wear.protolayout.expression.pipeline.QuotaManager);
+ method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config.Builder setPlatformTimeUpdateNotifier(androidx.wear.protolayout.expression.pipeline.PlatformTimeUpdateNotifier);
method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config.Builder setStateStore(androidx.wear.protolayout.expression.pipeline.StateStore);
- method public androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.Config.Builder setTimeGateway(androidx.wear.protolayout.expression.pipeline.TimeGateway);
}
public static class DynamicTypeEvaluator.EvaluationException extends java.lang.Exception {
@@ -49,8 +49,8 @@
}
public interface PlatformDataProvider {
- method public void registerForData(java.util.concurrent.Executor, androidx.wear.protolayout.expression.pipeline.PlatformDataReceiver);
- method public void unregisterForData();
+ method public void clearReceiver();
+ method public void setReceiver(java.util.concurrent.Executor, androidx.wear.protolayout.expression.pipeline.PlatformDataReceiver);
}
public interface PlatformDataReceiver {
@@ -58,18 +58,17 @@
method public void onInvalidated(java.util.Set<androidx.wear.protolayout.expression.PlatformDataKey<?>!>);
}
+ public interface PlatformTimeUpdateNotifier {
+ method public void clearReceiver();
+ method public void setReceiver(java.util.concurrent.Callable<com.google.common.util.concurrent.ListenableFuture<java.lang.Void!>!>);
+ }
+
public interface QuotaManager {
method public void releaseQuota(int);
method public boolean tryAcquireQuota(int);
}
- @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class SensorGatewaySingleDataProvider implements androidx.wear.protolayout.expression.pipeline.PlatformDataProvider {
- ctor public SensorGatewaySingleDataProvider(androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway, androidx.wear.protolayout.expression.PlatformDataKey<?>);
- method public void registerForData(java.util.concurrent.Executor, androidx.wear.protolayout.expression.pipeline.PlatformDataReceiver);
- method public void unregisterForData();
- }
-
- public class StateStore {
+ public final class StateStore {
ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public StateStore(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue!>);
method public static androidx.wear.protolayout.expression.pipeline.StateStore create(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
method public static int getMaxStateEntryCount();
@@ -77,33 +76,5 @@
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @UiThread public void setAppStateEntryValuesProto(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue!>);
}
- public interface TimeGateway {
- method public void registerForUpdates(java.util.concurrent.Executor, androidx.wear.protolayout.expression.pipeline.TimeGateway.TimeCallback);
- method public void unregisterForUpdates(androidx.wear.protolayout.expression.pipeline.TimeGateway.TimeCallback);
- }
-
- public static interface TimeGateway.TimeCallback {
- method public void onData();
- method public void onPreUpdate();
- }
-
-}
-
-package androidx.wear.protolayout.expression.pipeline.sensor {
-
- @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SensorGateway {
- method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void disableUpdates();
- method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void enableUpdates();
- method @UiThread public void registerSensorGatewayConsumer(androidx.wear.protolayout.expression.PlatformDataKey<?>, androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway.Consumer);
- method @UiThread public void registerSensorGatewayConsumer(androidx.wear.protolayout.expression.PlatformDataKey<?>, java.util.concurrent.Executor, androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway.Consumer);
- method @UiThread public void unregisterSensorGatewayConsumer(androidx.wear.protolayout.expression.PlatformDataKey<?>, androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway.Consumer);
- }
-
- public static interface SensorGateway.Consumer {
- method @AnyThread public void onData(double);
- method @AnyThread public default void onInvalidated();
- method @AnyThread public default void onPreUpdate();
- }
-
}
diff --git a/wear/protolayout/protolayout-expression-pipeline/build.gradle b/wear/protolayout/protolayout-expression-pipeline/build.gradle
index 4f92627..655a5e5 100644
--- a/wear/protolayout/protolayout-expression-pipeline/build.gradle
+++ b/wear/protolayout/protolayout-expression-pipeline/build.gradle
@@ -23,9 +23,11 @@
dependencies {
annotationProcessor(libs.nullaway)
+ api(libs.guavaListenableFuture)
api("androidx.annotation:annotation:1.2.0")
implementation("androidx.collection:collection:1.2.0")
implementation("androidx.core:core:1.7.0")
+ implementation("androidx.concurrent:concurrent-futures:1.1.0")
implementation("androidx.annotation:annotation-experimental:1.3.0")
implementation(project(path: ":wear:protolayout:protolayout-proto", configuration: "shadow"))
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/BoolNodes.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/BoolNodes.java
index 1651688..2cdde6f 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/BoolNodes.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/BoolNodes.java
@@ -61,11 +61,11 @@
/** Dynamic boolean node that gets value from the state. */
static class StateBoolNode extends StateSourceNode<Boolean> {
StateBoolNode(
- StateStore stateStore,
+ DataStore dataStore,
StateBoolSource protoNode,
DynamicTypeValueReceiverWithPreUpdate<Boolean> downstream) {
super(
- stateStore,
+ dataStore,
StateSourceNode.<DynamicBool>createKey(
protoNode.getSourceNamespace(), protoNode.getSourceKey()),
se -> se.getBoolVal().getValue(),
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/ColorNodes.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/ColorNodes.java
index ed1d027..0184038 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/ColorNodes.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/ColorNodes.java
@@ -60,11 +60,11 @@
/** Dynamic color node that gets value from the platform source. */
static class StateColorSourceNode extends StateSourceNode<Integer> {
StateColorSourceNode(
- StateStore stateStore,
+ DataStore dataStore,
StateColorSource protoNode,
DynamicTypeValueReceiverWithPreUpdate<Integer> downstream) {
super(
- stateStore,
+ dataStore,
StateSourceNode.<DynamicColor>createKey(
protoNode.getSourceNamespace(), protoNode.getSourceKey()),
se -> se.getColorVal().getArgb(),
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DataStore.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DataStore.java
new file mode 100644
index 0000000..e4e92ef
--- /dev/null
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DataStore.java
@@ -0,0 +1,49 @@
+/*
+ * 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.protolayout.expression.pipeline;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.wear.protolayout.expression.DynamicDataKey;
+import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
+
+/**
+ * {@link DynamicDataKey} to {@link DynamicDataValue} storage for ProtoLayout, which also supports
+ * sending callback when data items change.
+ */
+abstract class DataStore {
+ /**
+ * Registers the given callback for updates to the data item for the given {@code key}.
+ *
+ * <p>Note that the callback will be executed on the UI thread.
+ */
+ abstract void registerCallback(
+ @NonNull DynamicDataKey<?> key,
+ @NonNull DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback);
+
+ /** Unregisters the callback for the given {@code key} from receiving the updates. */
+ abstract void unregisterCallback(
+ @NonNull DynamicDataKey<?> key,
+ @NonNull DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback);
+
+ /**
+ * Retrieve the {@link DynamicDataValue} associated with the given {@link DynamicDataKey} in
+ * the store.
+ */
+ @Nullable
+ abstract DynamicDataValue getDynamicDataValuesProto(@NonNull DynamicDataKey<?> key);
+}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeBindingRequest.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeBindingRequest.java
index f4ddf02..1af5943 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeBindingRequest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeBindingRequest.java
@@ -17,6 +17,7 @@
package androidx.wear.protolayout.expression.pipeline;
import android.icu.util.ULocale;
+
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
@@ -28,6 +29,7 @@
import androidx.wear.protolayout.expression.proto.DynamicProto.DynamicInstant;
import androidx.wear.protolayout.expression.proto.DynamicProto.DynamicInt32;
import androidx.wear.protolayout.expression.proto.DynamicProto.DynamicString;
+
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.Executor;
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluator.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluator.java
index a247482..4313247 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluator.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluator.java
@@ -20,8 +20,6 @@
import android.annotation.SuppressLint;
import android.icu.util.ULocale;
-import android.os.Handler;
-import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -63,7 +61,7 @@
import androidx.wear.protolayout.expression.pipeline.StringNodes.Int32FormatNode;
import androidx.wear.protolayout.expression.pipeline.StringNodes.StateStringNode;
import androidx.wear.protolayout.expression.pipeline.StringNodes.StringConcatOpNode;
-import androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway;
+import androidx.wear.protolayout.expression.proto.DynamicProto;
import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableDynamicColor;
import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableDynamicFloat;
import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableDynamicInt32;
@@ -135,6 +133,7 @@
@NonNull private static final StateStore EMPTY_STATE_STORE = new StateStore(emptyMap());
@NonNull private final StateStore mStateStore;
+ @NonNull private final PlatformDataStore mPlatformDataStore;
@NonNull private final QuotaManager mAnimationQuotaManager;
@NonNull private final QuotaManager mDynamicTypesQuotaManager;
@NonNull private final EpochTimePlatformDataSource mTimeDataSource;
@@ -143,23 +142,23 @@
public static final class Config {
@Nullable private final StateStore mStateStore;
@Nullable private final QuotaManager mAnimationQuotaManager;
- @Nullable private final TimeGateway mTimeGateway;
@Nullable private final QuotaManager mDynamicTypesQuotaManager;
@NonNull private final Map<PlatformDataKey<?>, PlatformDataProvider>
mSourceKeyToDataProviders = new ArrayMap<>();
+ @Nullable private final PlatformTimeUpdateNotifier mPlatformTimeUpdateNotifier;
Config(
@Nullable StateStore stateStore,
@Nullable QuotaManager animationQuotaManager,
@Nullable QuotaManager dynamicTypesQuotaManager,
- @Nullable TimeGateway timeGateway,
@NonNull Map<PlatformDataKey<?>, PlatformDataProvider>
- sourceKeyToDataProviders) {
+ sourceKeyToDataProviders,
+ @Nullable PlatformTimeUpdateNotifier platformTimeUpdateNotifier) {
this.mStateStore = stateStore;
this.mAnimationQuotaManager = animationQuotaManager;
- this.mTimeGateway = timeGateway;
this.mDynamicTypesQuotaManager = dynamicTypesQuotaManager;
this.mSourceKeyToDataProviders.putAll(sourceKeyToDataProviders);
+ this.mPlatformTimeUpdateNotifier = platformTimeUpdateNotifier;
}
/** Builds a {@link DynamicTypeEvaluator.Config}. */
@@ -167,9 +166,9 @@
@Nullable private StateStore mStateStore = null;
@Nullable private QuotaManager mAnimationQuotaManager = null;
@Nullable private QuotaManager mDynamicTypesQuotaManager;
- @Nullable private TimeGateway mTimeGateway = null;
@NonNull private final Map<PlatformDataKey<?>, PlatformDataProvider>
mSourceKeyToDataProviders = new ArrayMap<>();
+ @Nullable private PlatformTimeUpdateNotifier mPlatformTimeUpdateNotifier;
/**
* Sets the state store that will be used for dereferencing the state keys in the
@@ -185,18 +184,6 @@
}
/**
- * Sets the quota manager used for limiting the total size of dynamic types in the
- * pipeline.
- *
- * <p>If not set, number of dynamic types will not be restricted.
- */
- @NonNull
- public Builder setDynamicTypesQuotaManager(@NonNull QuotaManager value) {
- mDynamicTypesQuotaManager = value;
- return this;
- }
-
- /**
* Sets the quota manager used for limiting the number of concurrently running
* animations.
*
@@ -210,14 +197,14 @@
}
/**
- * Sets the gateway used for time data.
+ * Sets the quota manager used for limiting the total size of dynamic types in the
+ * pipeline.
*
- * <p>If not set, a default 1hz {@link TimeGateway} implementation that utilizes a
- * main-thread {@code Handler} to trigger is used.
+ * <p>If not set, number of dynamic types will not be restricted.
*/
@NonNull
- public Builder setTimeGateway(@NonNull TimeGateway value) {
- mTimeGateway = value;
+ public Builder setDynamicTypesQuotaManager(@NonNull QuotaManager value) {
+ mDynamicTypesQuotaManager = value;
return this;
}
@@ -253,14 +240,25 @@
return this;
}
+ /**
+ * Sets the notifier used for updating the platform time data. If not set, by default
+ * platform time will be updated at 1Hz using a {@code Handler} on the main thread.
+ */
+ @NonNull
+ public Builder setPlatformTimeUpdateNotifier(
+ @NonNull PlatformTimeUpdateNotifier notifier) {
+ this.mPlatformTimeUpdateNotifier = notifier;
+ return this;
+ }
+
@NonNull
public Config build() {
return new Config(
mStateStore,
mAnimationQuotaManager,
mDynamicTypesQuotaManager,
- mTimeGateway,
- mSourceKeyToDataProviders);
+ mSourceKeyToDataProviders,
+ mPlatformTimeUpdateNotifier);
}
}
@@ -275,16 +273,6 @@
}
/**
- * Gets the quota manager used for limiting the total number of dynamic types in the
- * pipeline, or {@code null} if there are no restriction on the number of dynamic types. If
- * present, the quota manager is used to prevent unreasonably expensive expressions.
- */
- @Nullable
- public QuotaManager getDynamicTypesQuotaManager() {
- return mDynamicTypesQuotaManager;
- }
-
- /**
* Gets the quota manager used for limiting the number of concurrently running animations,
* or {@code null} if animations are disabled, causing non-infinite animations to have to
* the end value immediately.
@@ -295,12 +283,13 @@
}
/**
- * Gets the gateway used for time data, or {@code null} if a default 1hz {@link TimeGateway}
- * that utilizes a main-thread {@code Handler} to trigger is used.
+ * Gets the quota manager used for limiting the total number of dynamic types in the
+ * pipeline, or {@code null} if there are no restriction on the number of dynamic types. If
+ * present, the quota manager is used to prevent unreasonably expensive expressions.
*/
@Nullable
- public TimeGateway getTimeGateway() {
- return mTimeGateway;
+ public QuotaManager getDynamicTypesQuotaManager() {
+ return mDynamicTypesQuotaManager;
}
/**
@@ -311,6 +300,12 @@
return new ArrayMap<>(
(ArrayMap<PlatformDataKey<?>, PlatformDataProvider>) mSourceKeyToDataProviders);
}
+
+ /** Gets the notifier used for updating the platform time data. */
+ @Nullable
+ public PlatformTimeUpdateNotifier getPlatformTimeUpdateNotifier() {
+ return mPlatformTimeUpdateNotifier;
+ }
}
/** Constructs a {@link DynamicTypeEvaluator}. */
@@ -325,16 +320,14 @@
config.getDynamicTypesQuotaManager() != null
? config.getDynamicTypesQuotaManager()
: NO_OP_QUOTA_MANAGER;
- Handler uiHandler = new Handler(Looper.getMainLooper());
- MainThreadExecutor uiExecutor = new MainThreadExecutor(uiHandler);
- TimeGateway timeGateway = config.getTimeGateway();
- if (timeGateway == null) {
- timeGateway = new TimeGatewayImpl(uiHandler);
- ((TimeGatewayImpl) timeGateway).enableUpdates();
+ this.mPlatformDataStore = new PlatformDataStore(config.getPlatformDataProviders());
+ PlatformTimeUpdateNotifier notifier =
+ config.getPlatformTimeUpdateNotifier();
+ if (notifier == null) {
+ notifier = new PlatformTimeUpdateNotifierImpl();
+ ((PlatformTimeUpdateNotifierImpl) notifier).setUpdatesEnabled(true);
}
- this.mTimeDataSource = new EpochTimePlatformDataSource(uiExecutor, timeGateway);
-
- this.mStateStore.putAllPlatformProviders(config.getPlatformDataProviders());
+ this.mTimeDataSource = new EpochTimePlatformDataSource(notifier);
}
/**
@@ -550,8 +543,14 @@
}
case STATE_SOURCE:
{
- node = new StateStringNode(mStateStore, stringSource.getStateSource(), consumer);
- break;
+ DynamicProto.StateStringSource stateSource = stringSource.getStateSource();
+ node =
+ new StateStringNode(
+ stateSource.getSourceNamespace().isEmpty()
+ ? mStateStore : mPlatformDataStore,
+ stateSource,
+ consumer);
+ break;
}
case CONDITIONAL_OP:
{
@@ -617,7 +616,7 @@
break;
case PLATFORM_SOURCE: {
node = new LegacyPlatformInt32SourceNode(
- mStateStore,
+ mPlatformDataStore,
int32Source.getPlatformSource(),
consumer);
break;
@@ -641,8 +640,12 @@
}
case STATE_SOURCE:
{
+ DynamicProto.StateInt32Source stateSource = int32Source.getStateSource();
node = new StateInt32SourceNode(
- mStateStore, int32Source.getStateSource(), consumer);
+ stateSource.getSourceNamespace().isEmpty()
+ ? mStateStore : mPlatformDataStore,
+ stateSource,
+ consumer);
break;
}
case CONDITIONAL_OP:
@@ -838,9 +841,15 @@
node = new FixedFloatNode(floatSource.getFixed(), consumer);
break;
case STATE_SOURCE:
- node = new StateFloatSourceNode(
- mStateStore, floatSource.getStateSource(), consumer);
- break;
+ {
+ DynamicProto.StateFloatSource stateSource = floatSource.getStateSource();
+ node = new StateFloatSourceNode(
+ stateSource.getSourceNamespace().isEmpty()
+ ? mStateStore : mPlatformDataStore,
+ stateSource,
+ consumer);
+ break;
+ }
case ARITHMETIC_OPERATION:
{
ArithmeticFloatNode arithmeticNode =
@@ -938,8 +947,12 @@
node = new FixedColorNode(colorSource.getFixed(), consumer);
break;
case STATE_SOURCE:
+ DynamicProto.StateColorSource stateSource = colorSource.getStateSource();
node = new StateColorSourceNode(
- mStateStore, colorSource.getStateSource(), consumer);
+ stateSource.getSourceNamespace().isEmpty()
+ ? mStateStore : mPlatformDataStore,
+ stateSource,
+ consumer);
break;
case ANIMATABLE_FIXED:
// We don't have to check if enableAnimations is true, because if it's false and
@@ -1007,8 +1020,15 @@
node = new FixedBoolNode(boolSource.getFixed(), consumer);
break;
case STATE_SOURCE:
- node = new StateBoolNode(mStateStore, boolSource.getStateSource(), consumer);
- break;
+ {
+ DynamicProto.StateBoolSource stateSource = boolSource.getStateSource();
+ node = new StateBoolNode(
+ stateSource.getSourceNamespace().isEmpty()
+ ? mStateStore : mPlatformDataStore,
+ stateSource,
+ consumer);
+ break;
+ }
case INT32_COMPARISON:
{
ComparisonInt32Node compNode =
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/EpochTimePlatformDataSource.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/EpochTimePlatformDataSource.java
index a667d9e..449c6d9 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/EpochTimePlatformDataSource.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/EpochTimePlatformDataSource.java
@@ -16,46 +16,70 @@
package androidx.wear.protolayout.expression.pipeline;
-import androidx.collection.SimpleArrayMap;
-import androidx.wear.protolayout.expression.pipeline.TimeGateway.TimeCallback;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
+import androidx.annotation.VisibleForTesting;
+import androidx.concurrent.futures.CallbackToFutureAdapter;
+
+import com.google.common.util.concurrent.ListenableFuture;
import java.time.Instant;
-import java.util.concurrent.Executor;
+import java.util.ArrayList;
+import java.util.List;
/** Utility for time data source. */
class EpochTimePlatformDataSource {
- private final Executor mUiExecutor;
- private final TimeGateway mGateway;
- private final SimpleArrayMap<
- DynamicTypeValueReceiverWithPreUpdate<Instant>, TimeCallback>
- mConsumerToTimeCallback = new SimpleArrayMap<>();
+ @NonNull private final MainThreadExecutor mExecutor = new MainThreadExecutor();
- EpochTimePlatformDataSource(Executor uiExecutor, TimeGateway gateway) {
- mUiExecutor = uiExecutor;
- mGateway = gateway;
+ @NonNull final List<DynamicTypeValueReceiverWithPreUpdate<Instant>> mConsumerToTimeCallback =
+ new ArrayList<>();
+ @Nullable private final PlatformTimeUpdateNotifier mUpdateNotifier;
+
+ EpochTimePlatformDataSource(
+ @Nullable PlatformTimeUpdateNotifier platformTimeUpdateNotifier) {
+ this.mUpdateNotifier = platformTimeUpdateNotifier;
}
- public void registerForData(DynamicTypeValueReceiverWithPreUpdate<Instant> consumer) {
- TimeCallback timeCallback =
- new TimeCallback() {
- @Override
- public void onPreUpdate() {
- consumer.onPreUpdate();
- }
-
- @Override
- public void onData() {
- consumer.onData(Instant.now());
- }
- };
- mGateway.registerForUpdates(mUiExecutor, timeCallback);
- mConsumerToTimeCallback.put(consumer, timeCallback);
- }
-
- public void unregisterForData(DynamicTypeValueReceiverWithPreUpdate<Instant> consumer) {
- TimeCallback timeCallback = mConsumerToTimeCallback.remove(consumer);
- if (timeCallback != null) {
- mGateway.unregisterForUpdates(timeCallback);
+ @UiThread
+ void registerForData(DynamicTypeValueReceiverWithPreUpdate<Instant> consumer) {
+ if (mConsumerToTimeCallback.isEmpty() && mUpdateNotifier != null) {
+ mUpdateNotifier.setReceiver(this::tick);
}
+ mConsumerToTimeCallback.add(consumer);
+ }
+
+ @UiThread
+ void unregisterForData(DynamicTypeValueReceiverWithPreUpdate<Instant> consumer) {
+ mConsumerToTimeCallback.remove(consumer);
+ if (mConsumerToTimeCallback.isEmpty() && mUpdateNotifier != null) {
+ mUpdateNotifier.clearReceiver();
+ }
+ }
+
+ /**
+ * Updates all registered consumers with the new time.
+ */
+ @SuppressWarnings("NullAway")
+ private ListenableFuture<Void> tick() {
+ return CallbackToFutureAdapter.getFuture(completer -> {
+ mExecutor.execute(() -> {
+ try {
+ mConsumerToTimeCallback.forEach(
+ DynamicTypeValueReceiverWithPreUpdate::onPreUpdate);
+ Instant currentTime = Instant.now();
+ mConsumerToTimeCallback.forEach(c -> c.onData(currentTime));
+ completer.set(null);
+ } catch (RuntimeException e) {
+ completer.setException(e);
+ }
+ });
+ return "EpochTImePlatformDataSource#tick";
+ });
+ }
+
+ @VisibleForTesting
+ int getRegisterConsumersCount() {
+ return mConsumerToTimeCallback.size();
}
}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/FloatNodes.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/FloatNodes.java
index 9ebd1b1..3ca2138 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/FloatNodes.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/FloatNodes.java
@@ -68,11 +68,11 @@
/** Dynamic float node that gets value from the state. */
static class StateFloatSourceNode extends StateSourceNode<Float> {
StateFloatSourceNode(
- StateStore stateStore,
+ DataStore dataStore,
StateFloatSource protoNode,
DynamicTypeValueReceiverWithPreUpdate<Float> downstream) {
super(
- stateStore,
+ dataStore,
StateSourceNode.<DynamicFloat>createKey(
protoNode.getSourceNamespace(), protoNode.getSourceKey()),
se -> se.getFloatVal().getValue(),
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/Int32Nodes.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/Int32Nodes.java
index 75a3c59..077c672 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/Int32Nodes.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/Int32Nodes.java
@@ -78,11 +78,11 @@
static class LegacyPlatformInt32SourceNode extends StateSourceNode<Integer> {
LegacyPlatformInt32SourceNode(
- StateStore stateStore,
+ PlatformDataStore dataStore,
PlatformInt32Source protoNode,
DynamicTypeValueReceiverWithPreUpdate<Integer> downstream) {
super(
- stateStore,
+ dataStore,
getDataKey(protoNode.getSourceType()),
getStateExtractor(protoNode.getSourceType()),
downstream);
@@ -160,11 +160,11 @@
static class StateInt32SourceNode extends StateSourceNode<Integer> {
StateInt32SourceNode(
- StateStore stateStore,
+ DataStore dataStore,
StateInt32Source protoNode,
DynamicTypeValueReceiverWithPreUpdate<Integer> downstream) {
super(
- stateStore,
+ dataStore,
StateSourceNode.<DynamicInt32>createKey(
protoNode.getSourceNamespace(), protoNode.getSourceKey()),
se -> se.getInt32Val().getValue(),
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataProvider.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataProvider.java
index 6380561..51a9ee7 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataProvider.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataProvider.java
@@ -20,29 +20,39 @@
import androidx.wear.protolayout.expression.PlatformDataKey;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.Executor;
/**
* This interface is used by platform data providers to yield dynamic data for their supported data
* keys.
*
- * <p> It's up to the implementations to check if the expression provider has the required
- * permission before sending data with {@link PlatformDataReceiver#onData(Map)} )}. If a required
+ * <p>It's up to the implementations to check if the expression provider has the required
+ * permission before sending data with {@link PlatformDataReceiver#onData(Map)}. If a required
* permission is not granted or is revoked they should stop sending more data and call
- * {@link DynamicTypeValueReceiver#onInvalidated()} instead.
+ * {@link PlatformDataReceiver#onInvalidated(Set)} instead.
*/
public interface PlatformDataProvider {
/**
- * Registers a callback for receiving the platform data from this provider.
+ * Sets the receiver for receiving the platform data from this provider.
*
- * <p> The implementation should periodically send the dynamic data values for the set of
+ * <p>Each provider is expected to have only one receiver. When a receiver has already been
+ * set, the implementation should throw an exception.
+ *
+ * <p>The implementation should periodically send the dynamic data values for the set of
* {@link PlatformDataKey}s specified when registering this {@link PlatformDataProvider} in
* {@link DynamicTypeEvaluator.Config.Builder#addPlatformDataProvider}
+ *
+ * @param executor The executor to run the {@link PlatformDataReceiver#onData(Map)} or
+ * {@link PlatformDataReceiver#onInvalidated(Set)} on.
+ * @param receiver The {@link PlatformDataReceiver} to receive the new dynamic values or to
+ * be notified that the current data has been invalidated for the registered
+ * keys.
*/
- void registerForData(@NonNull Executor executor, @NonNull PlatformDataReceiver callback);
+ void setReceiver(@NonNull Executor executor, @NonNull PlatformDataReceiver receiver);
/**
- * Unregister from the provider.
+ * Clears the receiver from the provider.
*/
- void unregisterForData();
+ void clearReceiver();
}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataReceiver.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataReceiver.java
index f50e2a2..8a9b619 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataReceiver.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataReceiver.java
@@ -27,11 +27,20 @@
* Callback for receiving a PlatformDataProvider's new data.
*/
public interface PlatformDataReceiver {
+
/**
- * Called when the registered data provider is sending new values.
+ * Called by the registered {@ilnk PlatformDataProvider} to send new values.
+ *
+ * @param newData The new values for the registered keys.
*/
void onData(@NonNull Map<PlatformDataKey<?>, DynamicDataValue> newData);
- /** Called when the data provider has an invalid result. */
+ /**
+ * Called by the registered {@ilnk PlatformDataProvider} to notify that the current data has
+ * been invalidated. Typically, this invalidated status is transient and subsequent onData
+ * call can be followed to sent new values.
+ *
+ * @param keys The set of keys with current data been invalidated.
+ */
void onInvalidated(@NonNull Set<PlatformDataKey<?>> keys);
}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStore.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStore.java
new file mode 100644
index 0000000..8c7b1ab
--- /dev/null
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStore.java
@@ -0,0 +1,242 @@
+/*
+ * 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.protolayout.expression.pipeline;
+
+import static java.util.stream.Collectors.toMap;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.UiThread;
+import androidx.collection.ArrayMap;
+import androidx.collection.ArraySet;
+import androidx.wear.protolayout.expression.DynamicDataBuilders;
+import androidx.wear.protolayout.expression.DynamicDataKey;
+import androidx.wear.protolayout.expression.PlatformDataKey;
+import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.Executor;
+
+/**
+ * Platform data storage for ProtoLayout, which also supports sending callback when data items
+ * change.
+ *
+ * <p>Note that this class is **not** thread-safe. Since ProtoLayout inflation currently happens on
+ * the main thread, and because updates will eventually affect the main thread, this whole class
+ * must only be used from the UI thread.
+ */
+final class PlatformDataStore extends DataStore {
+ private static final String TAG = "ProtoLayoutPlatformDataStore";
+
+ private final Executor mUiExecutor;
+
+ @NonNull
+ private final Map<PlatformDataKey<?>, DynamicDataValue> mCurrentPlatformData =
+ new ArrayMap<>();
+
+ @NonNull
+ private final Map<DynamicDataKey<?>,
+ Set<DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue>>>
+ mRegisteredCallbacks = new ArrayMap<>();
+
+ @NonNull
+ private final Map<PlatformDataKey<?>, PlatformDataProvider>
+ mSourceKeyToDataProviders = new ArrayMap<>();
+
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+ PlatformDataStore(
+ @NonNull Map<PlatformDataKey<?>, PlatformDataProvider> sourceKeyToDataProviders) {
+ mSourceKeyToDataProviders.putAll(sourceKeyToDataProviders);
+ mUiExecutor = new MainThreadExecutor();
+ }
+
+ /**
+ * Update the given platform data item.
+ *
+ * <p>Informs registered listeners of changed values.
+ */
+ void updatePlatformDataEntries(
+ @NonNull Map<PlatformDataKey<?>, DynamicDataBuilders.DynamicDataValue> newData) {
+ updatePlatformDataEntriesProto(
+ newData.entrySet().stream().collect(toMap(
+ Map.Entry::getKey, entry -> entry.getValue().toDynamicDataValueProto()))
+ );
+ }
+
+ /**
+ * Update the given platform data item.
+ *
+ * <p>Informs registered listeners of changed values.
+ */
+ void updatePlatformDataEntriesProto(
+ @NonNull Map<PlatformDataKey<?>, DynamicDataValue> newData) {
+ Map<PlatformDataKey<?>, DynamicDataValue> changedEntries = new ArrayMap<>();
+ for (Map.Entry<PlatformDataKey<?>, DynamicDataValue> newEntry : newData.entrySet()) {
+ DynamicDataValue currentEntry = mCurrentPlatformData.get(newEntry.getKey());
+ if (currentEntry == null || !currentEntry.equals(newEntry.getValue())) {
+ changedEntries.put(newEntry.getKey(), newEntry.getValue());
+ }
+ }
+
+ for (Map.Entry<PlatformDataKey<?>, DynamicDataValue> entry : changedEntries.entrySet()) {
+ for (DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback :
+ mRegisteredCallbacks.getOrDefault(entry.getKey(), Collections.emptySet())) {
+ callback.onPreUpdate();
+ }
+ }
+
+ for (Map.Entry<PlatformDataKey<?>, DynamicDataValue> entry : changedEntries.entrySet()) {
+ for (DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback :
+ mRegisteredCallbacks.getOrDefault(entry.getKey(), Collections.emptySet())) {
+ callback.onData(entry.getValue());
+ }
+ mCurrentPlatformData.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Remove the platform data item with the given key.
+ *
+ * <p>Informs registered listeners by invalidating removed values.
+ */
+ void removePlatformDataEntries(@NonNull Set<PlatformDataKey<?>> keys) {
+ for (PlatformDataKey<?> key : keys) {
+ if (mCurrentPlatformData.get(key) != null) {
+ for (DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback :
+ mRegisteredCallbacks.getOrDefault(key, Collections.emptySet())) {
+ callback.onPreUpdate();
+ }
+ }
+ }
+
+ for (PlatformDataKey<?> key : keys) {
+ if (mCurrentPlatformData.get(key) != null) {
+ for (DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback :
+ mRegisteredCallbacks.getOrDefault(key, Collections.emptySet())) {
+ callback.onInvalidated();
+ }
+ mCurrentPlatformData.remove(key);
+ }
+ }
+ }
+
+ /** Gets dynamic value with the given {@code key}. */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @UiThread
+ @Nullable
+ @Override
+ public DynamicDataValue getDynamicDataValuesProto(@NonNull DynamicDataKey<?> key) {
+ return mCurrentPlatformData.get(key);
+ }
+
+ /**
+ * Registers the given callback for updates to the data item for the given {@code key}.
+ *
+ * <p>Note that the callback will be executed on the UI thread.
+ */
+ @UiThread
+ @Override
+ void registerCallback(
+ @NonNull DynamicDataKey<?> key,
+ @NonNull DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback) {
+ if (!(key instanceof PlatformDataKey)) {
+ return;
+ }
+
+ // The key has callback previously, then the provider receiver already set.
+ if (mRegisteredCallbacks.containsKey(key) && !mRegisteredCallbacks.get(key).isEmpty()) {
+ mRegisteredCallbacks.get(key).add(callback);
+ return;
+ }
+
+ PlatformDataProvider platformDataProvider = mSourceKeyToDataProviders.get(key);
+ if (platformDataProvider == null) {
+ Log.w(TAG, String.format("No platform data provider for %s.", key));
+ return;
+ }
+
+ // There is other key from the provider has callback registered, so the provider receiver
+ // already set
+ if (hasRegisteredCallback(platformDataProvider)) {
+ mRegisteredCallbacks.computeIfAbsent(key, k -> new ArraySet<>()).add(callback);
+ return;
+ }
+
+ mRegisteredCallbacks.computeIfAbsent(key, k -> new ArraySet<>()).add(callback);
+ // Set receiver to the provider
+ platformDataProvider.setReceiver(
+ mUiExecutor,
+ new PlatformDataReceiver() {
+ @Override
+ public void onData(
+ @NonNull
+ Map<PlatformDataKey<?>, DynamicDataBuilders.DynamicDataValue>
+ newData) {
+ updatePlatformDataEntries(newData);
+ }
+
+ @Override
+ public void onInvalidated(@NonNull Set<PlatformDataKey<?>> keys) {
+ removePlatformDataEntries(keys);
+ }
+ });
+ }
+
+ /** Unregisters the callback for the given {@code key} from receiving the updates. */
+ @UiThread
+ @Override
+ void unregisterCallback(
+ @NonNull DynamicDataKey<?> key,
+ @NonNull DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback) {
+ Set<DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue>> callbackSet =
+ mRegisteredCallbacks.get(key);
+
+ if (callbackSet == null) {
+ return;
+ }
+
+ callbackSet.remove(callback);
+
+ if (!(key instanceof PlatformDataKey) || !callbackSet.isEmpty()) {
+ return;
+ }
+
+ PlatformDataProvider platformDataProvider = mSourceKeyToDataProviders.get(key);
+ if (platformDataProvider == null) {
+ Log.w(TAG, String.format("No platform data provider for %s", key));
+ return;
+ }
+
+ if (!hasRegisteredCallback(platformDataProvider)) {
+ platformDataProvider.clearReceiver();
+ }
+ }
+
+ // check whether any key from the provider has registered callback
+ private boolean hasRegisteredCallback(PlatformDataProvider provider) {
+ return mSourceKeyToDataProviders.entrySet().stream().anyMatch(
+ entry -> Objects.equals(entry.getValue(), provider)
+ && !mRegisteredCallbacks.getOrDefault(
+ entry.getKey(), Collections.emptySet()).isEmpty());
+ }
+}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformTimeUpdateNotifier.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformTimeUpdateNotifier.java
new file mode 100644
index 0000000..b233647
--- /dev/null
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformTimeUpdateNotifier.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.wear.protolayout.expression.pipeline;
+
+import androidx.annotation.NonNull;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Interface used to notify all time based dynamic types that they should be updated with the new
+ * platform time (system time).
+ *
+ * <p>It's up to the implementations to chose at what frequency updates should be sent.
+ */
+public interface PlatformTimeUpdateNotifier {
+ /**
+ * Sets the callback to be called whenever platform time needs to be reevaluated.
+ *
+ * <p>Calling this method while there is already a receiver set, should replace the previous
+ * receiver.
+ *
+ * @param tick The callback to run whenever platform time needs to be reevaluated. The returned
+ * {@link ListenableFuture} will complete once all of the
+ * {@link DynamicTypeValueReceiver} callbacks triggered by this reevaluation have
+ * been called. This callback should be invoked by the implementation of
+ * this interface whenever platform time needs to be reevaluated.
+ */
+ void setReceiver(@NonNull Callable<ListenableFuture<Void>> tick);
+
+ /**
+ * Clears the receiver from the notifier.
+ */
+ void clearReceiver();
+}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformTimeUpdateNotifierImpl.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformTimeUpdateNotifierImpl.java
new file mode 100644
index 0000000..f6d465e
--- /dev/null
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformTimeUpdateNotifierImpl.java
@@ -0,0 +1,133 @@
+/*
+ * 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.protolayout.expression.pipeline;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Controls notifying for time-related updates using Android's clock. Updates can also be
+ * enabled/disabled.
+ */
+@RestrictTo(Scope.LIBRARY_GROUP)
+public class PlatformTimeUpdateNotifierImpl implements PlatformTimeUpdateNotifier {
+ private static final String TAG = "PlatformTimeUpdateNotifierImpl";
+ private final Handler mUiHandler = new Handler(Looper.getMainLooper());
+ @Nullable private Callable<ListenableFuture<Void>> mRegisteredReceiver;
+ private final Runnable mNotifyAndSchedule = this::notifyAndScheduleNextSecond;
+ private long mLastScheduleTimeMillis = 0;
+ private boolean mUpdatesEnabled = false;
+
+ @Override
+ public void setReceiver(@NonNull Callable<ListenableFuture<Void>> tick) {
+ if (mRegisteredReceiver != null) {
+ Log.w(TAG, "Clearing previously set receiver.");
+ clearReceiver();
+ }
+ mRegisteredReceiver = tick;
+
+ if (mUpdatesEnabled) {
+ // Send first update and schedule next.
+ mLastScheduleTimeMillis = SystemClock.uptimeMillis();
+ scheduleNextSecond();
+ runReceiver();
+ }
+ }
+
+ @Override
+ public void clearReceiver() {
+ mRegisteredReceiver = null;
+
+ // There are no more registered callbacks, stop the periodic call.
+ if (this.mUpdatesEnabled) {
+ mUiHandler.removeCallbacks(this.mNotifyAndSchedule, this);
+ }
+ }
+
+ /** Sets whether this notifier can send updates on the given receiver. */
+ public void setUpdatesEnabled(boolean updatesEnabled) {
+ if (updatesEnabled == this.mUpdatesEnabled) {
+ return;
+ }
+
+ this.mUpdatesEnabled = updatesEnabled;
+
+ if (!updatesEnabled) {
+ mUiHandler.removeCallbacks(this.mNotifyAndSchedule, this);
+ } else if (mRegisteredReceiver != null) {
+ mLastScheduleTimeMillis = SystemClock.uptimeMillis();
+ scheduleNextSecond();
+ }
+ }
+
+
+ @SuppressWarnings("ExecutorTaskName")
+ private void notifyAndScheduleNextSecond() {
+ if (!this.mUpdatesEnabled) {
+ return;
+ }
+
+ if (mRegisteredReceiver != null) {
+ runReceiver();
+ }
+ // Trigger updates.
+ scheduleNextSecond();
+ }
+
+ /** Call {@link Callable#call()} on the registered receiver and handles exception. */
+ private void runReceiver() {
+ if (mRegisteredReceiver == null) {
+ return;
+ }
+
+ try {
+ mRegisteredReceiver.call();
+ } catch (Exception e) {
+ throw new RuntimeException("Attempt to run registered receiver has failed.", e);
+ }
+ }
+
+ private void scheduleNextSecond() {
+ // Set up for the next update.
+ mLastScheduleTimeMillis += 1000;
+
+ // Ensure that the new time is actually in the future. If a call from uiHandler gets
+ // significantly delayed for any reason, then without this, we'll reschedule immediately
+ // (potentially multiple times), compounding the situation further.
+ if (mLastScheduleTimeMillis < SystemClock.uptimeMillis()) {
+ // Skip the failed updates...
+ long missedTime = SystemClock.uptimeMillis() - mLastScheduleTimeMillis;
+
+ // Round up to the nearest second...
+ missedTime = ((missedTime / 1000) + 1) * 1000;
+ mLastScheduleTimeMillis += missedTime;
+ }
+
+ mUiHandler.postAtTime(this.mNotifyAndSchedule, this, mLastScheduleTimeMillis);
+ }
+}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/SensorGatewaySingleDataProvider.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/SensorGatewaySingleDataProvider.java
deleted file mode 100644
index c90fbda..0000000
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/SensorGatewaySingleDataProvider.java
+++ /dev/null
@@ -1,86 +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.protolayout.expression.pipeline;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.RestrictTo.Scope;
-import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
-import androidx.wear.protolayout.expression.PlatformDataKey;
-import androidx.wear.protolayout.expression.PlatformHealthSources;
-import androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.Executor;
-import java.util.function.Function;
-
-/** This provider provides sensor data as state value. */
-@RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
-public class SensorGatewaySingleDataProvider implements PlatformDataProvider {
- @NonNull private final SensorGateway mSensorGateway;
- @NonNull final PlatformDataKey<?> mSupportedKey;
- @Nullable private SensorGateway.Consumer mSensorGatewayConsumer = null;
-
- @NonNull Function<Double, DynamicDataValue> mConvertFunc;
-
- public SensorGatewaySingleDataProvider(
- @NonNull SensorGateway sensorGateway,
- @NonNull PlatformDataKey<?> supportedKey
- ) {
- this.mSensorGateway = sensorGateway;
- this.mSupportedKey = supportedKey;
-
- if (mSupportedKey.equals(PlatformHealthSources.Keys.DAILY_STEPS)) {
- mConvertFunc = value -> DynamicDataValue.fromInt(value.intValue());
- } else {
- mConvertFunc = value -> DynamicDataValue.fromFloat(value.floatValue());
- }
- }
-
- @Override
- @SuppressWarnings("HiddenTypeParameters")
- public void registerForData(
- @NonNull Executor executor, @NonNull PlatformDataReceiver callback) {
- SensorGateway.Consumer sensorConsumer =
- new SensorGateway.Consumer() {
- @Override
- public void onData(double value) {
- executor.execute(() -> callback.onData(
- Map.of(mSupportedKey, mConvertFunc.apply(value)))
- );
- }
-
- @Override
- public void onInvalidated() {
- executor.execute(() -> callback.onInvalidated(
- Collections.singleton(mSupportedKey)));
- }
- };
- mSensorGatewayConsumer = sensorConsumer;
- mSensorGateway.registerSensorGatewayConsumer(mSupportedKey, sensorConsumer);
- }
-
- @Override
- public void unregisterForData() {
- if (mSensorGatewayConsumer != null) {
- mSensorGateway.unregisterSensorGatewayConsumer(mSupportedKey, mSensorGatewayConsumer);
- mSensorGatewayConsumer = null;
- }
- }
-}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateSourceNode.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateSourceNode.java
index ef45da0..9397006 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateSourceNode.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateSourceNode.java
@@ -18,10 +18,10 @@
import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
+import androidx.wear.protolayout.expression.AppDataKey;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicType;
import androidx.wear.protolayout.expression.DynamicDataKey;
import androidx.wear.protolayout.expression.PlatformDataKey;
-import androidx.wear.protolayout.expression.AppDataKey;
import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import java.util.function.Function;
@@ -30,17 +30,17 @@
implements DynamicDataSourceNode<T>,
DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> {
@NonNull private static final String RESERVED_NAMESPACE = "protolayout";
- private final StateStore mStateStore;
+ private final DataStore mDataStore;
private final DynamicDataKey<?> mKey;
private final Function<DynamicDataValue, T> mStateExtractor;
private final DynamicTypeValueReceiverWithPreUpdate<T> mDownstream;
StateSourceNode(
- StateStore stateStore,
+ DataStore dataStore,
DynamicDataKey<?> key,
Function<DynamicDataValue, T> stateExtractor,
DynamicTypeValueReceiverWithPreUpdate<T> downstream) {
- this.mStateStore = stateStore;
+ this.mDataStore = dataStore;
this.mKey = key;
this.mStateExtractor = stateExtractor;
this.mDownstream = downstream;
@@ -55,8 +55,8 @@
@Override
@UiThread
public void init() {
- mStateStore.registerCallback(mKey, this);
- DynamicDataValue item = mStateStore.getDynamicDataValuesProto(mKey);
+ mDataStore.registerCallback(mKey, this);
+ DynamicDataValue item = mDataStore.getDynamicDataValuesProto(mKey);
if (item != null) {
this.onData(item);
@@ -68,7 +68,7 @@
@Override
@UiThread
public void destroy() {
- mStateStore.unregisterCallback(mKey, this);
+ mDataStore.unregisterCallback(mKey, this);
}
@Override
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateStore.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateStore.java
index bf65534..93d2a9c 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateStore.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateStore.java
@@ -19,8 +19,6 @@
import static java.util.stream.Collectors.toMap;
import android.annotation.SuppressLint;
-import android.os.Handler;
-import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -32,13 +30,11 @@
import androidx.wear.protolayout.expression.DynamicDataBuilders;
import androidx.wear.protolayout.expression.DynamicDataKey;
import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
-import androidx.wear.protolayout.expression.PlatformDataKey;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.concurrent.Executor;
import java.util.stream.Stream;
/**
@@ -48,16 +44,13 @@
* the main thread, and because updates will eventually affect the main thread, this whole class
* must only be used from the UI thread.
*/
-public class StateStore {
+public final class StateStore extends DataStore {
@SuppressLint("MinMaxConstant")
private static final int MAX_STATE_ENTRY_COUNT = 30;
- private final Executor mUiExecutor;
- @NonNull private final Map<AppDataKey<?>, DynamicDataValue> mCurrentAppState
- = new ArrayMap<>();
+ private static final String TAG = "ProtoLayoutStateStore";
- @NonNull
- private final Map<PlatformDataKey<?>, DynamicDataValue> mCurrentPlatformData
+ @NonNull private final Map<AppDataKey<?>, DynamicDataValue> mCurrentAppState
= new ArrayMap<>();
@NonNull
@@ -66,14 +59,6 @@
Set<DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue>>>
mRegisteredCallbacks = new ArrayMap<>();
- @NonNull
- private final Map<PlatformDataKey<?>, PlatformDataProvider>
- mSourceKeyToDataProviders = new ArrayMap<>();
-
- @NonNull
- private final Map<PlatformDataProvider, Integer> mProviderToRegisteredKeyCount
- = new ArrayMap<>();
-
/**
* Creates a {@link StateStore}.
*
@@ -94,12 +79,6 @@
throw stateTooLargeException(initialState.size());
}
mCurrentAppState.putAll(initialState);
- mUiExecutor = new MainThreadExecutor(new Handler(Looper.getMainLooper()));
- }
-
- void putAllPlatformProviders(
- @NonNull Map<PlatformDataKey<?>, PlatformDataProvider> sourceKeyToDataProviders) {
- mSourceKeyToDataProviders.putAll(sourceKeyToDataProviders);
}
/**
@@ -166,90 +145,13 @@
}
}
- /**
- * Update the given platform data item.
- *
- * <p>Informs registered listeners of changed values.
- */
- void updatePlatformDataEntries(
- @NonNull Map<PlatformDataKey<?>, DynamicDataBuilders.DynamicDataValue> newData) {
- updatePlatformDataEntryProto(
- newData.entrySet().stream().collect(
- toMap(Entry::getKey, entry -> entry.getValue().toDynamicDataValueProto()))
- );
- }
-
- /**
- * Update the given platform data item.
- *
- * <p>Informs registered listeners of changed values.
- */
- void updatePlatformDataEntryProto(
- @NonNull Map<PlatformDataKey<?>, DynamicDataValue> newData) {
- Map<PlatformDataKey<?>, DynamicDataValue> changedEntries = new ArrayMap<>();
- for (Entry<PlatformDataKey<?>, DynamicDataValue> newEntry : newData.entrySet()) {
- DynamicDataValue currentEntry = mCurrentPlatformData.get(newEntry.getKey());
- if (currentEntry == null || !currentEntry.equals(newEntry.getValue())) {
- changedEntries.put(newEntry.getKey(), newEntry.getValue());
- }
- }
-
- for (Entry<PlatformDataKey<?>, DynamicDataValue> entry : changedEntries.entrySet()) {
- for (DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback :
- mRegisteredCallbacks.getOrDefault(entry.getKey(), Collections.emptySet())) {
- callback.onPreUpdate();
- }
- }
-
- for (Entry<PlatformDataKey<?>, DynamicDataValue> entry : changedEntries.entrySet()) {
- for (DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback :
- mRegisteredCallbacks.getOrDefault(entry.getKey(), Collections.emptySet())) {
- callback.onData(entry.getValue());
- }
- mCurrentPlatformData.put(entry.getKey(), entry.getValue());
- }
- }
-
- /**
- * Remove the platform data item with the given key.
- *
- * <p>Informs registered listeners by invalidating removed values.
- */
- void removePlatformDataEntry(@NonNull Set<PlatformDataKey<?>> keys) {
- for (PlatformDataKey<?> key : keys) {
- if (mCurrentPlatformData.get(key) != null) {
- for (DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback :
- mRegisteredCallbacks.getOrDefault(key, Collections.emptySet())) {
- callback.onPreUpdate();
- }
- }
- }
-
- for (PlatformDataKey<?> key : keys) {
- if (mCurrentPlatformData.get(key) != null) {
- for (DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback :
- mRegisteredCallbacks.getOrDefault(key, Collections.emptySet())) {
- callback.onInvalidated();
- }
- mCurrentPlatformData.remove(key);
- }
- }
- }
-
/** Gets dynamic value with the given {@code key}. */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@UiThread
@Nullable
+ @Override
public DynamicDataValue getDynamicDataValuesProto(@NonNull DynamicDataKey<?> key) {
- if (key instanceof AppDataKey) {
- return mCurrentAppState.get(key);
- }
-
- if (key instanceof PlatformDataKey) {
- return mCurrentPlatformData.get(key);
- }
-
- return null;
+ return mCurrentAppState.get(key);
}
/**
@@ -258,50 +160,16 @@
* <p>Note that the callback will be executed on the UI thread.
*/
@UiThread
+ @Override
void registerCallback(
@NonNull DynamicDataKey<?> key,
@NonNull DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback) {
mRegisteredCallbacks.computeIfAbsent(key, k -> new ArraySet<>()).add(callback);
-
- if (!(key instanceof PlatformDataKey) ||
- (mRegisteredCallbacks.containsKey(key) && mRegisteredCallbacks.get(key).size() > 1)
- ) {
- return;
- }
-
- PlatformDataProvider platformDataProvider = mSourceKeyToDataProviders.get(key);
- if (platformDataProvider != null) {
- int registeredKeyCount =
- mProviderToRegisteredKeyCount.getOrDefault(platformDataProvider, 0);
-
- if (registeredKeyCount == 0) {
- platformDataProvider.registerForData(
- mUiExecutor,
- new PlatformDataReceiver() {
- @Override
- public void onData(
- @NonNull
- Map<PlatformDataKey<?>, DynamicDataBuilders.DynamicDataValue>
- newData) {
- updatePlatformDataEntries(newData);
- }
-
- @Override
- public void onInvalidated(@NonNull Set<PlatformDataKey<?>> keys) {
- removePlatformDataEntry(keys);
- }
- });
- }
-
- mProviderToRegisteredKeyCount.put(platformDataProvider, registeredKeyCount + 1);
- } else {
- throw new IllegalArgumentException(
- String.format("No platform data provider for %s", key));
- }
}
/** Unregisters the callback for the given {@code key} from receiving the updates. */
@UiThread
+ @Override
void unregisterCallback(
@NonNull DynamicDataKey<?> key,
@NonNull DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> callback) {
@@ -310,23 +178,6 @@
mRegisteredCallbacks.get(key);
if (callbackSet != null) {
callbackSet.remove(callback);
-
- if (!(key instanceof PlatformDataKey) || !callbackSet.isEmpty()) {
- return;
- }
-
- PlatformDataProvider platformDataProvider = mSourceKeyToDataProviders.get(key);
- if (platformDataProvider != null) {
- int registeredKeyCount =
- mProviderToRegisteredKeyCount.getOrDefault(platformDataProvider, 0);
- if (registeredKeyCount == 1) {
- platformDataProvider.unregisterForData();
- }
- mProviderToRegisteredKeyCount.put(platformDataProvider, registeredKeyCount - 1);
- } else {
- throw new IllegalArgumentException(
- String.format("No platform data provider for %s", key));
- }
}
}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StringNodes.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StringNodes.java
index 77dcfc4..1978b04 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StringNodes.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StringNodes.java
@@ -100,11 +100,11 @@
/** Dynamic string node that gets a value from the state. */
static class StateStringNode extends StateSourceNode<String> {
StateStringNode(
- StateStore stateStore,
+ DataStore dataStore,
StateStringSource protoNode,
DynamicTypeValueReceiverWithPreUpdate<String> downstream) {
super(
- stateStore,
+ dataStore,
StateSourceNode.<DynamicString>createKey(
protoNode.getSourceNamespace(), protoNode.getSourceKey()),
se -> truncate(se.getStringVal().getValue()),
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/TimeGateway.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/TimeGateway.java
deleted file mode 100644
index d9662d0..0000000
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/TimeGateway.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.
- * 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.protolayout.expression.pipeline;
-
-import androidx.annotation.NonNull;
-
-import java.util.concurrent.Executor;
-
-/**
- * Controls evaluation triggering of time-related expressions.
- *
- * <p>Can be optionally provided to {@link DynamicTypeEvaluator} in order to have fine control of
- * how time-related expressions are triggered for re-evaluation.
- */
-public interface TimeGateway {
- /** Callback for {@link TimeGateway} triggers. */
- interface TimeCallback {
- /**
- * Called just before an update happens. All onPreUpdate calls will be made before any
- * onUpdate calls fire.
- *
- * <p>Will be called on the same executor passed to {@link TimeGateway#registerForUpdates}.
- *
- * <p>It is up to the caller to ensure synchronization between {@link #onPreUpdate()} and
- * {@link #onData()} calls (both called on the {@link Executor} provided to {@link
- * #registerForUpdates}), e.g. by providing a single-threaded ordered {@link Executor}. If
- * not synchronized, it's possible that {@link #onData()} will be invoked before {@link
- * #onPreUpdate()} on the same time tick.
- */
- void onPreUpdate();
-
- /**
- * Notifies that the current time has changed.
- *
- * <p>Will be called on the same executor passed to {@link TimeGateway#registerForUpdates}.
- *
- * <p>It is up to the caller to ensure synchronization between {@link #onPreUpdate()} and
- * {@link #onData()} calls (both called on the {@link Executor} provided to {@link
- * #registerForUpdates}), e.g. by providing a single-threaded ordered {@link Executor}. If
- * not synchronized, it's possible that {@link #onData()} will be invoked before {@link
- * #onPreUpdate()} on the same time tick.
- */
- void onData();
- }
-
- /**
- * Register for time updates. All callbacks will be called on the provided executor.
- *
- * <p>It is up to the caller to ensure synchronization between {@link
- * TimeCallback#onPreUpdate()} and {@link TimeCallback#onData()} calls (both called on the
- * provided {@link Executor}), e.g. by providing a single-threaded ordered {@link Executor}. If
- * not synchronized, it's possible that {@link TimeCallback#onData()} will be invoked before
- * {@link TimeCallback#onPreUpdate()} on the same time tick.
- */
- void registerForUpdates(@NonNull Executor executor, @NonNull TimeCallback callback);
-
- /** Unregister for time updates. */
- void unregisterForUpdates(@NonNull TimeCallback callback);
-}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/TimeGatewayImpl.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/TimeGatewayImpl.java
deleted file mode 100644
index 18bae95..0000000
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/TimeGatewayImpl.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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.
- * 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.protolayout.expression.pipeline;
-
-import android.os.Handler;
-import android.os.SystemClock;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.RestrictTo.Scope;
-import androidx.annotation.UiThread;
-import androidx.collection.ArrayMap;
-
-import java.util.Map;
-import java.util.concurrent.Executor;
-
-/** Default implementation of {@link TimeGateway} using Android's clock. */
-@RestrictTo(Scope.LIBRARY_GROUP)
-public final class TimeGatewayImpl implements TimeGateway, AutoCloseable {
- private final Handler uiHandler;
- private final Map<TimeCallback, Executor> registeredCallbacks = new ArrayMap<>();
- private boolean updatesEnabled = false;
- private final Runnable onTick;
-
- private long lastScheduleTimeMillis = 0;
-
- // Suppress warning on "onTick = this::notifyNextSecond". This happens because notifyNextSecond
- // is @UnderInitialization here, but onTick needs to be @Initialized. This is safe though; the
- // only time that onTick can be invoked is in the other methods on this class, which can only be
- // called after initialization is complete. This class is also final, so those methods cannot be
- // called from a sub-constructor either.
- @SuppressWarnings("methodref.receiver.bound")
- public TimeGatewayImpl(@NonNull Handler uiHandler) {
- this.uiHandler = uiHandler;
-
- this.onTick = this::notifyNextSecond;
- }
-
- /** See {@link TimeGateway#registerForUpdates(Executor, TimeCallback)}. */
- @Override
- public void registerForUpdates(@NonNull Executor executor, @NonNull TimeCallback callback) {
- registeredCallbacks.put(callback, executor);
-
- // If this was the first registration, _and_ we're enabled, then schedule the message on the
- // Handler (otherwise, another call has already scheduled the call).
- if (registeredCallbacks.size() == 1 && this.updatesEnabled) {
- lastScheduleTimeMillis = SystemClock.uptimeMillis() + 1000;
- uiHandler.postAtTime(this.onTick, this, lastScheduleTimeMillis);
- }
-
- // Send first update to initialize clients that are using this TimeGateway
- if (updatesEnabled) {
- callback.onPreUpdate();
- callback.onData();
- }
- }
-
- /** See {@link TimeGateway#unregisterForUpdates(TimeCallback)}. */
- @Override
- public void unregisterForUpdates(@NonNull TimeCallback callback) {
- registeredCallbacks.remove(callback);
-
- // If there are no more registered callbacks, stop the periodic call.
- if (registeredCallbacks.isEmpty() && this.updatesEnabled) {
- uiHandler.removeCallbacks(this.onTick, this);
- }
- }
-
- @UiThread
- public void enableUpdates() {
- setUpdatesEnabled(true);
- }
-
- @UiThread
- public void disableUpdates() {
- setUpdatesEnabled(false);
- }
-
- private void setUpdatesEnabled(boolean updatesEnabled) {
- if (updatesEnabled == this.updatesEnabled) {
- return;
- }
-
- this.updatesEnabled = updatesEnabled;
-
- if (!updatesEnabled) {
- uiHandler.removeCallbacks(this.onTick, this);
- } else if (!registeredCallbacks.isEmpty()) {
- lastScheduleTimeMillis = SystemClock.uptimeMillis() + 1000;
-
- uiHandler.postAtTime(this.onTick, this, lastScheduleTimeMillis);
- }
- }
-
- @SuppressWarnings("ExecutorTaskName")
- private void notifyNextSecond() {
- if (!this.updatesEnabled) {
- return;
- }
-
- for (Map.Entry<TimeCallback, Executor> callback : registeredCallbacks.entrySet()) {
- callback.getValue().execute(callback.getKey()::onPreUpdate);
- }
-
- for (Map.Entry<TimeCallback, Executor> callback : registeredCallbacks.entrySet()) {
- callback.getValue().execute(callback.getKey()::onData);
- }
-
- lastScheduleTimeMillis += 1000;
-
- // Ensure that the new time is actually in the future. If a call from uiHandler gets
- // significantly delayed for any reason, then without this, we'll reschedule immediately
- // (potentially multiple times), compounding the situation further.
- if (lastScheduleTimeMillis < SystemClock.uptimeMillis()) {
- // Skip the failed updates...
- long missedTime = SystemClock.uptimeMillis() - lastScheduleTimeMillis;
-
- // Round up to the nearest second...
- missedTime = ((missedTime / 1000) + 1) * 1000;
- lastScheduleTimeMillis += missedTime;
- }
-
- uiHandler.postAtTime(this.onTick, this, lastScheduleTimeMillis);
- }
-
- @Override
- @UiThread
- public void close() {
- setUpdatesEnabled(false);
- registeredCallbacks.clear();
- }
-}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/sensor/SensorGateway.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/sensor/SensorGateway.java
deleted file mode 100644
index b6eef40..0000000
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/sensor/SensorGateway.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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.
- * 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.protolayout.expression.pipeline.sensor;
-
-import androidx.annotation.AnyThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.RestrictTo.Scope;
-import androidx.annotation.UiThread;
-import androidx.wear.protolayout.expression.DynamicBuilders;
-import androidx.wear.protolayout.expression.PlatformDataKey;
-import androidx.wear.protolayout.expression.PlatformHealthSources;
-
-import java.util.concurrent.Executor;
-
-/**
- * Gateway for proto layout expression library to be able to access sensor data, e.g. health data.
- */
-@RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
-public interface SensorGateway {
-
- /**
- * Consumer for sensor data.
- *
- * <p>If Consumer is relying on multiple sources or upstream nodes, it should be responsible for
- * data coordination between pending updates and received data.
- *
- * <p>For example, this Consumer listens to two upstream sources:
- *
- * <pre>{@code
- * class MyConsumer implements Consumer {
- * int pending = 0;
- *
- * @Override
- * public void onPreUpdate(){
- * pending++;
- * }
- *
- * @Override
- * public void onData(double value){
- * // store the value internally
- * pending--;
- * if (pending == 0) {
- * // We've received data from every changed upstream source
- * consumeTheChangedDataValues()
- * }
- * }
- * }
- * }</pre>
- */
- interface Consumer {
- /**
- * Called when a new batch of data has arrived. The actual data will be delivered in {@link
- * #onData(double)} after this method is called on all registered consumers.
- */
- @AnyThread
- default void onPreUpdate() {}
-
- /**
- * Called when a new data for the requested data type is received. This will be run on a
- * single background thread.
- *
- * <p>Note that there is no notification when a daily sensor data item resets to zero; this
- * will simply emit an item of sensor data with value 0.0 when the rollover happens.
- */
- @AnyThread
- void onData(double value);
-
- /**
- * Notify that the current data for the registered data type has been invalidated. This
- * could be, for example, that the current heart rate is no longer valid as the user is not
- * wearing the device.
- */
- @AnyThread
- default void onInvalidated() {}
- }
-
- /**
- * Enables/unpauses sending updates to the consumers. All cached updates (while updates were
- * paused) for data types will be delivered by sending the latest data.
- */
- @RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
- void enableUpdates();
-
- /**
- * Disables/pauses sending updates to the consumers. While paused, updates will be cached to be
- * delivered after unpausing.
- */
- @RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
- void disableUpdates();
-
- /**
- * Register for updates for the given data type. This may cause {@link Consumer} to immediately
- * fire if there is suitable cached data, otherwise {@link Consumer} will fire when there is
- * appropriate updates to the requested sensor data.
- *
- * <p>Implementations should check if the provider has permission to provide the requested data
- * type.
- *
- * <p>Note that the callback will be executed on the single background thread (implementation
- * dependent). To specify the execution thread, use {@link #registerSensorGatewayConsumer(
- * PlatformDataKey, Executor, Consumer)}.
- *
- * @throws SecurityException if the provider does not have permission to provide requested data
- * type.
- */
- @UiThread
- void registerSensorGatewayConsumer(
- @NonNull PlatformDataKey<?> key, @NonNull Consumer consumer);
-
- /**
- * Register for updates for the given data type. This may cause {@link Consumer} to immediately
- * fire if there is suitable cached data, otherwise {@link Consumer} will fire when there is
- * appropriate updates to the requested sensor data.
- *
- * <p>Implementations should check if the provider has permission to provide the requested data
- * type.
- *
- * <p>The callback will be executed on the provided {@link Executor}.
- *
- * @throws SecurityException if the provider does not have permission to provide requested data
- * type.
- */
- @UiThread
- void registerSensorGatewayConsumer(
- @NonNull PlatformDataKey<?> key,
- @NonNull /* @CallbackExecutor */ Executor executor,
- @NonNull Consumer consumer);
-
- /** Unregister for updates for the given data type. */
- @UiThread
- void unregisterSensorGatewayConsumer(
- @NonNull PlatformDataKey<?> key, @NonNull Consumer consumer);
-}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/AnimatableNodeTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/AnimatableNodeTest.java
index 7bd0f02..5b50fe9 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/AnimatableNodeTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/AnimatableNodeTest.java
@@ -17,6 +17,7 @@
package androidx.wear.protolayout.expression.pipeline;
import static com.google.common.truth.Truth.assertThat;
+
import static org.robolectric.Shadows.shadowOf;
import android.animation.TypeEvaluator;
@@ -33,13 +34,13 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Range;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
@RunWith(AndroidJUnit4.class)
public class AnimatableNodeTest {
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/BoolNodesTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/BoolNodesTest.java
index bf04b5e..00591df 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/BoolNodesTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/BoolNodesTest.java
@@ -20,6 +20,7 @@
import static androidx.wear.protolayout.expression.proto.DynamicProto.LogicalOpType.LOGICAL_OP_TYPE_EQUAL;
import static androidx.wear.protolayout.expression.proto.DynamicProto.LogicalOpType.LOGICAL_OP_TYPE_NOT_EQUAL;
import static androidx.wear.protolayout.expression.proto.DynamicProto.LogicalOpType.LOGICAL_OP_TYPE_OR;
+
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -27,17 +28,20 @@
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool;
import androidx.wear.protolayout.expression.pipeline.BoolNodes.FixedBoolNode;
import androidx.wear.protolayout.expression.pipeline.BoolNodes.StateBoolNode;
+import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import androidx.wear.protolayout.expression.proto.DynamicProto;
import androidx.wear.protolayout.expression.proto.DynamicProto.LogicalBoolOp;
import androidx.wear.protolayout.expression.proto.DynamicProto.StateBoolSource;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedBool;
-import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
+
import com.google.common.collect.ImmutableMap;
-import java.util.ArrayList;
-import java.util.List;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(AndroidJUnit4.class)
public class BoolNodesTest {
@Test
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/ColorNodesTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/ColorNodesTest.java
index cbf06ed..b0a1d3b 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/ColorNodesTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/ColorNodesTest.java
@@ -25,17 +25,17 @@
import android.os.Looper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor;
import androidx.wear.protolayout.expression.AppDataKey;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor;
import androidx.wear.protolayout.expression.pipeline.ColorNodes.AnimatableFixedColorNode;
import androidx.wear.protolayout.expression.pipeline.ColorNodes.DynamicAnimatedColorNode;
import androidx.wear.protolayout.expression.pipeline.ColorNodes.FixedColorNode;
import androidx.wear.protolayout.expression.pipeline.ColorNodes.StateColorSourceNode;
import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationSpec;
+import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableFixedColor;
import androidx.wear.protolayout.expression.proto.DynamicProto.StateColorSource;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedColor;
-import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java
index 67b1243..dd3b228 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java
@@ -18,19 +18,33 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static java.lang.Integer.MAX_VALUE;
+import android.icu.util.ULocale;
+
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.wear.protolayout.expression.DynamicBuilders;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool;
+import androidx.wear.protolayout.expression.PlatformDataKey;
+import androidx.wear.protolayout.expression.PlatformHealthSources;
import androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.EvaluationException;
+import com.google.common.util.concurrent.ListenableFuture;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.time.Instant;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.concurrent.Callable;
@RunWith(AndroidJUnit4.class)
public class DynamicTypeEvaluatorTest {
@@ -55,6 +69,36 @@
}
@Test
+ public void timeDataGetsPropagated() throws Exception {
+ TestPlatformTimeUpdateNotifier notifier = new TestPlatformTimeUpdateNotifier();
+ DynamicTypeEvaluator evaluator = createEvaluatorWithTime(notifier);
+ ArrayList<String> results = new ArrayList<>();
+ DynamicTypeBindingRequest request =
+ createSingleNodeDynamicStringFromTimePlatformRequest(results);
+ BoundDynamicType boundDynamicType = evaluator.bind(request);
+
+ // Evaluation hasn't started yet, nothing should be called.
+ ListenableFuture<Void> resultFuture = notifier.callReceiver();
+ assertThat(resultFuture).isNull();
+ assertThat(results).isEmpty();
+
+ // Start evaluation.
+ boundDynamicType.startEvaluation();
+
+ // Trigger reevaluation, which should send a result.
+ for (int i = 0; i < 5; i++) {
+ resultFuture = notifier.callReceiver();
+ assertThat(resultFuture).isNotNull();
+ assertThat(resultFuture.isDone()).isTrue();
+ assertThat(results).hasSize(i + 1);
+ assertThat(Integer.parseInt(results.get(i))).isAtLeast(0);
+ assertThat(Integer.parseInt(results.get(i))).isLessThan(60);
+ }
+
+ boundDynamicType.close();
+ }
+
+ @Test
public void evaluateBindingRequest_insufficientDynamicNodeQuota_canRetryAfterQuotaReleased()
throws EvaluationException {
DynamicTypeEvaluator evaluator =
@@ -74,6 +118,26 @@
assertThat(boundDynamicType2.getDynamicNodeCount()).isEqualTo(1);
}
+ @Test
+ public void platformDataProvider_correctlySet() throws EvaluationException {
+ AddToListCallback<Integer> results = new AddToListCallback<>(new ArrayList<>());
+ DynamicTypeBindingRequest request =
+ DynamicTypeBindingRequest.forDynamicInt32(
+ PlatformHealthSources.dailySteps(),
+ new MainThreadExecutor(), results);
+ PlatformDataProvider provider = mock(PlatformDataProvider.class);
+ DynamicTypeEvaluator evaluator = createEvaluatorWithProvider(provider,
+ PlatformHealthSources.Keys.DAILY_STEPS);
+
+ BoundDynamicType boundDynamicType = evaluator.bind(request);
+ boundDynamicType.startEvaluation();
+
+ verify(provider).setReceiver(any(), any());
+
+ boundDynamicType.close();
+ verify(provider).clearReceiver();
+ }
+
@NonNull
private static DynamicTypeBindingRequest createSingleNodeDynamicBoolRequest(
ArrayList<Boolean> results) {
@@ -83,10 +147,42 @@
new AddToListCallback<>(results));
}
+ @NonNull
+ private static DynamicTypeBindingRequest createSingleNodeDynamicStringFromTimePlatformRequest(
+ ArrayList<String> results) {
+ return DynamicTypeBindingRequest.forDynamicString(
+ DynamicBuilders.DynamicInstant.platformTimeWithSecondsPrecision().durationUntil(
+ DynamicBuilders.DynamicInstant
+ .withSecondsPrecision(Instant.now())).getSecondsPart().format(),
+ ULocale.ENGLISH,
+ new MainThreadExecutor(),
+ new AddToListCallback<>(results));
+ }
+
private static DynamicTypeEvaluator createEvaluator() {
return createEvaluatorWithQuota(unlimitedQuota(), unlimitedQuota());
}
+ private static DynamicTypeEvaluator createEvaluatorWithProvider(PlatformDataProvider provider
+ , PlatformDataKey<?> key) {
+ return new DynamicTypeEvaluator(
+ new DynamicTypeEvaluator.Config.Builder()
+ .setAnimationQuotaManager(unlimitedQuota())
+ .setDynamicTypesQuotaManager(unlimitedQuota())
+ .addPlatformDataProvider(provider, Collections.singleton(key))
+ .build());
+ }
+
+ private static DynamicTypeEvaluator createEvaluatorWithTime(
+ PlatformTimeUpdateNotifier notifier) {
+ return new DynamicTypeEvaluator(
+ new DynamicTypeEvaluator.Config.Builder()
+ .setAnimationQuotaManager(unlimitedQuota())
+ .setDynamicTypesQuotaManager(unlimitedQuota())
+ .setPlatformTimeUpdateNotifier(notifier)
+ .build());
+ }
+
private static DynamicTypeEvaluator createEvaluatorWithQuota(
QuotaManager animationQuota, QuotaManager dynamicTypesQuota) {
StateStore stateStore = new StateStore(new HashMap<>());
@@ -105,4 +201,31 @@
private static QuotaManager noQuota() {
return new FixedQuotaManagerImpl(0);
}
+
+ private static final class TestPlatformTimeUpdateNotifier
+ extends PlatformTimeUpdateNotifierImpl {
+ private Callable<ListenableFuture<Void>> mRegisteredReceiver;
+
+ @Nullable
+ ListenableFuture<Void> callReceiver() throws Exception {
+ if (mRegisteredReceiver != null) {
+ return mRegisteredReceiver.call();
+ }
+ return null;
+ }
+
+ @Override
+ public void setReceiver(@NonNull Callable<ListenableFuture<Void>> tick) {
+ super.setReceiver(tick);
+
+ mRegisteredReceiver = tick;
+ }
+
+ @Override
+ public void clearReceiver() {
+ super.clearReceiver();
+
+ mRegisteredReceiver = null;
+ }
+ }
}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/FakeSensorGateway.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/FakeSensorGateway.java
deleted file mode 100644
index c661e3f..0000000
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/FakeSensorGateway.java
+++ /dev/null
@@ -1,57 +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.protolayout.expression.pipeline;
-
-import androidx.annotation.NonNull;
-import androidx.wear.protolayout.expression.PlatformDataKey;
-import androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-class FakeSensorGateway implements SensorGateway {
- final List<Consumer> registeredConsumers = new ArrayList<>();
-
- @Override
- public void enableUpdates() {
- }
-
- @Override
- public void disableUpdates() {
- }
-
- @Override
- public void registerSensorGatewayConsumer(
- @NonNull PlatformDataKey<?> key, @NonNull Consumer consumer) {
- registeredConsumers.add(consumer);
- }
-
- @Override
- public void registerSensorGatewayConsumer(
- @NonNull PlatformDataKey<?> key,
- @NonNull Executor executor,
- @NonNull Consumer consumer) {
- registerSensorGatewayConsumer(key, consumer);
- }
-
- @Override
- public void unregisterSensorGatewayConsumer(
- @NonNull PlatformDataKey<?> key, @NonNull Consumer consumer) {
- registeredConsumers.remove(consumer);
- }
-}
\ No newline at end of file
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/FloatNodeTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/FloatNodeTest.java
index 1f82ec7..0962e77 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/FloatNodeTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/FloatNodeTest.java
@@ -16,19 +16,22 @@
package androidx.wear.protolayout.expression.pipeline;
+import static androidx.wear.protolayout.expression.PlatformHealthSources.Keys.HEART_RATE_BPM;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
import static org.robolectric.Shadows.shadowOf;
import static java.lang.Integer.MAX_VALUE;
import android.os.Looper;
-import androidx.collection.ArrayMap;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat;
import androidx.wear.protolayout.expression.AppDataKey;
-import androidx.wear.protolayout.expression.PlatformHealthSources;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat;
+import androidx.wear.protolayout.expression.DynamicDataBuilders;
import androidx.wear.protolayout.expression.pipeline.FloatNodes.AnimatableFixedFloatNode;
import androidx.wear.protolayout.expression.pipeline.FloatNodes.ArithmeticFloatNode;
import androidx.wear.protolayout.expression.pipeline.FloatNodes.DynamicAnimatedFloatNode;
@@ -37,6 +40,7 @@
import androidx.wear.protolayout.expression.pipeline.FloatNodes.StateFloatSourceNode;
import androidx.wear.protolayout.expression.pipeline.Int32Nodes.StateInt32SourceNode;
import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationSpec;
+import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableFixedFloat;
import androidx.wear.protolayout.expression.proto.DynamicProto.ArithmeticFloatOp;
import androidx.wear.protolayout.expression.proto.DynamicProto.ArithmeticOpType;
@@ -44,13 +48,17 @@
import androidx.wear.protolayout.expression.proto.DynamicProto.StateInt32Source;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedFloat;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedInt32;
-import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.Collections;
@@ -58,9 +66,10 @@
@RunWith(AndroidJUnit4.class)
public class FloatNodeTest {
-
private static final AppDataKey<DynamicFloat> KEY_FOO = new AppDataKey<>("foo");
-
+ @Rule
+ public MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Mock private PlatformDataProvider mMockDataProvider;
@Test
public void fixedFloatNodesTest() {
List<Float> results = new ArrayList<>();
@@ -131,35 +140,39 @@
@Test
public void stateFloatSource_canSubscribeToHeartRateUpdates() {
- FakeSensorGateway fakeSensorGateway = new FakeSensorGateway();
- StateStore stateStore = new StateStore(new ArrayMap<>());
- stateStore.putAllPlatformProviders(
+ PlatformDataStore platformDataStore = new PlatformDataStore(
Collections.singletonMap(
- PlatformHealthSources.Keys.HEART_RATE_BPM,
- new SensorGatewaySingleDataProvider(
- fakeSensorGateway, PlatformHealthSources.Keys.HEART_RATE_BPM)));
+ HEART_RATE_BPM,
+ mMockDataProvider));
StateFloatSource dailyStepsSource =
StateFloatSource.newBuilder()
- .setSourceKey(PlatformHealthSources.Keys.HEART_RATE_BPM.getKey())
+ .setSourceKey(HEART_RATE_BPM.getKey())
.setSourceNamespace(
- PlatformHealthSources.Keys.HEART_RATE_BPM.getNamespace())
+ HEART_RATE_BPM.getNamespace())
.build();
List<Float> results = new ArrayList<>();
StateFloatSourceNode dailyStepsSourceNode =
new StateFloatSourceNode(
- stateStore,
+ platformDataStore,
dailyStepsSource,
new AddToListCallback<>(results));
dailyStepsSourceNode.preInit();
dailyStepsSourceNode.init();
- assertThat(fakeSensorGateway.registeredConsumers).hasSize(1);
+ ArgumentCaptor<PlatformDataReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(PlatformDataReceiver.class);
+ verify(mMockDataProvider).setReceiver(any(), receiverCaptor.capture());
- fakeSensorGateway.registeredConsumers.get(0).onData(70.0);
+ PlatformDataReceiver receiver = receiverCaptor.getValue();
+ receiver.onData(ImmutableMap.of(HEART_RATE_BPM,
+ DynamicDataBuilders.DynamicDataValue.fromFloat(70.0f)));
+
assertThat(results).hasSize(1);
assertThat(results).containsExactly(70.0f);
- fakeSensorGateway.registeredConsumers.get(0).onData(80.0);
+ receiver.onData(ImmutableMap.of(HEART_RATE_BPM,
+ DynamicDataBuilders.DynamicDataValue.fromFloat(80.0f)));
+
assertThat(results).hasSize(2);
assertThat(results).containsExactly(70.0f, 80.0f);
}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/InstantNodesTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/InstantNodesTest.java
index 5c4d32d..4a53b5e 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/InstantNodesTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/InstantNodesTest.java
@@ -16,12 +16,10 @@
package androidx.wear.protolayout.expression.pipeline;
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-
import static com.google.common.truth.Truth.assertThat;
-import androidx.annotation.NonNull;
-import androidx.core.content.ContextCompat;
+import static org.mockito.Mockito.mock;
+
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.wear.protolayout.expression.pipeline.InstantNodes.FixedInstantNode;
import androidx.wear.protolayout.expression.pipeline.InstantNodes.PlatformTimeSourceNode;
@@ -32,10 +30,7 @@
import java.time.Instant;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Executor;
@RunWith(AndroidJUnit4.class)
public class InstantNodesTest {
@@ -55,38 +50,17 @@
@Test
public void testPlatformTimeSourceNodeDestroy() {
- FakeTimeGateway fakeTimeGateway = new FakeTimeGateway();
EpochTimePlatformDataSource timeSource =
- new EpochTimePlatformDataSource(
- ContextCompat.getMainExecutor(getApplicationContext()), fakeTimeGateway);
+ new EpochTimePlatformDataSource(mock(PlatformTimeUpdateNotifier.class));
List<Instant> results = new ArrayList<>();
PlatformTimeSourceNode node =
new PlatformTimeSourceNode(timeSource, new AddToListCallback<>(results));
node.preInit();
node.init();
- assertThat(fakeTimeGateway.getNumRegisteredCallbacks()).isEqualTo(1);
+ assertThat(timeSource.getRegisterConsumersCount()).isEqualTo(1);
node.destroy();
- assertThat(fakeTimeGateway.getNumRegisteredCallbacks()).isEqualTo(0);
- }
-
- private static class FakeTimeGateway implements TimeGateway {
- private final Set<TimeCallback> mRegisteredCallbacks = new HashSet<>();
-
- @Override
- public void registerForUpdates(
- @NonNull Executor executor, @NonNull TimeGateway.TimeCallback callback) {
- mRegisteredCallbacks.add(callback);
- }
-
- @Override
- public void unregisterForUpdates(@NonNull TimeGateway.TimeCallback callback) {
- mRegisteredCallbacks.remove(callback);
- }
-
- public int getNumRegisteredCallbacks() {
- return mRegisteredCallbacks.size();
- }
+ assertThat(timeSource.getRegisterConsumersCount()).isEqualTo(0);
}
}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/Int32NodesTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/Int32NodesTest.java
index 5b223d7..c3a90ce 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/Int32NodesTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/Int32NodesTest.java
@@ -16,8 +16,12 @@
package androidx.wear.protolayout.expression.pipeline;
+import static androidx.wear.protolayout.expression.PlatformHealthSources.Keys.DAILY_STEPS;
+import static androidx.wear.protolayout.expression.PlatformHealthSources.Keys.HEART_RATE_BPM;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.robolectric.Shadows.shadowOf;
@@ -25,10 +29,10 @@
import android.os.Looper;
-import androidx.collection.ArrayMap;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.wear.protolayout.expression.AppDataKey;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32;
+import androidx.wear.protolayout.expression.DynamicDataBuilders;
import androidx.wear.protolayout.expression.PlatformHealthSources;
import androidx.wear.protolayout.expression.pipeline.Int32Nodes.AnimatableFixedInt32Node;
import androidx.wear.protolayout.expression.pipeline.Int32Nodes.DynamicAnimatedInt32Node;
@@ -47,11 +51,13 @@
import androidx.wear.protolayout.expression.proto.FixedProto.FixedInt32;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -68,6 +74,8 @@
@Mock
private DynamicTypeValueReceiverWithPreUpdate<Integer> mMockValueReceiver;
+ @Mock
+ private PlatformDataProvider mMockDataProvider;
private static final AppDataKey<DynamicInt32> KEY_FOO = new AppDataKey<>("foo");
@@ -227,13 +235,10 @@
@Test
public void stateInt32Source_canSubscribeToDailyStepsUpdates() {
- FakeSensorGateway fakeSensorGateway = new FakeSensorGateway();
- StateStore stateStore = new StateStore(new ArrayMap<>());
- stateStore.putAllPlatformProviders(
+ PlatformDataStore platformDataStore = new PlatformDataStore(
Collections.singletonMap(
PlatformHealthSources.Keys.DAILY_STEPS,
- new SensorGatewaySingleDataProvider(
- fakeSensorGateway, PlatformHealthSources.Keys.DAILY_STEPS)));
+ mMockDataProvider));
StateInt32Source dailyStepsSource =
StateInt32Source.newBuilder()
.setSourceKey(PlatformHealthSources.Keys.DAILY_STEPS.getKey())
@@ -242,19 +247,24 @@
List<Integer> results = new ArrayList<>();
StateInt32SourceNode dailyStepsSourceNode =
new StateInt32SourceNode(
- stateStore,
+ platformDataStore,
dailyStepsSource,
new AddToListCallback<>(results));
dailyStepsSourceNode.preInit();
dailyStepsSourceNode.init();
- assertThat(fakeSensorGateway.registeredConsumers).hasSize(1);
+ ArgumentCaptor<PlatformDataReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(PlatformDataReceiver.class);
+ verify(mMockDataProvider).setReceiver(any(), receiverCaptor.capture());
- fakeSensorGateway.registeredConsumers.get(0).onData(70);
+ PlatformDataReceiver receiver = receiverCaptor.getValue();
+ receiver.onData(ImmutableMap.of(DAILY_STEPS,
+ DynamicDataBuilders.DynamicDataValue.fromInt(70)));
assertThat(results).hasSize(1);
assertThat(results).containsExactly(70);
- fakeSensorGateway.registeredConsumers.get(0).onData(80);
+ receiver.onData(ImmutableMap.of(DAILY_STEPS,
+ DynamicDataBuilders.DynamicDataValue.fromInt(80)));
assertThat(results).hasSize(2);
assertThat(results).containsExactly(70, 80);
}
@@ -394,13 +404,10 @@
@Test
public void platformInt32Source_canSubscribeToHeartRateUpdates() {
- FakeSensorGateway fakeSensorGateway = new FakeSensorGateway();
- StateStore stateStore = new StateStore(new ArrayMap<>());
- stateStore.putAllPlatformProviders(
+ PlatformDataStore platformDataStore = new PlatformDataStore(
Collections.singletonMap(
PlatformHealthSources.Keys.HEART_RATE_BPM,
- new SensorGatewaySingleDataProvider(
- fakeSensorGateway, PlatformHealthSources.Keys.HEART_RATE_BPM)));
+ mMockDataProvider));
PlatformInt32Source platformSource =
PlatformInt32Source.newBuilder()
.setSourceType(
@@ -410,32 +417,36 @@
List<Integer> results = new ArrayList<>();
LegacyPlatformInt32SourceNode platformSourceNode =
new LegacyPlatformInt32SourceNode(
- stateStore,
+ platformDataStore,
platformSource,
new AddToListCallback<>(results));
platformSourceNode.preInit();
platformSourceNode.init();
- assertThat(fakeSensorGateway.registeredConsumers).hasSize(1);
+ ArgumentCaptor<PlatformDataReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(PlatformDataReceiver.class);
+ verify(mMockDataProvider).setReceiver(any(), receiverCaptor.capture());
- fakeSensorGateway.registeredConsumers.get(0).onData(70);
+ PlatformDataReceiver receiver = receiverCaptor.getValue();
+ receiver.onData(ImmutableMap.of(HEART_RATE_BPM,
+ DynamicDataBuilders.DynamicDataValue.fromFloat(70.0f)));
+
assertThat(results).hasSize(1);
assertThat(results).containsExactly(70);
- fakeSensorGateway.registeredConsumers.get(0).onData(80);
+ receiver.onData(ImmutableMap.of(HEART_RATE_BPM,
+ DynamicDataBuilders.DynamicDataValue.fromFloat(80.0f)));
+
assertThat(results).hasSize(2);
assertThat(results).containsExactly(70, 80);
}
@Test
public void platformInt32Source_canSubscribeToDailyStepsUpdates() {
- FakeSensorGateway fakeSensorGateway = new FakeSensorGateway();
- StateStore stateStore = new StateStore(new ArrayMap<>());
- stateStore.putAllPlatformProviders(
+ PlatformDataStore platformDataStore = new PlatformDataStore(
Collections.singletonMap(
PlatformHealthSources.Keys.DAILY_STEPS,
- new SensorGatewaySingleDataProvider(
- fakeSensorGateway, PlatformHealthSources.Keys.DAILY_STEPS)));
+ mMockDataProvider));
PlatformInt32Source platformSource =
PlatformInt32Source.newBuilder()
.setSourceType(
@@ -445,32 +456,36 @@
List<Integer> results = new ArrayList<>();
LegacyPlatformInt32SourceNode platformSourceNode =
new LegacyPlatformInt32SourceNode(
- stateStore,
+ platformDataStore,
platformSource,
new AddToListCallback<>(results));
platformSourceNode.preInit();
platformSourceNode.init();
- assertThat(fakeSensorGateway.registeredConsumers).hasSize(1);
+ ArgumentCaptor<PlatformDataReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(PlatformDataReceiver.class);
+ verify(mMockDataProvider).setReceiver(any(), receiverCaptor.capture());
- fakeSensorGateway.registeredConsumers.get(0).onData(70.0);
+ PlatformDataReceiver receiver = receiverCaptor.getValue();
+ receiver.onData(ImmutableMap.of(DAILY_STEPS,
+ DynamicDataBuilders.DynamicDataValue.fromInt(70)));
+
assertThat(results).hasSize(1);
assertThat(results).containsExactly(70);
- fakeSensorGateway.registeredConsumers.get(0).onData(80.0);
+ receiver.onData(ImmutableMap.of(DAILY_STEPS,
+ DynamicDataBuilders.DynamicDataValue.fromInt(80)));
+
assertThat(results).hasSize(2);
assertThat(results).containsExactly(70, 80);
}
@Test
public void platformInt32Source_propagatesInvalidatedSignal() {
- FakeSensorGateway fakeSensorGateway = new FakeSensorGateway();
- StateStore stateStore = new StateStore(new ArrayMap<>());
- stateStore.putAllPlatformProviders(
+ PlatformDataStore platformDataStore = new PlatformDataStore(
Collections.singletonMap(
PlatformHealthSources.Keys.HEART_RATE_BPM,
- new SensorGatewaySingleDataProvider(
- fakeSensorGateway, PlatformHealthSources.Keys.HEART_RATE_BPM)));
+ mMockDataProvider));
PlatformInt32Source platformSource =
PlatformInt32Source.newBuilder()
.setSourceType(
@@ -479,7 +494,7 @@
.build();
LegacyPlatformInt32SourceNode platformSourceNode =
new LegacyPlatformInt32SourceNode(
- stateStore,
+ platformDataStore,
platformSource,
mMockValueReceiver);
@@ -487,9 +502,13 @@
verify(mMockValueReceiver).onPreUpdate();
platformSourceNode.init();
- assertThat(fakeSensorGateway.registeredConsumers).hasSize(1);
+ ArgumentCaptor<PlatformDataReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(PlatformDataReceiver.class);
+ verify(mMockDataProvider).setReceiver(any(), receiverCaptor.capture());
- fakeSensorGateway.registeredConsumers.get(0).onInvalidated();
+ PlatformDataReceiver receiver = receiverCaptor.getValue();
+ receiver.onInvalidated(ImmutableSet.of(HEART_RATE_BPM));
+
verify(mMockValueReceiver).onInvalidated();
}
}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/ParametrizedDynamicTypeEvaluatorTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/ParametrizedDynamicTypeEvaluatorTest.java
index 4480847..50b7b05 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/ParametrizedDynamicTypeEvaluatorTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/ParametrizedDynamicTypeEvaluatorTest.java
@@ -29,6 +29,7 @@
import android.os.Looper;
import androidx.annotation.NonNull;
+import androidx.wear.protolayout.expression.AppDataKey;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicDuration;
@@ -38,12 +39,11 @@
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString;
-import androidx.wear.protolayout.expression.AppDataKey;
+import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedBool;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedFloat;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedInt32;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedString;
-import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStoreTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStoreTest.java
new file mode 100644
index 0000000..ecfea31
--- /dev/null
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStoreTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.protolayout.expression.pipeline;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.util.ArrayMap;
+
+import androidx.annotation.NonNull;
+import androidx.collection.ArraySet;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.wear.protolayout.expression.DynamicBuilders;
+import androidx.wear.protolayout.expression.DynamicDataBuilders;
+import androidx.wear.protolayout.expression.PlatformDataKey;
+import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
+import androidx.wear.protolayout.expression.proto.FixedProto;
+
+import com.google.common.truth.Expect;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+public class PlatformDataStoreTest {
+ @Rule public Expect mExpect = Expect.create();
+ private static final PlatformDataKey<DynamicBuilders.DynamicString> KEY_FOO_PLATFORM =
+ new PlatformDataKey<>("platform", "foo");
+ private static final PlatformDataKey<DynamicBuilders.DynamicString> KEY_BAZ_PLATFORM =
+ new PlatformDataKey<>("platform", "baz");
+
+ private final PlatformDataProviderUnderTest mDataProvider = new PlatformDataProviderUnderTest();
+ private final PlatformDataStore mDataStoreUnderTest = new PlatformDataStore(
+ Map.of(
+ KEY_FOO_PLATFORM, mDataProvider,
+ KEY_BAZ_PLATFORM, mDataProvider
+ )
+ );
+
+ public PlatformDataStoreTest() {}
+
+ @Test
+ public void canUpdatePlatformData() {
+ mDataStoreUnderTest.updatePlatformDataEntriesProto(
+ Map.of(KEY_FOO_PLATFORM, buildDynamicDataValue("valueFoo1")));
+
+ mExpect.that(mDataStoreUnderTest.getDynamicDataValuesProto(KEY_FOO_PLATFORM))
+ .isEqualTo(buildDynamicDataValue("valueFoo1"));
+
+ mDataStoreUnderTest.updatePlatformDataEntriesProto(
+ Map.of(KEY_FOO_PLATFORM, buildDynamicDataValue("valueFoo2"),
+ KEY_BAZ_PLATFORM, buildDynamicDataValue("valueBaz")));
+ mExpect.that(mDataStoreUnderTest.getDynamicDataValuesProto(KEY_FOO_PLATFORM))
+ .isEqualTo(buildDynamicDataValue("valueFoo2"));
+
+ mExpect.that(mDataStoreUnderTest.getDynamicDataValuesProto(KEY_FOO_PLATFORM))
+ .isEqualTo(buildDynamicDataValue("valueFoo2"));
+ mExpect.that(mDataStoreUnderTest.getDynamicDataValuesProto(KEY_BAZ_PLATFORM))
+ .isEqualTo(buildDynamicDataValue("valueBaz"));
+ }
+ @Test
+ public void platformDataProvider_register_updateData_unregister() {
+ DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> cbFoo =
+ buildStateUpdateCallbackMock();
+ mDataStoreUnderTest.registerCallback(KEY_FOO_PLATFORM, cbFoo);
+ verify(cbFoo).onPreUpdate();
+ verify(cbFoo).onData(buildDynamicDataValue("fooValue"));
+ mExpect.that(mDataProvider.mRegisterCount).isEqualTo(1);
+
+ DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> cbBaz =
+ buildStateUpdateCallbackMock();
+ mDataStoreUnderTest.registerCallback(KEY_BAZ_PLATFORM, cbBaz);
+ mExpect.that(mDataProvider.mRegisterCount).isEqualTo(1);
+
+ DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> cbFoo2 =
+ buildStateUpdateCallbackMock();
+ mDataStoreUnderTest.registerCallback(KEY_FOO_PLATFORM, cbFoo2);
+ mExpect.that(mDataProvider.mRegisterCount).isEqualTo(1);
+
+ mDataProvider.updateValues(
+ Map.of(KEY_FOO_PLATFORM,
+ DynamicDataBuilders.DynamicDataValue.fromString("newFooValue"),
+ KEY_BAZ_PLATFORM,
+ DynamicDataBuilders.DynamicDataValue.fromString("newBazValue")
+ ));
+ verify(cbFoo, times(2)).onPreUpdate();
+ verify(cbFoo2).onPreUpdate();
+ verify(cbBaz).onPreUpdate();
+ verify(cbFoo).onData(buildDynamicDataValue("newFooValue"));
+ verify(cbFoo2).onData(buildDynamicDataValue("newFooValue"));
+ verify(cbBaz).onData(buildDynamicDataValue("newBazValue"));
+
+ mDataProvider.updateValues(
+ Map.of(
+ KEY_BAZ_PLATFORM,
+ DynamicDataBuilders.DynamicDataValue.fromString("updatedBazValue")
+ ));
+ verify(cbFoo, times(1)).onData(buildDynamicDataValue("newFooValue"));
+ verify(cbFoo2, times(1)).onData(buildDynamicDataValue("newFooValue"));
+ verify(cbBaz).onData(buildDynamicDataValue("newBazValue"));
+
+ mDataStoreUnderTest.unregisterCallback(KEY_FOO_PLATFORM, cbFoo);
+ mExpect.that(mDataProvider.mRegisterCount).isEqualTo(1);
+ mDataStoreUnderTest.unregisterCallback(KEY_FOO_PLATFORM, cbFoo2);
+ mExpect.that(mDataProvider.mRegisterCount).isEqualTo(1);
+ mDataStoreUnderTest.unregisterCallback(KEY_BAZ_PLATFORM, cbBaz);
+ mExpect.that(mDataProvider.mRegisterCount).isEqualTo(0);
+ }
+
+ @SuppressWarnings("unchecked")
+ private DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> buildStateUpdateCallbackMock() {
+ // This needs an unchecked cast because of the generic; this method just centralizes the
+ // warning suppression.
+ return mock(DynamicTypeValueReceiverWithPreUpdate.class);
+ }
+
+ private DynamicDataValue buildDynamicDataValue(String value) {
+ return DynamicDataValue.newBuilder()
+ .setStringVal(FixedProto.FixedString.newBuilder().setValue(value))
+ .build();
+ }
+
+ private class PlatformDataProviderUnderTest implements PlatformDataProvider {
+
+ private PlatformDataReceiver mRegisteredCallback = null;
+
+ private final Map<PlatformDataKey<?>, DynamicDataBuilders.DynamicDataValue> mCurrentValue =
+ new ArrayMap<>();
+
+ private final Set<PlatformDataKey<?>> mSupportedKeys = new ArraySet<>();
+
+ int mRegisterCount = 0;
+
+ PlatformDataProviderUnderTest() {
+ mSupportedKeys.add(KEY_FOO_PLATFORM);
+ mSupportedKeys.add(KEY_BAZ_PLATFORM);
+ mCurrentValue.put(
+ KEY_FOO_PLATFORM,
+ DynamicDataBuilders.DynamicDataValue.fromString("fooValue")
+ );
+ mCurrentValue.put(
+ KEY_BAZ_PLATFORM,
+ DynamicDataBuilders.DynamicDataValue.fromString("bazValue")
+ );
+ }
+
+ public void updateValues(
+ @NonNull Map<PlatformDataKey<?>, DynamicDataBuilders.DynamicDataValue> newData) {
+ mCurrentValue.putAll(newData);
+ if (mRegisteredCallback != null) {
+ mRegisteredCallback.onData(mCurrentValue);
+ }
+ }
+
+ @Override
+ public void setReceiver(
+ @NonNull Executor executor,
+ @NonNull PlatformDataReceiver callback) {
+ mRegisterCount++;
+ mRegisteredCallback = callback;
+ executor.execute(() -> callback.onData(mCurrentValue));
+ }
+
+ @Override
+ public void clearReceiver() {
+ if (mRegisteredCallback != null) {
+ mRegisteredCallback.onInvalidated(mSupportedKeys);
+ mRegisterCount--;
+ mRegisteredCallback = null;
+ }
+ }
+ }
+}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/PlatformTimeUpdateNotifierImplTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/PlatformTimeUpdateNotifierImplTest.java
new file mode 100644
index 0000000..2f40411
--- /dev/null
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/PlatformTimeUpdateNotifierImplTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.protolayout.expression.pipeline;
+
+
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+import android.os.SystemClock;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.shadows.ShadowLooper;
+
+import java.time.Duration;
+import java.util.concurrent.Callable;
+
+@RunWith(AndroidJUnit4.class)
+// For mocking the receiver.
+@SuppressWarnings("unchecked")
+public class PlatformTimeUpdateNotifierImplTest {
+ @Rule
+ public MockitoRule mMockRule = MockitoJUnit.rule();
+
+ private final ShadowLooper mMainLooper = ShadowLooper.shadowMainLooper();
+
+ private final PlatformTimeUpdateNotifierImpl mNotifierUnderTest =
+ new PlatformTimeUpdateNotifierImpl();
+ @Mock private Callable<ListenableFuture<Void>> mTick;
+
+
+ @Test
+ public void registerForUpdates_callsCallbackEverySecondWhenEnabled() throws Exception {
+ mNotifierUnderTest.setUpdatesEnabled(true);
+ mNotifierUnderTest.setReceiver(mTick);
+ mMainLooper.idle();
+
+ // First callback to initialize clients
+ verify(mTick).call();
+ reset(mTick);
+
+ for (int i = 0; i < 5; i++) {
+ runFor(500);
+ verifyNoInteractions(mTick);
+ runFor(500);
+
+ verify(mTick).call();
+ reset(mTick);
+ }
+ }
+
+ @Test
+ public void disableUpdates_stopsCallingCallback() {
+ mNotifierUnderTest.setUpdatesEnabled(true);
+ mNotifierUnderTest.setReceiver(mTick);
+ mMainLooper.idle();
+
+ // Run a little so it gets set up.
+ runFor(2500);
+ reset(mTick);
+
+ mNotifierUnderTest.setUpdatesEnabled(false);
+ runFor(1000);
+
+ verifyNoInteractions(mTick);
+ }
+
+ @Test
+ public void enableUpdates_reenablesCallback() throws Exception {
+ mNotifierUnderTest.setUpdatesEnabled(true);
+ mNotifierUnderTest.setReceiver(mTick);
+ mMainLooper.idle();
+
+ // Run a little so it gets set up.
+ runFor(2500);
+ reset(mTick);
+
+ mNotifierUnderTest.setUpdatesEnabled(false);
+ runFor(1000);
+
+ mNotifierUnderTest.setUpdatesEnabled(true);
+ runFor(500);
+ verifyNoInteractions(mTick);
+ runFor(500);
+ verify(mTick).call();
+ }
+
+ @Test
+ public void clearReceiver_stopsUpdates() {
+ mNotifierUnderTest.setUpdatesEnabled(true);
+ mNotifierUnderTest.setReceiver(mTick);
+ mMainLooper.idle();
+
+ // Run a little so it gets set up.
+ runFor(2500);
+ reset(mTick);
+
+ mNotifierUnderTest.clearReceiver();
+
+ runFor(2000);
+ verifyNoInteractions(mTick);
+ }
+
+ @Test
+ public void missedUpdate_schedulesAgainInFuture() throws Exception {
+ // This test is a tad fragile, and needs to know about the implementation details of Looper
+ // and ShadowLooper. Looper will call SystemClock.uptimeMillis internally to see what is
+ // schedulable. ShadowLooper also uses this in idleFor; it will do something similar to
+ // runFor; find the next time, advance SystemClock.setCurrentTimeMillis by that amount, call
+ // idle(), then keep going. Note though that it pulls the current time via
+ // SystemClock.uptimeMillis, but sets the current time via SystemClock.setCurrentTimeMillis.
+ // It appears that to Robolectric, the two are aliased (and getting the current time using
+ // System.getCurrentTimeMillis() gets the **actual** current time).
+ //
+ // This means that we can fake this behaviour to simulate a "missed" call; just advance the
+ // system clock, then call ShadowLooper#idle() to trigger any tasks that should have been
+ // dispatched in that time.
+ mNotifierUnderTest.setUpdatesEnabled(true);
+ mNotifierUnderTest.setReceiver(mTick);
+ mMainLooper.idle();
+
+ // First callback to initialize clients
+ verify(mTick).call();
+ reset(mTick);
+
+ // Advance by a few seconds...
+ long advanceBy = 5500;
+ long nextTimeMillis = SystemClock.uptimeMillis() + advanceBy;
+ SystemClock.setCurrentTimeMillis(nextTimeMillis);
+
+ mMainLooper.idle();
+
+ // The callback should have fired **once**, and another single callback scheduled in 500ms
+ // time.
+ verify(mTick).call();
+
+ reset(mTick);
+
+ runFor(500);
+
+ verify(mTick).call();
+ }
+
+ @Test
+ public void attemptToSetMultipleReceivers_replacesFirstOne() throws Exception {
+ mNotifierUnderTest.setUpdatesEnabled(true);
+ mNotifierUnderTest.setReceiver(mTick);
+ mMainLooper.idle();
+
+ // First callback to initialize clients
+ verify(mTick).call();
+ reset(mTick);
+
+ mNotifierUnderTest.setReceiver(() -> null);
+
+ runFor(2000);
+ verifyNoInteractions(mTick);
+ }
+
+ private void runFor(long runMillis) {
+ mMainLooper.idleFor(Duration.ofMillis(runMillis));
+ }
+}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StateStoreTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StateStoreTest.java
index 324d7ed..f803991 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StateStoreTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StateStoreTest.java
@@ -25,17 +25,12 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
-import android.util.ArrayMap;
-
-import androidx.annotation.NonNull;
-import androidx.collection.ArraySet;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.wear.protolayout.expression.AppDataKey;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString;
import androidx.wear.protolayout.expression.DynamicDataBuilders;
-import androidx.wear.protolayout.expression.PlatformDataKey;
-import androidx.wear.protolayout.expression.proto.FixedProto.FixedString;
import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
+import androidx.wear.protolayout.expression.proto.FixedProto.FixedString;
import com.google.common.collect.ImmutableMap;
import com.google.common.truth.Expect;
@@ -48,8 +43,6 @@
import java.util.HashMap;
import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Executor;
@RunWith(AndroidJUnit4.class)
public class StateStoreTest {
@@ -58,11 +51,6 @@
private static final AppDataKey<DynamicString> KEY_FOO = new AppDataKey<>("foo");
private static final AppDataKey<DynamicString> KEY_BAZ = new AppDataKey<>("baz");
- private static final PlatformDataKey<DynamicString> KEY_FOO_PLATFORM
- = new PlatformDataKey<>("platform", "foo");
- private static final PlatformDataKey<DynamicString> KEY_BAZ_PLATFORM
- = new PlatformDataKey<>("platform","baz");
-
private final StateStore mStateStoreUnderTest =
new StateStore(
ImmutableMap.of(
@@ -141,34 +129,6 @@
}
@Test
- public void canUpdatePlatformData() {
- mStateStoreUnderTest.updatePlatformDataEntryProto(
- Map.of(KEY_FOO_PLATFORM, buildDynamicDataValue("valueFoo1")));
-
- mExpect.that(mStateStoreUnderTest.getDynamicDataValuesProto(KEY_FOO))
- .isEqualTo(buildDynamicDataValue("bar"));
- mExpect.that(mStateStoreUnderTest.getDynamicDataValuesProto(KEY_BAZ))
- .isEqualTo(buildDynamicDataValue("foobar"));
- mExpect.that(mStateStoreUnderTest.getDynamicDataValuesProto(KEY_FOO_PLATFORM))
- .isEqualTo(buildDynamicDataValue("valueFoo1"));
-
- mStateStoreUnderTest.updatePlatformDataEntryProto(
- Map.of(KEY_FOO_PLATFORM, buildDynamicDataValue("valueFoo2"),
- KEY_BAZ_PLATFORM, buildDynamicDataValue("valueBaz")));
- mExpect.that(mStateStoreUnderTest.getDynamicDataValuesProto(KEY_FOO_PLATFORM))
- .isEqualTo(buildDynamicDataValue("valueFoo2"));
-
- mExpect.that(mStateStoreUnderTest.getDynamicDataValuesProto(KEY_FOO))
- .isEqualTo(buildDynamicDataValue("bar"));
- mExpect.that(mStateStoreUnderTest.getDynamicDataValuesProto(KEY_BAZ))
- .isEqualTo(buildDynamicDataValue("foobar"));
- mExpect.that(mStateStoreUnderTest.getDynamicDataValuesProto(KEY_FOO_PLATFORM))
- .isEqualTo(buildDynamicDataValue("valueFoo2"));
- mExpect.that(mStateStoreUnderTest.getDynamicDataValuesProto(KEY_BAZ_PLATFORM))
- .isEqualTo(buildDynamicDataValue("valueBaz"));
- }
-
- @Test
public void setStateFiresListeners() {
DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> cb = buildStateUpdateCallbackMock();
mStateStoreUnderTest.registerCallback(KEY_FOO, cb);
@@ -181,61 +141,6 @@
}
@Test
- public void platformDataProvider_register_updateData_unregister() {
- PlatformDataProviderUnderTest dataProvider = new PlatformDataProviderUnderTest();
- Map<PlatformDataKey<?>, PlatformDataProvider> sourceKeyToDataProvider = new ArrayMap<>();
- sourceKeyToDataProvider.put(KEY_FOO_PLATFORM, dataProvider);
- sourceKeyToDataProvider.put(KEY_BAZ_PLATFORM, dataProvider);
- mStateStoreUnderTest.putAllPlatformProviders(sourceKeyToDataProvider);
-
- DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> cbFoo =
- buildStateUpdateCallbackMock();
- mStateStoreUnderTest.registerCallback(KEY_FOO_PLATFORM, cbFoo);
- verify(cbFoo).onPreUpdate();
- verify(cbFoo).onData(buildDynamicDataValue("fooValue"));
- mExpect.that(dataProvider.mRegisterCount).isEqualTo(1);
-
- DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> cbBaz =
- buildStateUpdateCallbackMock();
- mStateStoreUnderTest.registerCallback(KEY_BAZ_PLATFORM, cbBaz);
- mExpect.that(dataProvider.mRegisterCount).isEqualTo(1);
-
- DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> cbFoo2 =
- buildStateUpdateCallbackMock();
- mStateStoreUnderTest.registerCallback(KEY_FOO_PLATFORM, cbFoo2);
- mExpect.that(dataProvider.mRegisterCount).isEqualTo(1);
-
- dataProvider.updateValues(
- Map.of(KEY_FOO_PLATFORM,
- DynamicDataBuilders.DynamicDataValue.fromString("newFooValue"),
- KEY_BAZ_PLATFORM,
- DynamicDataBuilders.DynamicDataValue.fromString("newBazValue")
- ));
- verify(cbFoo, times(2)).onPreUpdate();
- verify(cbFoo2).onPreUpdate();
- verify(cbBaz).onPreUpdate();
- verify(cbFoo).onData(buildDynamicDataValue("newFooValue"));
- verify(cbFoo2).onData(buildDynamicDataValue("newFooValue"));
- verify(cbBaz).onData(buildDynamicDataValue("newBazValue"));
-
- dataProvider.updateValues(
- Map.of(
- KEY_BAZ_PLATFORM,
- DynamicDataBuilders.DynamicDataValue.fromString("updatedBazValue")
- ));
- verify(cbFoo, times(1)).onData(buildDynamicDataValue("newFooValue"));
- verify(cbFoo2, times(1)).onData(buildDynamicDataValue("newFooValue"));
- verify(cbBaz).onData(buildDynamicDataValue("newBazValue"));
-
- mStateStoreUnderTest.unregisterCallback(KEY_FOO_PLATFORM, cbFoo);
- mExpect.that(dataProvider.mRegisterCount).isEqualTo(1);
- mStateStoreUnderTest.unregisterCallback(KEY_FOO_PLATFORM, cbFoo2);
- mExpect.that(dataProvider.mRegisterCount).isEqualTo(1);
- mStateStoreUnderTest.unregisterCallback(KEY_BAZ_PLATFORM, cbBaz);
- mExpect.that(dataProvider.mRegisterCount).isEqualTo(0);
- }
-
- @Test
public void setStateFiresOnPreStateUpdateFirst() {
DynamicTypeValueReceiverWithPreUpdate<DynamicDataValue> cb = buildStateUpdateCallbackMock();
@@ -332,55 +237,4 @@
.setStringVal(FixedString.newBuilder().setValue(value))
.build();
}
-
- private class PlatformDataProviderUnderTest implements PlatformDataProvider {
-
- private PlatformDataReceiver mRegisteredCallback = null;
-
- private final Map<PlatformDataKey<?>, DynamicDataBuilders.DynamicDataValue> mCurrentValue =
- new ArrayMap<>();
-
- private final Set<PlatformDataKey<?>> mSupportedKeys= new ArraySet<>();
-
- int mRegisterCount = 0;
-
- PlatformDataProviderUnderTest() {
- mSupportedKeys.add(KEY_FOO_PLATFORM);
- mSupportedKeys.add(KEY_BAZ_PLATFORM);
- mCurrentValue.put(
- KEY_FOO_PLATFORM,
- DynamicDataBuilders.DynamicDataValue.fromString("fooValue")
- );
- mCurrentValue.put(
- KEY_BAZ_PLATFORM,
- DynamicDataBuilders.DynamicDataValue.fromString("bazValue")
- );
- }
-
- public void updateValues(
- @NonNull Map<PlatformDataKey<?> , DynamicDataBuilders.DynamicDataValue> newData) {
- mCurrentValue.putAll(newData);
- if (mRegisteredCallback != null) {
- mRegisteredCallback.onData(mCurrentValue);
- }
- }
-
- @Override
- public void registerForData(
- @NonNull Executor executor,
- @NonNull PlatformDataReceiver callback) {
- mRegisterCount++;
- mRegisteredCallback = callback;
- executor.execute(() -> callback.onData(mCurrentValue));
- }
-
- @Override
- public void unregisterForData() {
- if (mRegisteredCallback != null) {
- mRegisteredCallback.onInvalidated(mSupportedKeys);
- mRegisterCount--;
- mRegisteredCallback = null;
- }
- }
- }
}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StringNodesTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StringNodesTest.java
index f9afae6..b3d45da 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StringNodesTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StringNodesTest.java
@@ -29,10 +29,10 @@
import androidx.wear.protolayout.expression.pipeline.StringNodes.Int32FormatNode;
import androidx.wear.protolayout.expression.pipeline.StringNodes.StateStringNode;
import androidx.wear.protolayout.expression.pipeline.StringNodes.StringConcatOpNode;
+import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import androidx.wear.protolayout.expression.proto.DynamicProto.Int32FormatOp;
import androidx.wear.protolayout.expression.proto.DynamicProto.StateStringSource;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedString;
-import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import com.google.common.collect.ImmutableMap;
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/TimeGatewayImplTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/TimeGatewayImplTest.java
deleted file mode 100644
index 08d0bbc..0000000
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/TimeGatewayImplTest.java
+++ /dev/null
@@ -1,189 +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.protolayout.expression.pipeline;
-
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoInteractions;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.wear.protolayout.expression.pipeline.TimeGateway.TimeCallback;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.robolectric.shadows.ShadowLooper;
-
-import java.time.Duration;
-import java.util.concurrent.Executor;
-
-@RunWith(AndroidJUnit4.class)
-public class TimeGatewayImplTest {
- @Rule public MockitoRule mMockRule = MockitoJUnit.rule();
-
- private final ShadowLooper mMainLooper = ShadowLooper.shadowMainLooper();
- private final Handler mTestHandler = new Handler(Looper.getMainLooper());
- private final Executor mImmediateExecutor = Runnable::run;
- @Mock private TimeCallback mCallback;
-
- private final TimeGatewayImpl mGatewayUnderTest = new TimeGatewayImpl(mTestHandler);
-
- @Test
- public void registerForUpdates_callsCallbackEverySecondWhenEnabled() {
- mGatewayUnderTest.enableUpdates();
- mGatewayUnderTest.registerForUpdates(mImmediateExecutor, mCallback);
- mMainLooper.idle();
-
- // First callback to initialize clients
- verify(mCallback).onPreUpdate();
- verify(mCallback).onData();
- reset(mCallback);
-
- for (int i = 0; i < 5; i++) {
- runFor(500);
- verifyNoInteractions(mCallback);
- runFor(500);
-
- verify(mCallback).onPreUpdate();
- verify(mCallback).onData();
- reset(mCallback);
- }
- }
-
- @Test
- public void disableUpdates_stopsCallingCallback() {
- mGatewayUnderTest.enableUpdates();
- mGatewayUnderTest.registerForUpdates(mImmediateExecutor, mCallback);
- mMainLooper.idle();
-
- // Run a little so it gets set up.
- runFor(2500);
- reset(mCallback);
-
- mGatewayUnderTest.disableUpdates();
- runFor(1000);
-
- verifyNoInteractions(mCallback);
- }
-
- @Test
- public void enableUpdates_reenablesCallback() {
- mGatewayUnderTest.enableUpdates();
- mGatewayUnderTest.registerForUpdates(mImmediateExecutor, mCallback);
- mMainLooper.idle();
-
- // Run a little so it gets set up.
- runFor(2500);
- reset(mCallback);
-
- mGatewayUnderTest.disableUpdates();
- runFor(1000);
-
- mGatewayUnderTest.enableUpdates();
- runFor(500);
- verifyNoInteractions(mCallback);
- runFor(500);
- verify(mCallback).onPreUpdate();
- verify(mCallback).onData();
- }
-
- @Test
- public void close_stopsUpdates() throws Exception {
- mGatewayUnderTest.enableUpdates();
- mGatewayUnderTest.registerForUpdates(mImmediateExecutor, mCallback);
- mMainLooper.idle();
-
- // Run a little so it gets set up.
- runFor(2500);
- reset(mCallback);
-
- mGatewayUnderTest.close();
-
- runFor(2000);
- verifyNoInteractions(mCallback);
- }
-
- @Test
- public void unregisterForUpdates() {
- mGatewayUnderTest.enableUpdates();
- mGatewayUnderTest.registerForUpdates(mImmediateExecutor, mCallback);
- mMainLooper.idle();
-
- // Run a little so it gets set up.
- runFor(2500);
- reset(mCallback);
-
- mGatewayUnderTest.unregisterForUpdates(mCallback);
-
- runFor(2000);
- verifyNoInteractions(mCallback);
- }
-
- @Test
- public void missedUpdate_schedulesAgainInFuture() throws Exception {
- // This test is a tad fragile, and needs to know about the implementation details of Looper
- // and ShadowLooper. Looper will call SystemClock.uptimeMillis internally to see what is
- // schedulable. ShadowLooper also uses this in idleFor; it will do something similar to
- // runFor; find the next time, advance SystemClock.setCurrentTimeMillis by that amount, call
- // idle(), then keep going. Note though that it pulls the current time via
- // SystemClock.uptimeMillis, but sets the current time via SystemClock.setCurrentTimeMillis.
- // It appears that to Robolectric, the two are aliased (and getting the current time using
- // System.getCurrentTimeMillis() gets the **actual** current time).
- //
- // This means that we can fake this behaviour to simulate a "missed" call; just advance the
- // system clock, then call ShadowLooper#idle() to trigger any tasks that should have been
- // dispatched in that time.
- mGatewayUnderTest.enableUpdates();
- mGatewayUnderTest.registerForUpdates(mImmediateExecutor, mCallback);
- mMainLooper.idle();
-
- // First callback to initialize clients
- verify(mCallback).onPreUpdate();
- verify(mCallback).onData();
- reset(mCallback);
-
- // Advance by a few seconds...
- long advanceBy = 5500;
- long nextTimeMillis = SystemClock.uptimeMillis() + advanceBy;
- SystemClock.setCurrentTimeMillis(nextTimeMillis);
-
- mMainLooper.idle();
-
- // The callback should have fired **once**, and another single callback scheduled in 500ms
- // time.
- verify(mCallback).onPreUpdate();
- verify(mCallback).onData();
-
- reset(mCallback);
-
- runFor(500);
-
- verify(mCallback).onPreUpdate();
- verify(mCallback).onData();
- }
-
- private void runFor(long runMillis) {
- mMainLooper.idleFor(Duration.ofMillis(runMillis));
- }
-}
diff --git a/wear/protolayout/protolayout-expression/api/current.txt b/wear/protolayout/protolayout-expression/api/current.txt
index f51a3e9..ee606de 100644
--- a/wear/protolayout/protolayout-expression/api/current.txt
+++ b/wear/protolayout/protolayout-expression/api/current.txt
@@ -315,17 +315,38 @@
public class PlatformHealthSources {
method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyCalories();
- method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyDistanceM();
+ method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyDistanceMeters();
method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyFloors();
method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 dailySteps();
+ method @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy heartRateAccuracy();
method @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat heartRateBpm();
}
+ public static class PlatformHealthSources.Constants {
+ ctor public PlatformHealthSources.Constants();
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_HIGH;
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_LOW;
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_MEDIUM;
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_NO_CONTACT;
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_UNKNOWN;
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_UNRELIABLE;
+ }
+
+ public static final class PlatformHealthSources.DynamicHeartRateAccuracy implements androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 {
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy HIGH;
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy LOW;
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy MEDIUM;
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy NO_CONTACT;
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy UNKNOWN;
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy UNRELIABLE;
+ }
+
public static class PlatformHealthSources.Keys {
field @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> DAILY_CALORIES;
- field @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> DAILY_DISTANCE_M;
+ field @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> DAILY_DISTANCE_METERS;
field @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> DAILY_FLOORS;
field @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32!> DAILY_STEPS;
+ field @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy!> HEART_RATE_ACCURACY;
field @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> HEART_RATE_BPM;
}
diff --git a/wear/protolayout/protolayout-expression/api/restricted_current.txt b/wear/protolayout/protolayout-expression/api/restricted_current.txt
index f51a3e9..ee606de 100644
--- a/wear/protolayout/protolayout-expression/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-expression/api/restricted_current.txt
@@ -315,17 +315,38 @@
public class PlatformHealthSources {
method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyCalories();
- method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyDistanceM();
+ method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyDistanceMeters();
method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyFloors();
method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 dailySteps();
+ method @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy heartRateAccuracy();
method @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat heartRateBpm();
}
+ public static class PlatformHealthSources.Constants {
+ ctor public PlatformHealthSources.Constants();
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_HIGH;
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_LOW;
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_MEDIUM;
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_NO_CONTACT;
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_UNKNOWN;
+ field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_UNRELIABLE;
+ }
+
+ public static final class PlatformHealthSources.DynamicHeartRateAccuracy implements androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 {
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy HIGH;
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy LOW;
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy MEDIUM;
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy NO_CONTACT;
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy UNKNOWN;
+ field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy UNRELIABLE;
+ }
+
public static class PlatformHealthSources.Keys {
field @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> DAILY_CALORIES;
- field @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> DAILY_DISTANCE_M;
+ field @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> DAILY_DISTANCE_METERS;
field @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> DAILY_FLOORS;
field @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32!> DAILY_STEPS;
+ field @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy!> HEART_RATE_ACCURACY;
field @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static final androidx.wear.protolayout.expression.PlatformDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> HEART_RATE_BPM;
}
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/AnimationParameterBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/AnimationParameterBuilders.java
index 69a0886c..568d847 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/AnimationParameterBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/AnimationParameterBuilders.java
@@ -108,20 +108,14 @@
}
}
- /**
- * Get the fingerprint for this object, or null if unknown.
- *
- */
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static AnimationSpec fromProto(
@@ -132,7 +126,6 @@
/**
* Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
* created using this method can't be added to any other wrapper.
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@@ -140,10 +133,7 @@
return fromProto(proto, null);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public AnimationParameterProto.AnimationSpec toProto() {
@@ -445,10 +435,7 @@
@Nullable
Fingerprint getFingerprint();
- /**
- * Builder to create {@link Easing} objects.
- *
- */
+ /** Builder to create {@link Easing} objects. */
@RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
@@ -458,10 +445,7 @@
}
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static Easing easingFromProto(
@@ -540,10 +524,7 @@
return mFingerprint;
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static CubicBezierEasing fromProto(
@@ -557,10 +538,7 @@
return fromProto(proto, null);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
AnimationParameterProto.CubicBezierEasing toProto() {
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
index 0fe6f1a..d90d926 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
@@ -460,7 +460,6 @@
* Returns the internal proto instance.
*
*/
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.PlatformInt32Source toProto() {
return mImpl;
@@ -583,6 +582,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.ArithmeticInt32Op toProto() {
return mImpl;
@@ -596,6 +596,19 @@
return DynamicProto.DynamicInt32.newBuilder().setArithmeticOperation(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ArithmeticInt32Op{"
+ + "inputLhs="
+ + getInputLhs()
+ + ", inputRhs="
+ + getInputRhs()
+ + ", operationType="
+ + getOperationType()
+ + "}";
+ }
+
/** Builder for {@link ArithmeticInt32Op}. */
public static final class Builder implements DynamicInt32.Builder {
@@ -705,6 +718,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.StateInt32Source toProto() {
return mImpl;
@@ -848,6 +862,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.ConditionalInt32Op toProto() {
return mImpl;
@@ -861,6 +876,19 @@
return DynamicProto.DynamicInt32.newBuilder().setConditionalOp(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ConditionalInt32Op{"
+ + "condition="
+ + getCondition()
+ + ", valueIfTrue="
+ + getValueIfTrue()
+ + ", valueIfFalse="
+ + getValueIfFalse()
+ + "}";
+ }
+
/** Builder for {@link ConditionalInt32Op}. */
public static final class Builder implements DynamicInt32.Builder {
@@ -997,6 +1025,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.ConditionalFloatOp toProto() {
return mImpl;
@@ -1010,6 +1039,19 @@
return DynamicProto.DynamicFloat.newBuilder().setConditionalOp(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ConditionalFloatOp{"
+ + "condition="
+ + getCondition()
+ + ", valueIfTrue="
+ + getValueIfTrue()
+ + ", valueIfFalse="
+ + getValueIfFalse()
+ + "}";
+ }
+
/** Builder for {@link ConditionalFloatOp}. */
public static final class Builder implements DynamicFloat.Builder {
@@ -1124,6 +1166,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.FloatToInt32Op toProto() {
return mImpl;
@@ -1241,6 +1284,7 @@
public Fingerprint getFingerprint() {
return mFingerprint;
}
+
/** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@@ -1256,7 +1300,6 @@
}
/** Returns the internal proto instance. */
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.AnimatableFixedInt32 toProto() {
return mImpl;
@@ -1390,6 +1433,7 @@
public Fingerprint getFingerprint() {
return mFingerprint;
}
+
/** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@@ -1406,7 +1450,6 @@
}
/** Returns the internal proto instance. */
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.AnimatableDynamicInt32 toProto() {
return mImpl;
@@ -2611,6 +2654,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.Int32FormatOp toProto() {
return mImpl;
@@ -2749,6 +2793,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.StateStringSource toProto() {
return mImpl;
@@ -2764,7 +2809,8 @@
@Override
@NonNull
public String toString() {
- return "StateStringSource{"+ "sourceKey="
+ return "StateStringSource{"
+ + "sourceKey="
+ getSourceKey()
+ ", sourceNamespace="
+ getSourceNamespace()
@@ -2890,6 +2936,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.ConditionalStringOp toProto() {
return mImpl;
@@ -3033,6 +3080,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.ConcatStringOp toProto() {
return mImpl;
@@ -3195,6 +3243,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.FloatFormatOp toProto() {
return mImpl;
@@ -3579,6 +3628,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.ArithmeticFloatOp toProto() {
return mImpl;
@@ -3592,6 +3642,19 @@
return DynamicProto.DynamicFloat.newBuilder().setArithmeticOperation(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ArithmeticFloatOp{"
+ + "inputLhs="
+ + getInputLhs()
+ + ", inputRhs="
+ + getInputRhs()
+ + ", operationType="
+ + getOperationType()
+ + "}";
+ }
+
/** Builder for {@link ArithmeticFloatOp}. */
public static final class Builder implements DynamicFloat.Builder {
@@ -3702,6 +3765,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.StateFloatSource toProto() {
return mImpl;
@@ -3717,7 +3781,8 @@
@Override
@NonNull
public String toString() {
- return "StateFloatSource{"+ "sourceKey="
+ return "StateFloatSource{"
+ + "sourceKey="
+ getSourceKey()
+ ", sourceNamespace="
+ getSourceNamespace()
@@ -3812,6 +3877,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.Int32ToFloatOp toProto() {
return mImpl;
@@ -3927,6 +3993,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.AnimatableFixedFloat toProto() {
return mImpl;
@@ -4076,6 +4143,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.AnimatableDynamicFloat toProto() {
return mImpl;
@@ -5194,6 +5262,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.StateBoolSource toProto() {
return mImpl;
@@ -5334,6 +5403,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.ComparisonInt32Op toProto() {
return mImpl;
@@ -5347,6 +5417,19 @@
return DynamicProto.DynamicBool.newBuilder().setInt32Comparison(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ComparisonInt32Op{"
+ + "inputLhs="
+ + getInputLhs()
+ + ", inputRhs="
+ + getInputRhs()
+ + ", operationType="
+ + getOperationType()
+ + "}";
+ }
+
/** Builder for {@link ComparisonInt32Op}. */
public static final class Builder implements DynamicBool.Builder {
@@ -5478,6 +5561,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.ComparisonFloatOp toProto() {
return mImpl;
@@ -5491,6 +5575,19 @@
return DynamicProto.DynamicBool.newBuilder().setFloatComparison(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ComparisonFloatOp{"
+ + "inputLhs="
+ + getInputLhs()
+ + ", inputRhs="
+ + getInputRhs()
+ + ", operationType="
+ + getOperationType()
+ + "}";
+ }
+
/** Builder for {@link ComparisonFloatOp}. */
public static final class Builder implements DynamicBool.Builder {
@@ -5594,6 +5691,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.NotBoolOp toProto() {
return mImpl;
@@ -5714,6 +5812,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.LogicalBoolOp toProto() {
return mImpl;
@@ -6062,6 +6161,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.StateColorSource toProto() {
return mImpl;
@@ -6195,6 +6295,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.AnimatableFixedColor toProto() {
return mImpl;
@@ -6344,6 +6445,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.AnimatableDynamicColor toProto() {
return mImpl;
@@ -6492,7 +6594,6 @@
}
/** Returns the internal proto instance. */
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.ConditionalColorOp toProto() {
return mImpl;
@@ -6809,6 +6910,9 @@
if (proto.hasAnimatableDynamic()) {
return AnimatableDynamicColor.fromProto(proto.getAnimatableDynamic(), fingerprint);
}
+ if (proto.hasConditionalOp()) {
+ return ConditionalColorOp.fromProto(proto.getConditionalOp(), fingerprint);
+ }
throw new IllegalStateException("Proto was not a recognised instance of DynamicColor");
}
@@ -6857,6 +6961,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.PlatformTimeSource toProto() {
return mImpl;
@@ -6975,7 +7080,6 @@
}
/** Returns the internal proto instance. */
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.ConditionalInstantOp toProto() {
return mImpl;
@@ -7302,6 +7406,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.BetweenDuration toProto() {
return mImpl;
@@ -7451,7 +7556,6 @@
}
/** Returns the internal proto instance. */
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.ConditionalDurationOp toProto() {
return mImpl;
@@ -7851,7 +7955,7 @@
return FixedDuration.fromProto(proto.getFixed(), fingerprint);
}
if (proto.hasConditionalOp()) {
- return ConditionalDurationOp.fromProto(proto.getConditionalOp());
+ return ConditionalDurationOp.fromProto(proto.getConditionalOp(), fingerprint);
}
throw new IllegalStateException("Proto was not a recognised instance of DynamicDuration");
}
@@ -7926,6 +8030,7 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@NonNull
DynamicProto.GetDurationPartOp toProto() {
return mImpl;
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataBuilders.java
index 8f91189..15ef422 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataBuilders.java
@@ -43,10 +43,7 @@
* @since 1.2
*/
public interface DynamicDataValue {
- /**
- * Get the protocol buffer representation of this object.
- *
- */
+ /** Get the protocol buffer representation of this object. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicDataProto.DynamicDataValue toDynamicDataValueProto();
@@ -150,17 +147,12 @@
return new FixedString.Builder().setValue(constant).build();
}
- /**
- * Get the fingerprint for this object or null if unknown.
- *
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
Fingerprint getFingerprint();
- /** Builder to create {@link DynamicDataValue} objects.
- *
- */
+ /** Builder to create {@link DynamicDataValue} objects. */
@RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
@@ -173,27 +165,35 @@
/**
* Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
* created using this method can't be added to any other wrapper.
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static DynamicDataValue dynamicDataValueFromProto(
@NonNull DynamicDataProto.DynamicDataValue proto) {
+ return dynamicDataValueFromProto(proto, null);
+ }
+
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public static DynamicDataValue dynamicDataValueFromProto(
+ @NonNull DynamicDataProto.DynamicDataValue proto, @Nullable Fingerprint fingerprint) {
if (proto.hasStringVal()) {
- return FixedString.fromProto(proto.getStringVal());
+ return FixedString.fromProto(proto.getStringVal(), fingerprint);
}
if (proto.hasInt32Val()) {
- return FixedInt32.fromProto(proto.getInt32Val());
+ return FixedInt32.fromProto(proto.getInt32Val(), fingerprint);
}
if (proto.hasFloatVal()) {
- return FixedFloat.fromProto(proto.getFloatVal());
+ return FixedFloat.fromProto(proto.getFloatVal(), fingerprint);
}
if (proto.hasBoolVal()) {
- return FixedBool.fromProto(proto.getBoolVal());
+ return FixedBool.fromProto(proto.getBoolVal(), fingerprint);
}
if (proto.hasColorVal()) {
- return FixedColor.fromProto(proto.getColorVal());
+ return FixedColor.fromProto(proto.getColorVal(), fingerprint);
}
throw new IllegalStateException("Proto was not a recognised instance of DynamicDataValue");
}
+
}
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataKey.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataKey.java
index 29c060d..55fdf73 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataKey.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataKey.java
@@ -78,6 +78,6 @@
@NonNull
@Override
public String toString() {
- return String.format("namespace = %s, key = %s", mNamespace, mKey);
+ return String.format("DynamicDataKey{namespace=%s, key=%s}", mNamespace, mKey);
}
}
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java
index 5d6d870..3718124 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java
@@ -77,6 +77,8 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
FixedProto.FixedInt32 toProto() {
return mImpl;
@@ -176,6 +178,8 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
FixedProto.FixedString toProto() {
return mImpl;
@@ -275,6 +279,8 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
FixedProto.FixedFloat toProto() {
return mImpl;
@@ -376,6 +382,8 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
FixedProto.FixedBool toProto() {
return mImpl;
@@ -476,6 +484,8 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
FixedProto.FixedColor toProto() {
return mImpl;
@@ -573,6 +583,8 @@
return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
FixedProto.FixedInstant toProto() {
return mImpl;
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformDataKey.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformDataKey.java
index 24ed21e..b1fd7cf 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformDataKey.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformDataKey.java
@@ -22,19 +22,18 @@
/**
* Represent a {@link DynamicDataKey} that references real-time data from the platform.
*
- * <p> The [namespace, key] tuple creates the actual reference, so that a single key can refer to
- * two different sources in two different namespaces.
+ * <p>The [namespace, key] tuple creates the actual reference, so that a single key can refer to two
+ * different sources in two different namespaces.
*
- * <p> The namespace must not be empty. Additionally, the "protolayout" namespace (and its
- * lowercase and uppercase variations) are reserved for the default platform data sources and
- * should not be used for any custom OEM data source. To choose the namespace that does not
- * conflict with an existing one, use a unique prefix for your namespace, for example, company
- * name or product name.
+ * <p>The namespace must not be empty. Additionally, the "protolayout" namespace (and its lowercase
+ * and uppercase variations) are reserved for the default platform data sources and should not be
+ * used for any custom OEM data source. To make sure namespaces are unique, any custom namespace is
+ * expected to follow Java style naming {@code com.company.foo}.
*
* @param <T> The data type of the dynamic values that this key is bound to.
*/
-public final class PlatformDataKey<T extends DynamicBuilders.DynamicType> extends DynamicDataKey<T>
-{
+public final class PlatformDataKey<T extends DynamicBuilders.DynamicType>
+ extends DynamicDataKey<T> {
@NonNull private static final String RESERVED_NAMESPACE = "protolayout";
/**
@@ -50,15 +49,16 @@
}
if (RESERVED_NAMESPACE.equalsIgnoreCase(namespace)) {
- throw new IllegalArgumentException(String.format(
- "Custom data source must not use the reserved namespace:%s",
- RESERVED_NAMESPACE));
+ throw new IllegalArgumentException(
+ String.format(
+ "Custom data source must not use the reserved namespace:%s",
+ RESERVED_NAMESPACE));
}
}
/**
- * Create a {@link PlatformDataKey} with the specified key in the reserved namespace.
- * This should only be used by protolayout library internally for default platform data sources.
+ * Create a {@link PlatformDataKey} with the specified key in the reserved namespace. This
+ * should only be used by protolayout library internally for default platform data sources.
*
* @param key The key that references the platform data source
*/
@@ -67,4 +67,3 @@
super(RESERVED_NAMESPACE, key);
}
}
-
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformHealthSources.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformHealthSources.java
index 0214ed2..069542a 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformHealthSources.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformHealthSources.java
@@ -22,13 +22,52 @@
import android.Manifest;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresPermission;
+import androidx.annotation.RestrictTo;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32;
import androidx.wear.protolayout.expression.DynamicBuilders.PlatformInt32Source;
+import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
+import androidx.wear.protolayout.expression.proto.DynamicProto;
/** Dynamic types for platform health sources. */
public class PlatformHealthSources {
+ /** Constants for platform health sources. */
+ public static class Constants {
+ /** The accuracy is unknown. */
+ private static final int HEART_RATE_ACCURACY_UNKNOWN_VALUE = 0;
+ /** The heart rate cannot be acquired because the sensor is not properly contacting skin. */
+ private static final int HEART_RATE_ACCURACY_NO_CONTACT_VALUE = 1;
+ /** Heart rate data is currently too unreliable to be used. */
+ private static final int HEART_RATE_ACCURACY_UNRELIABLE_VALUE = 2;
+ /** Heart rate data is available but the accuracy is low. */
+ private static final int HEART_RATE_ACCURACY_LOW_VALUE = 3;
+ /** Heart rate data is available and the accuracy is medium. */
+ private static final int HEART_RATE_ACCURACY_MEDIUM_VALUE = 4;
+ /** Heart rate data is available with high accuracy. */
+ private static final int HEART_RATE_ACCURACY_HIGH_VALUE = 5;
+
+ /** The accuracy is unknown. */
+ public static final DynamicDataValue HEART_RATE_ACCURACY_UNKNOWN =
+ DynamicDataValue.fromInt(HEART_RATE_ACCURACY_UNKNOWN_VALUE);
+ /** The heart rate cannot be acquired because the sensor is not properly contacting skin. */
+ public static final DynamicDataValue HEART_RATE_ACCURACY_NO_CONTACT =
+ DynamicDataValue.fromInt(HEART_RATE_ACCURACY_NO_CONTACT_VALUE);
+ /** Heart rate data is currently too unreliable to be used. */
+ public static final DynamicDataValue HEART_RATE_ACCURACY_UNRELIABLE =
+ DynamicDataValue.fromInt(HEART_RATE_ACCURACY_UNRELIABLE_VALUE);
+ /** Heart rate data is available but the accuracy is low. */
+ public static final DynamicDataValue HEART_RATE_ACCURACY_LOW =
+ DynamicDataValue.fromInt(HEART_RATE_ACCURACY_LOW_VALUE);
+ /** Heart rate data is available and the accuracy is medium. */
+ public static final DynamicDataValue HEART_RATE_ACCURACY_MEDIUM =
+ DynamicDataValue.fromInt(HEART_RATE_ACCURACY_MEDIUM_VALUE);
+ /** Heart rate data is available with high accuracy. */
+ public static final DynamicDataValue HEART_RATE_ACCURACY_HIGH =
+ DynamicDataValue.fromInt(HEART_RATE_ACCURACY_HIGH_VALUE);
+ }
+
/** Data sources keys for platform health sources. */
public static class Keys {
private Keys() {}
@@ -40,6 +79,14 @@
new PlatformDataKey<>("HeartRate");
/**
+ * The data source key for heart rate sensor accuracy data from platform health sources. The
+ * accuracy value is one of {@code HEART_RATE_ACCURACY_*} constants.
+ */
+ @NonNull
+ @RequiresPermission(Manifest.permission.BODY_SENSORS)
+ public static final PlatformDataKey<DynamicHeartRateAccuracy> HEART_RATE_ACCURACY =
+ new PlatformDataKey<>("HeartRate Accuracy");
+ /**
* The data source key for daily step count data from platform health sources. This is the
* total step count over a day and it resets when 00:00 is reached (in whatever is the
* timezone set at that time). This can result in the DAILY period being greater than or
@@ -52,21 +99,21 @@
/**
* The data source key for daily distance data (in meters) from platform health sources.
- * This is the total distance over a day and it resets when 00:00 is reached (in whatever
- * is the timezone set at that time). This can result in the DAILY period being greater
- * than or less than 24 hours when the timezone of the device is changed.
+ * This is the total distance over a day and it resets when 00:00 is reached (in whatever is
+ * the timezone set at that time). This can result in the DAILY period being greater than or
+ * less than 24 hours when the timezone of the device is changed.
*/
@NonNull
@RequiresPermission(Manifest.permission.ACTIVITY_RECOGNITION)
- public static final PlatformDataKey<DynamicFloat> DAILY_DISTANCE_M =
+ public static final PlatformDataKey<DynamicFloat> DAILY_DISTANCE_METERS =
new PlatformDataKey<>("Daily Distance");
/**
* The data source key for daily calories data from platform health sources. This is the
* total number of calories over a day (including both BMR and active calories) and it
* resets when 00:00 is reached (in whatever is the timezone set at that time). This can
- * result in the DAILY period being greater than or less than 24 hours when the timezone
- * of the device is changed.
+ * result in the DAILY period being greater than or less than 24 hours when the timezone of
+ * the device is changed.
*/
@NonNull
@RequiresPermission(Manifest.permission.ACTIVITY_RECOGNITION)
@@ -75,9 +122,9 @@
/**
* The data source key for daily floors data from platform health sources. This is the total
- * number of floors climbed over a day and it resets when 00:00 is reached (in whatever
- * is the timezone set at that time). This can result in the DAILY period being greater
- * than or less than 24 hours when the timezone of the device is changed.
+ * number of floors climbed over a day and it resets when 00:00 is reached (in whatever is
+ * the timezone set at that time). This can result in the DAILY period being greater than or
+ * less than 24 hours when the timezone of the device is changed.
*/
@NonNull
@RequiresPermission(Manifest.permission.ACTIVITY_RECOGNITION)
@@ -103,10 +150,26 @@
}
/**
+ * Creates a {@link DynamicHeartRateAccuracy} which receives the current heat rate sensor
+ * accuracy from platform sources.
+ *
+ * <p>The accuracy value is one of {@link DynamicHeartRateAccuracy} constants.
+ */
+ @RequiresPermission(Manifest.permission.BODY_SENSORS)
+ @NonNull
+ public static DynamicHeartRateAccuracy heartRateAccuracy() {
+ return new DynamicHeartRateAccuracy(
+ new DynamicBuilders.StateInt32Source.Builder()
+ .setSourceKey(Keys.HEART_RATE_ACCURACY.getKey())
+ .setSourceNamespace(Keys.HEART_RATE_ACCURACY.getNamespace())
+ .build());
+ }
+
+ /**
* Creates a {@link DynamicInt32} which receives the current daily steps from platform health
* sources. This is the total step count over a day and it resets when 00:00 is reached (in
- * whatever is the timezone set at that time). This can result in the DAILY period being
- * greater than or less than 24 hours when the timezone of the device is changed.
+ * whatever is the timezone set at that time). This can result in the DAILY period being greater
+ * than or less than 24 hours when the timezone of the device is changed.
*
* <p>This method provides backward compatibility and is preferred over using {@link
* Keys#DAILY_STEPS} directly.
@@ -122,8 +185,8 @@
/**
* Creates a {@link DynamicFloat} which receives the current daily floors from platform health
* sources. This is the total number of floors climbed over a day and it resets when 00:00 is
- * reached (in whatever is the timezone set at that time). This can result in the DAILY
- * period being greater than or less than 24 hours when the timezone of the device is changed.
+ * reached (in whatever is the timezone set at that time). This can result in the DAILY period
+ * being greater than or less than 24 hours when the timezone of the device is changed.
*/
@RequiresPermission(Manifest.permission.ACTIVITY_RECOGNITION)
@NonNull
@@ -134,9 +197,9 @@
/**
* Creates a {@link DynamicFloat} which receives the current daily calories from platform health
* sources. This is the total number of calories over a day (including both BMR and active
- * calories) and it resets when 00:00 is reached (in whatever is the timezone set at that
- * time). This can result in the DAILY period being greater than or less than 24 hours when
- * the timezone of the device is changed.
+ * calories) and it resets when 00:00 is reached (in whatever is the timezone set at that time).
+ * This can result in the DAILY period being greater than or less than 24 hours when the
+ * timezone of the device is changed.
*/
@RequiresPermission(Manifest.permission.ACTIVITY_RECOGNITION)
@NonNull
@@ -146,14 +209,65 @@
/**
* Creates a {@link DynamicFloat} which receives the current daily distance expressed in meters
- * from platform health sources. This is the total distance over a day and it resets when
- * 00:00 is reached (in whatever is the timezone set at that time). This can result in the
- * DAILY period being greater than or less than 24 hours when the timezone of the device is
- * changed.
+ * from platform health sources. This is the total distance over a day and it resets when 00:00
+ * is reached (in whatever is the timezone set at that time). This can result in the DAILY
+ * period being greater than or less than 24 hours when the timezone of the device is changed.
*/
@RequiresPermission(Manifest.permission.ACTIVITY_RECOGNITION)
@NonNull
- public static DynamicFloat dailyDistanceM() {
- return DynamicFloat.from(Keys.DAILY_DISTANCE_M);
+ public static DynamicFloat dailyDistanceMeters() {
+ return DynamicFloat.from(Keys.DAILY_DISTANCE_METERS);
+ }
+
+ /** Dynamic heart rate sensor accuracy value. */
+ public static final class DynamicHeartRateAccuracy implements DynamicInt32 {
+ private final DynamicInt32 mImpl;
+
+ DynamicHeartRateAccuracy(DynamicInt32 impl) {
+ this.mImpl = impl;
+ }
+
+ private DynamicHeartRateAccuracy(int val) {
+ this(DynamicInt32.constant(val));
+ }
+
+ /** The accuracy is unknown. */
+ @NonNull
+ public static final DynamicHeartRateAccuracy UNKNOWN =
+ new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_UNKNOWN_VALUE);
+ /** The heart rate cannot be acquired because the sensor is not properly contacting skin. */
+ @NonNull
+ public static final DynamicHeartRateAccuracy NO_CONTACT =
+ new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_NO_CONTACT_VALUE);
+ /** Heart rate data is currently too unreliable to be used. */
+ @NonNull
+ public static final DynamicHeartRateAccuracy UNRELIABLE =
+ new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_UNRELIABLE_VALUE);
+ /** Heart rate data is available but the accuracy is low. */
+ @NonNull
+ public static final DynamicHeartRateAccuracy LOW =
+ new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_LOW_VALUE);
+ /** Heart rate data is available and the accuracy is medium. */
+ @NonNull
+ public static final DynamicHeartRateAccuracy MEDIUM =
+ new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_MEDIUM_VALUE);
+ /** Heart rate data is available with high accuracy. */
+ @NonNull
+ public static final DynamicHeartRateAccuracy HIGH =
+ new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_HIGH_VALUE);
+
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ @Override
+ public DynamicProto.DynamicInt32 toDynamicInt32Proto() {
+ return mImpl.toDynamicInt32Proto();
+ }
+
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public Fingerprint getFingerprint() {
+ return mImpl.getFingerprint();
+ }
}
}
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/VersionBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/VersionBuilders.java
index 5a1f126..0c69edf 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/VersionBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/VersionBuilders.java
@@ -61,19 +61,14 @@
return mImpl.getMinor();
}
- /**
- * Get the fingerprint for this object, or null if unknown.
- *
- */
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static VersionInfo fromProto(
@@ -84,7 +79,6 @@
/**
* Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
* created using this method can't be added to any other wrapper.
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@@ -92,10 +86,7 @@
return fromProto(proto, null);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public VersionProto.VersionInfo toProto() {
diff --git a/wear/protolayout/protolayout-material/api/current.txt b/wear/protolayout/protolayout-material/api/current.txt
index 64cf2bf..2ee3d02 100644
--- a/wear/protolayout/protolayout-material/api/current.txt
+++ b/wear/protolayout/protolayout-material/api/current.txt
@@ -13,7 +13,7 @@
method public String? getTextContent();
}
- public static final class Button.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class Button.Builder {
ctor public Button.Builder(android.content.Context, androidx.wear.protolayout.ModifiersBuilders.Clickable);
method public androidx.wear.protolayout.material.Button build();
method public androidx.wear.protolayout.material.Button.Builder setButtonColors(androidx.wear.protolayout.material.ButtonColors);
@@ -62,7 +62,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension getWidth();
}
- public static final class Chip.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class Chip.Builder {
ctor public Chip.Builder(android.content.Context, androidx.wear.protolayout.ModifiersBuilders.Clickable, androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
method public androidx.wear.protolayout.material.Chip build();
method public androidx.wear.protolayout.material.Chip.Builder setChipColors(androidx.wear.protolayout.material.ChipColors);
@@ -109,7 +109,7 @@
method public androidx.wear.protolayout.DimensionBuilders.DpProp getStrokeWidth();
}
- public static final class CircularProgressIndicator.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class CircularProgressIndicator.Builder {
ctor public CircularProgressIndicator.Builder();
method public androidx.wear.protolayout.material.CircularProgressIndicator build();
method public androidx.wear.protolayout.material.CircularProgressIndicator.Builder setCircularProgressIndicatorColors(androidx.wear.protolayout.material.ProgressIndicatorColors);
@@ -137,12 +137,14 @@
method public androidx.wear.protolayout.material.ChipColors getChipColors();
method public androidx.wear.protolayout.ModifiersBuilders.Clickable getClickable();
method public String getText();
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public boolean hasExcludeFontPadding();
}
- public static final class CompactChip.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class CompactChip.Builder {
ctor public CompactChip.Builder(android.content.Context, String, androidx.wear.protolayout.ModifiersBuilders.Clickable, androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
method public androidx.wear.protolayout.material.CompactChip build();
method public androidx.wear.protolayout.material.CompactChip.Builder setChipColors(androidx.wear.protolayout.material.ChipColors);
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.material.CompactChip.Builder setExcludeFontPadding(boolean);
}
public class ProgressIndicatorColors {
@@ -163,7 +165,6 @@
public class Text implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
method public static androidx.wear.protolayout.material.Text? fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.ColorBuilders.ColorProp getColor();
- method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public boolean getExcludeFontPadding();
method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle getFontStyle();
method public float getLineHeight();
method public int getMaxLines();
@@ -172,11 +173,12 @@
method public int getOverflow();
method public androidx.wear.protolayout.TypeBuilders.StringProp getText();
method public int getWeight();
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public boolean hasExcludeFontPadding();
method public boolean isItalic();
method public boolean isUnderline();
}
- public static final class Text.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class Text.Builder {
ctor public Text.Builder(android.content.Context, androidx.wear.protolayout.TypeBuilders.StringProp, androidx.wear.protolayout.TypeBuilders.StringLayoutConstraint);
ctor public Text.Builder(android.content.Context, String);
method public androidx.wear.protolayout.material.Text build();
@@ -199,12 +201,14 @@
method public int getHorizontalAlignment();
method public String getText();
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension getWidth();
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public boolean hasExcludeFontPadding();
}
- public static final class TitleChip.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class TitleChip.Builder {
ctor public TitleChip.Builder(android.content.Context, String, androidx.wear.protolayout.ModifiersBuilders.Clickable, androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
method public androidx.wear.protolayout.material.TitleChip build();
method public androidx.wear.protolayout.material.TitleChip.Builder setChipColors(androidx.wear.protolayout.material.ChipColors);
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.material.TitleChip.Builder setExcludeFontPadding(boolean);
method public androidx.wear.protolayout.material.TitleChip.Builder setHorizontalAlignment(int);
method public androidx.wear.protolayout.material.TitleChip.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
method public androidx.wear.protolayout.material.TitleChip.Builder setWidth(@Dimension(unit=androidx.annotation.Dimension.DP) float);
@@ -237,7 +241,7 @@
method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement? getSecondaryLabelTextContent();
}
- public static final class EdgeContentLayout.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class EdgeContentLayout.Builder {
ctor public EdgeContentLayout.Builder(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
method public androidx.wear.protolayout.material.layouts.EdgeContentLayout build();
method public androidx.wear.protolayout.material.layouts.EdgeContentLayout.Builder setContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
@@ -255,10 +259,10 @@
}
public static final class LayoutDefaults.MultiButtonLayoutDefaults {
- field public static final int BUTTON_MAX_NUMBER = 7; // 0x7
field public static final androidx.wear.protolayout.DimensionBuilders.DpProp BUTTON_SIZE_FOR_1_BUTTON;
field public static final androidx.wear.protolayout.DimensionBuilders.DpProp BUTTON_SIZE_FOR_2_BUTTONS;
field public static final androidx.wear.protolayout.DimensionBuilders.DpProp BUTTON_SIZE_FOR_3_PLUS_BUTTONS;
+ field public static final int MAX_BUTTONS = 7; // 0x7
}
public class MultiButtonLayout implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
@@ -269,7 +273,7 @@
field public static final int FIVE_BUTTON_DISTRIBUTION_TOP_HEAVY = 1; // 0x1
}
- public static final class MultiButtonLayout.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class MultiButtonLayout.Builder {
ctor public MultiButtonLayout.Builder();
method public androidx.wear.protolayout.material.layouts.MultiButtonLayout.Builder addButtonContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.material.layouts.MultiButtonLayout build();
@@ -282,7 +286,7 @@
method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getSlotContents();
}
- public static final class MultiSlotLayout.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class MultiSlotLayout.Builder {
ctor public MultiSlotLayout.Builder();
method public androidx.wear.protolayout.material.layouts.MultiSlotLayout.Builder addSlotContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.material.layouts.MultiSlotLayout build();
@@ -298,7 +302,7 @@
method @Dimension(unit=androidx.annotation.Dimension.DP) public float getVerticalSpacerHeight();
}
- public static final class PrimaryLayout.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class PrimaryLayout.Builder {
ctor public PrimaryLayout.Builder(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
method public androidx.wear.protolayout.material.layouts.PrimaryLayout build();
method public androidx.wear.protolayout.material.layouts.PrimaryLayout.Builder setContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
diff --git a/wear/protolayout/protolayout-material/api/restricted_current.txt b/wear/protolayout/protolayout-material/api/restricted_current.txt
index 64cf2bf..2ee3d02 100644
--- a/wear/protolayout/protolayout-material/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-material/api/restricted_current.txt
@@ -13,7 +13,7 @@
method public String? getTextContent();
}
- public static final class Button.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class Button.Builder {
ctor public Button.Builder(android.content.Context, androidx.wear.protolayout.ModifiersBuilders.Clickable);
method public androidx.wear.protolayout.material.Button build();
method public androidx.wear.protolayout.material.Button.Builder setButtonColors(androidx.wear.protolayout.material.ButtonColors);
@@ -62,7 +62,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension getWidth();
}
- public static final class Chip.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class Chip.Builder {
ctor public Chip.Builder(android.content.Context, androidx.wear.protolayout.ModifiersBuilders.Clickable, androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
method public androidx.wear.protolayout.material.Chip build();
method public androidx.wear.protolayout.material.Chip.Builder setChipColors(androidx.wear.protolayout.material.ChipColors);
@@ -109,7 +109,7 @@
method public androidx.wear.protolayout.DimensionBuilders.DpProp getStrokeWidth();
}
- public static final class CircularProgressIndicator.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class CircularProgressIndicator.Builder {
ctor public CircularProgressIndicator.Builder();
method public androidx.wear.protolayout.material.CircularProgressIndicator build();
method public androidx.wear.protolayout.material.CircularProgressIndicator.Builder setCircularProgressIndicatorColors(androidx.wear.protolayout.material.ProgressIndicatorColors);
@@ -137,12 +137,14 @@
method public androidx.wear.protolayout.material.ChipColors getChipColors();
method public androidx.wear.protolayout.ModifiersBuilders.Clickable getClickable();
method public String getText();
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public boolean hasExcludeFontPadding();
}
- public static final class CompactChip.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class CompactChip.Builder {
ctor public CompactChip.Builder(android.content.Context, String, androidx.wear.protolayout.ModifiersBuilders.Clickable, androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
method public androidx.wear.protolayout.material.CompactChip build();
method public androidx.wear.protolayout.material.CompactChip.Builder setChipColors(androidx.wear.protolayout.material.ChipColors);
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.material.CompactChip.Builder setExcludeFontPadding(boolean);
}
public class ProgressIndicatorColors {
@@ -163,7 +165,6 @@
public class Text implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
method public static androidx.wear.protolayout.material.Text? fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.ColorBuilders.ColorProp getColor();
- method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public boolean getExcludeFontPadding();
method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle getFontStyle();
method public float getLineHeight();
method public int getMaxLines();
@@ -172,11 +173,12 @@
method public int getOverflow();
method public androidx.wear.protolayout.TypeBuilders.StringProp getText();
method public int getWeight();
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public boolean hasExcludeFontPadding();
method public boolean isItalic();
method public boolean isUnderline();
}
- public static final class Text.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class Text.Builder {
ctor public Text.Builder(android.content.Context, androidx.wear.protolayout.TypeBuilders.StringProp, androidx.wear.protolayout.TypeBuilders.StringLayoutConstraint);
ctor public Text.Builder(android.content.Context, String);
method public androidx.wear.protolayout.material.Text build();
@@ -199,12 +201,14 @@
method public int getHorizontalAlignment();
method public String getText();
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension getWidth();
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public boolean hasExcludeFontPadding();
}
- public static final class TitleChip.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class TitleChip.Builder {
ctor public TitleChip.Builder(android.content.Context, String, androidx.wear.protolayout.ModifiersBuilders.Clickable, androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
method public androidx.wear.protolayout.material.TitleChip build();
method public androidx.wear.protolayout.material.TitleChip.Builder setChipColors(androidx.wear.protolayout.material.ChipColors);
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.material.TitleChip.Builder setExcludeFontPadding(boolean);
method public androidx.wear.protolayout.material.TitleChip.Builder setHorizontalAlignment(int);
method public androidx.wear.protolayout.material.TitleChip.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
method public androidx.wear.protolayout.material.TitleChip.Builder setWidth(@Dimension(unit=androidx.annotation.Dimension.DP) float);
@@ -237,7 +241,7 @@
method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement? getSecondaryLabelTextContent();
}
- public static final class EdgeContentLayout.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class EdgeContentLayout.Builder {
ctor public EdgeContentLayout.Builder(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
method public androidx.wear.protolayout.material.layouts.EdgeContentLayout build();
method public androidx.wear.protolayout.material.layouts.EdgeContentLayout.Builder setContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
@@ -255,10 +259,10 @@
}
public static final class LayoutDefaults.MultiButtonLayoutDefaults {
- field public static final int BUTTON_MAX_NUMBER = 7; // 0x7
field public static final androidx.wear.protolayout.DimensionBuilders.DpProp BUTTON_SIZE_FOR_1_BUTTON;
field public static final androidx.wear.protolayout.DimensionBuilders.DpProp BUTTON_SIZE_FOR_2_BUTTONS;
field public static final androidx.wear.protolayout.DimensionBuilders.DpProp BUTTON_SIZE_FOR_3_PLUS_BUTTONS;
+ field public static final int MAX_BUTTONS = 7; // 0x7
}
public class MultiButtonLayout implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
@@ -269,7 +273,7 @@
field public static final int FIVE_BUTTON_DISTRIBUTION_TOP_HEAVY = 1; // 0x1
}
- public static final class MultiButtonLayout.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class MultiButtonLayout.Builder {
ctor public MultiButtonLayout.Builder();
method public androidx.wear.protolayout.material.layouts.MultiButtonLayout.Builder addButtonContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.material.layouts.MultiButtonLayout build();
@@ -282,7 +286,7 @@
method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getSlotContents();
}
- public static final class MultiSlotLayout.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class MultiSlotLayout.Builder {
ctor public MultiSlotLayout.Builder();
method public androidx.wear.protolayout.material.layouts.MultiSlotLayout.Builder addSlotContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.material.layouts.MultiSlotLayout build();
@@ -298,7 +302,7 @@
method @Dimension(unit=androidx.annotation.Dimension.DP) public float getVerticalSpacerHeight();
}
- public static final class PrimaryLayout.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class PrimaryLayout.Builder {
ctor public PrimaryLayout.Builder(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
method public androidx.wear.protolayout.material.layouts.PrimaryLayout build();
method public androidx.wear.protolayout.material.layouts.PrimaryLayout.Builder setContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
diff --git a/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/TestCasesGenerator.java b/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/TestCasesGenerator.java
index 3653dc9..f508a0c 100644
--- a/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/TestCasesGenerator.java
+++ b/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/TestCasesGenerator.java
@@ -208,36 +208,53 @@
// more than 9, the rest will be deleted.
testCases.put(
"compactchip_default_len2_golden" + goldenSuffix,
- new CompactChip.Builder(context, "Ab", clickable, deviceParameters).build());
+ new CompactChip.Builder(context, "Ab", clickable, deviceParameters)
+ .setExcludeFontPadding(true)
+ .build());
testCases.put(
"compactchip_default_len5_golden" + goldenSuffix,
- new CompactChip.Builder(context, "Abcde", clickable, deviceParameters).build());
+ new CompactChip.Builder(context, "Abcde", clickable, deviceParameters)
+ .setExcludeFontPadding(true)
+ .build());
testCases.put(
"compactchip_default_len9_golden" + goldenSuffix,
- new CompactChip.Builder(context, "Abcdefghi", clickable, deviceParameters).build());
+ new CompactChip.Builder(context, "Abcdefghi", clickable, deviceParameters)
+ .setExcludeFontPadding(true)
+ .build());
testCases.put(
"compactchip_default_toolong_golden" + goldenSuffix,
new CompactChip.Builder(
context, "AbcdefghiEXTRAEXTRAEXTRA", clickable, deviceParameters)
+ .setExcludeFontPadding(true)
.build());
testCases.put(
"compactchip_custom_default_golden" + goldenSuffix,
new CompactChip.Builder(context, "Action", clickable, deviceParameters)
.setChipColors(new ChipColors(Color.YELLOW, Color.BLACK))
+ .setExcludeFontPadding(true)
+ .build());
+ testCases.put(
+ "compactchip_includepadding_default_golden" + goldenSuffix,
+ new CompactChip.Builder(context, "Action", clickable, deviceParameters)
+ .setExcludeFontPadding(false)
.build());
testCases.put(
"titlechip_default_golden" + goldenSuffix,
- new TitleChip.Builder(context, largeChipText, clickable, deviceParameters).build());
+ new TitleChip.Builder(context, largeChipText, clickable, deviceParameters)
+ .setExcludeFontPadding(true)
+ .build());
testCases.put(
"titlechip_default_texttoolong_golden" + goldenSuffix,
new TitleChip.Builder(context, "abcdeabcdeabcdeEXTRA", clickable, deviceParameters)
+ .setExcludeFontPadding(true)
.build());
testCases.put(
"titlechip_leftalign_secondary_default_golden" + goldenSuffix,
new TitleChip.Builder(context, largeChipText, clickable, deviceParameters)
.setHorizontalAlignment(HORIZONTAL_ALIGN_START)
.setChipColors(ChipDefaults.TITLE_SECONDARY_COLORS)
+ .setExcludeFontPadding(true)
.build());
testCases.put(
"titlechip_centered_custom_150_secondary_default_golden" + goldenSuffix,
@@ -245,6 +262,12 @@
.setHorizontalAlignment(HORIZONTAL_ALIGN_CENTER)
.setChipColors(new ChipColors(Color.YELLOW, Color.BLUE))
.setWidth(150)
+ .setExcludeFontPadding(true)
+ .build());
+ testCases.put(
+ "titlechip_includepadding_default_golden" + goldenSuffix,
+ new TitleChip.Builder(context, largeChipText, clickable, deviceParameters)
+ .setExcludeFontPadding(false)
.build());
testCases.put(
diff --git a/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/layouts/TestCasesGenerator.java b/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/layouts/TestCasesGenerator.java
index e95c9da..02bd273 100644
--- a/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/layouts/TestCasesGenerator.java
+++ b/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/layouts/TestCasesGenerator.java
@@ -75,9 +75,12 @@
HashMap<String, LayoutElement> testCases = new HashMap<>();
TitleChip content =
- new TitleChip.Builder(context, "Action", clickable, deviceParameters).build();
+ new TitleChip.Builder(context, "Action", clickable, deviceParameters)
+ .setExcludeFontPadding(true)
+ .build();
CompactChip.Builder primaryChipBuilder =
- new CompactChip.Builder(context, "Action", clickable, deviceParameters);
+ new CompactChip.Builder(context, "Action", clickable, deviceParameters)
+ .setExcludeFontPadding(true);
testCases.put(
"default_empty_primarychiplayout_golden" + goldenSuffix,
@@ -93,6 +96,7 @@
"Too_long_textToo_long_textToo_long_text",
clickable,
deviceParameters)
+ .setExcludeFontPadding(true)
.build())
.build());
testCases.put(
@@ -162,7 +166,8 @@
.build());
primaryChipBuilder =
- new CompactChip.Builder(context, "Action", clickable, deviceParameters);
+ new CompactChip.Builder(context, "Action", clickable, deviceParameters)
+ .setExcludeFontPadding(true);
testCases.put(
"coloredbox_1_chip_columnslayout_golden" + goldenSuffix,
new PrimaryLayout.Builder(deviceParameters)
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
index d4e15b1..d0efe27 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
@@ -26,6 +26,8 @@
import static androidx.wear.protolayout.material.ChipDefaults.HORIZONTAL_PADDING;
import static androidx.wear.protolayout.material.ChipDefaults.ICON_SIZE;
import static androidx.wear.protolayout.material.ChipDefaults.ICON_SPACER_WIDTH;
+import static androidx.wear.protolayout.material.ChipDefaults.MIN_TAPPABLE_HEIGHT;
+import static androidx.wear.protolayout.material.ChipDefaults.MIN_TAPPABLE_WIDTH;
import static androidx.wear.protolayout.material.ChipDefaults.PRIMARY_COLORS;
import static androidx.wear.protolayout.material.Helper.checkNotNull;
import static androidx.wear.protolayout.material.Helper.checkTag;
@@ -33,18 +35,22 @@
import static androidx.wear.protolayout.material.Helper.getTagBytes;
import static androidx.wear.protolayout.material.Helper.radiusOf;
+import static java.lang.Math.max;
+
import android.content.Context;
import androidx.annotation.Dimension;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.wear.protolayout.ColorBuilders.ColorProp;
import androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters;
import androidx.wear.protolayout.DimensionBuilders.ContainerDimension;
import androidx.wear.protolayout.DimensionBuilders.DpProp;
+import androidx.wear.protolayout.DimensionBuilders.WrappedDimensionProp;
import androidx.wear.protolayout.LayoutElementBuilders;
import androidx.wear.protolayout.LayoutElementBuilders.Box;
import androidx.wear.protolayout.LayoutElementBuilders.ColorFilter;
@@ -63,6 +69,7 @@
import androidx.wear.protolayout.ModifiersBuilders.Semantics;
import androidx.wear.protolayout.TypeBuilders.StringProp;
import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.expression.ProtoLayoutExperimental;
import androidx.wear.protolayout.material.Typography.TypographyName;
import androidx.wear.protolayout.proto.LayoutElementProto;
@@ -75,10 +82,11 @@
* ProtoLayout component {@link Chip} that represents clickable object with the text, optional label
* and optional icon or with custom content.
*
- * <p>The Chip is Stadium shape and has a max height designed to take no more than two lines of text
- * of {@link Typography#TYPOGRAPHY_BUTTON} style. The {@link Chip} can have an icon horizontally
- * parallel to the two lines of text. Width of chip can very, and the recommended size is screen
- * dependent with the recommended margin being applied.
+ * <p>The Chip is Stadium shape that has a max height designed to take no more than two lines of
+ * text of {@link Typography#TYPOGRAPHY_BUTTON} style and with minimum tap target to meet
+ * accessibility requirements. The {@link Chip} can have an icon horizontally parallel to the two
+ * lines of text. Width of chip can very, and the recommended size is screen dependent with the
+ * recommended margin being applied.
*
* <p>The recommended set of {@link ChipColors} styles can be obtained from {@link ChipDefaults}.,
* e.g. {@link ChipDefaults#PRIMARY_COLORS} to get a color scheme for a primary {@link Chip}.
@@ -118,11 +126,17 @@
*/
static final String METADATA_TAG_CUSTOM_CONTENT = "CSTCHP";
+ /** Outer tappable Box. */
+ @NonNull private final Box mImpl;
+
+ /** Inner visible Box with all Chip elements. */
@NonNull private final Box mElement;
- Chip(@NonNull Box element) {
- mElement = element;
+ Chip(@NonNull Box impl) {
+ mImpl = impl;
+ mElement = (Box) impl.getContents().get(0);
}
+
/** Builder class for {@link androidx.wear.protolayout.material.Chip}. */
public static final class Builder implements LayoutElement.Builder {
private static final int NOT_SET = 0;
@@ -149,6 +163,7 @@
@TypographyName private int mPrimaryLabelTypography;
@NonNull private DpProp mHorizontalPadding = HORIZONTAL_PADDING;
private boolean mIsScalable = true;
+ private boolean mIsFontPaddingExcluded = false;
private int mMaxLines = 0; // 0 indicates that is not set.
@NonNull private String mMetadataTag = "";
@@ -274,6 +289,22 @@
}
/**
+ * Sets whether the font padding for the primary label is excluded.
+ *
+ * <p>It should be used for creating CompactChip and TitleChip to make the label vertically
+ * aligned. Shouldn't be used if there is anything else in chip besides primary label.
+ *
+ * @see Text.Builder#setExcludeFontPadding
+ */
+ @NonNull
+ @ProtoLayoutExperimental
+ @SuppressWarnings("MissingGetterMatchingBuilder")
+ Builder setPrimaryLabelExcludeFontPadding(boolean excluded) {
+ this.mIsFontPaddingExcluded = excluded;
+ return this;
+ }
+
+ /**
* Sets the secondary label for the {@link Chip}. Any previously added custom content will
* be overridden. If secondary label is set, primary label must be set too with {@link
* #setPrimaryLabelContent}.
@@ -357,7 +388,6 @@
public Chip build() {
Modifiers.Builder modifiers =
new Modifiers.Builder()
- .setClickable(mClickable)
.setPadding(
new Padding.Builder()
.setStart(mHorizontalPadding)
@@ -370,25 +400,56 @@
new Corner.Builder()
.setRadius(radiusOf(mHeight))
.build())
- .build())
- .setMetadata(
- new ElementMetadata.Builder()
- .setTagData(getTagBytes(getCorrectMetadataTag()))
- .build())
- .setSemantics(
- new Semantics.Builder()
- .setContentDescription(getCorrectContentDescription())
.build());
- Box.Builder element =
+ Box.Builder visible =
new Box.Builder()
- .setWidth(mWidth)
.setHeight(mHeight)
+ .setWidth(mWidth)
.setHorizontalAlignment(getCorrectHorizontalAlignment())
.addContent(getCorrectContent())
.setModifiers(modifiers.build());
- return new Chip(element.build());
+ Box tappable =
+ new Box.Builder()
+ .setWidth(resolveMinTappableWidth())
+ .setHeight(dp(resolveMinTappableHeight()))
+ .setModifiers(
+ new Modifiers.Builder()
+ .setClickable(mClickable)
+ .setMetadata(
+ new ElementMetadata.Builder()
+ .setTagData(
+ getTagBytes(
+ getCorrectMetadataTag())
+ )
+ .build())
+ .setSemantics(
+ new Semantics.Builder()
+ .setContentDescription(
+ getCorrectContentDescription())
+ .build())
+ .build())
+ .addContent(visible.build())
+ .build();
+
+ return new Chip(tappable);
+ }
+
+ private ContainerDimension resolveMinTappableWidth() {
+ if (mWidth instanceof DpProp) {
+ return dp(max(((DpProp) mWidth).getValue(), MIN_TAPPABLE_WIDTH.getValue()));
+ } else if (mWidth instanceof WrappedDimensionProp) {
+ return new WrappedDimensionProp.Builder()
+ .setMinimumSize(MIN_TAPPABLE_WIDTH)
+ .build();
+ } else {
+ return mWidth;
+ }
+ }
+
+ private float resolveMinTappableHeight() {
+ return max(mHeight.getValue(), MIN_TAPPABLE_HEIGHT.getValue());
}
@NonNull
@@ -434,6 +495,7 @@
}
@NonNull
+ @OptIn(markerClass = ProtoLayoutExperimental.class)
private LayoutElement getCorrectContent() {
if (mCustomContent != null) {
return mCustomContent;
@@ -447,6 +509,7 @@
.setOverflow(LayoutElementBuilders.TEXT_OVERFLOW_ELLIPSIZE_END)
.setMultilineAlignment(LayoutElementBuilders.TEXT_ALIGN_START)
.setIsScalable(mIsScalable)
+ .setExcludeFontPadding(mIsFontPaddingExcluded)
.build();
// Placeholder for text.
@@ -506,7 +569,7 @@
}
}
- /** Returns height of this Chip. */
+ /** Returns the visible height of this Chip. */
@NonNull
public ContainerDimension getHeight() {
return checkNotNull(mElement.getHeight());
@@ -521,7 +584,7 @@
/** Returns click event action associated with this Chip. */
@NonNull
public Clickable getClickable() {
- return checkNotNull(checkNotNull(mElement.getModifiers()).getClickable());
+ return checkNotNull(checkNotNull(mImpl.getModifiers()).getClickable());
}
/** Returns background color of this Chip. */
@@ -569,7 +632,7 @@
/** Returns content description of this Chip. */
@Nullable
public StringProp getContentDescription() {
- Semantics semantics = checkNotNull(mElement.getModifiers()).getSemantics();
+ Semantics semantics = checkNotNull(mImpl.getModifiers()).getSemantics();
if (semantics == null) {
return null;
}
@@ -659,8 +722,16 @@
/** Returns metadata tag set to this Chip. */
@NonNull
String getMetadataTag() {
- return getMetadataTagName(
- checkNotNull(checkNotNull(mElement.getModifiers()).getMetadata()));
+ return getMetadataTagName(checkNotNull(checkNotNull(mImpl.getModifiers()).getMetadata()));
+ }
+
+ /**
+ * Returns whether the font padding for the primary label is excluded.
+ */
+ @ProtoLayoutExperimental
+ boolean hasPrimaryLabelExcludeFontPadding() {
+ Text primaryLabel = getPrimaryLabelContentObject();
+ return primaryLabel != null && primaryLabel.hasExcludeFontPadding();
}
/**
@@ -688,13 +759,13 @@
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
public LayoutElementProto.LayoutElement toLayoutElementProto() {
- return mElement.toLayoutElementProto();
+ return mImpl.toLayoutElementProto();
}
@Nullable
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
public Fingerprint getFingerprint() {
- return mElement.getFingerprint();
+ return mImpl.getFingerprint();
}
}
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/ChipDefaults.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/ChipDefaults.java
index 2139050..18b54ba 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/ChipDefaults.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/ChipDefaults.java
@@ -44,12 +44,18 @@
public static final DpProp COMPACT_HEIGHT = dp(32);
/**
- * The default height of tappable area for standard {@link CompactChip}
- *
+ * The minimum width of tappable target area.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public static final DpProp COMPACT_HEIGHT_TAPPABLE = dp(48);
+ public static final DpProp MIN_TAPPABLE_WIDTH = dp(48);
+
+ /**
+ * The minimum height of tappable target area.
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public static final DpProp MIN_TAPPABLE_HEIGHT = dp(48);
/**
* The default height for standard {@link TitleChip}
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/CompactChip.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/CompactChip.java
index 840aa47..e969b18 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/CompactChip.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/CompactChip.java
@@ -19,9 +19,9 @@
import static androidx.wear.protolayout.DimensionBuilders.wrap;
import static androidx.wear.protolayout.LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER;
import static androidx.wear.protolayout.material.ChipDefaults.COMPACT_HEIGHT;
-import static androidx.wear.protolayout.material.ChipDefaults.COMPACT_HEIGHT_TAPPABLE;
import static androidx.wear.protolayout.material.ChipDefaults.COMPACT_HORIZONTAL_PADDING;
import static androidx.wear.protolayout.material.ChipDefaults.COMPACT_PRIMARY_COLORS;
+import static androidx.wear.protolayout.material.ChipDefaults.MIN_TAPPABLE_HEIGHT;
import static androidx.wear.protolayout.material.Helper.checkNotNull;
import static androidx.wear.protolayout.material.Helper.checkTag;
import static androidx.wear.protolayout.material.Helper.getTagBytes;
@@ -30,6 +30,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters;
@@ -40,14 +41,15 @@
import androidx.wear.protolayout.ModifiersBuilders.ElementMetadata;
import androidx.wear.protolayout.ModifiersBuilders.Modifiers;
import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.expression.ProtoLayoutExperimental;
import androidx.wear.protolayout.proto.LayoutElementProto;
/**
* ProtoLayout component {@link CompactChip} that represents clickable object with the text.
*
- * <p>The Chip is Stadium shape and has a max height designed to take no more than one line of text
- * of {@link Typography#TYPOGRAPHY_CAPTION1} style. Width of the chip is adjustable to the text
- * size.
+ * <p>The CompactChip is Stadium shape and has a max height designed to take no more than one line
+ * of text of {@link Typography#TYPOGRAPHY_CAPTION1} style. Width of the chip is adjustable to
+ * the text size.
*
* <p>The recommended set of {@link ChipColors} styles can be obtained from {@link ChipDefaults}.,
* e.g. {@link ChipDefaults#COMPACT_PRIMARY_COLORS} to get a color scheme for a primary {@link
@@ -76,13 +78,10 @@
/** Tool tag for Metadata in Modifiers, so we know that Box is actually a CompactChip. */
static final String METADATA_TAG = "CMPCHP";
- @NonNull private final Box mImpl;
@NonNull private final Chip mElement;
- CompactChip(@NonNull Box element) {
- this.mImpl = element;
- // We know for sure that content of the Box is Chip.
- this.mElement = new Chip((Box) element.getContents().get(0));
+ CompactChip(@NonNull Chip element) {
+ this.mElement = element;
}
/** Builder class for {@link androidx.wear.protolayout.material.CompactChip}. */
@@ -92,6 +91,7 @@
@NonNull private final Clickable mClickable;
@NonNull private final DeviceParameters mDeviceParameters;
@NonNull private ChipColors mChipColors = COMPACT_PRIMARY_COLORS;
+ private boolean mIsFontPaddingExcluded = false;
/**
* Creates a builder for the {@link CompactChip} with associated action and the given text
@@ -125,9 +125,24 @@
return this;
}
+ /**
+ * Sets whether the font padding is excluded or not. If not set, default to false, meaning
+ * that text will have font padding included.
+ *
+ * <p>Setting this to {@code true} will perfectly align the text label.
+ */
+ @NonNull
+ @ProtoLayoutExperimental
+ @SuppressWarnings("MissingGetterMatchingBuilder")
+ public Builder setExcludeFontPadding(boolean excluded) {
+ this.mIsFontPaddingExcluded = excluded;
+ return this;
+ }
+
/** Constructs and returns {@link CompactChip} with the provided content and look. */
@NonNull
@Override
+ @OptIn(markerClass = ProtoLayoutExperimental.class)
public CompactChip build() {
Chip.Builder chipBuilder =
new Chip.Builder(mContext, mClickable, mDeviceParameters)
@@ -141,25 +156,10 @@
.setHorizontalPadding(COMPACT_HORIZONTAL_PADDING)
.setPrimaryLabelContent(mText)
.setPrimaryLabelTypography(Typography.TYPOGRAPHY_CAPTION1)
+ .setPrimaryLabelExcludeFontPadding(mIsFontPaddingExcluded)
.setIsPrimaryLabelScalable(false);
- Box tappableChip =
- new Box.Builder()
- .setModifiers(
- new Modifiers.Builder()
- .setClickable(mClickable)
- .setMetadata(
- new ElementMetadata.Builder()
- .setTagData(getTagBytes(METADATA_TAG))
- .build())
- .build())
- .setWidth(wrap())
- .setHeight(COMPACT_HEIGHT_TAPPABLE)
- .setVerticalAlignment(LayoutElementBuilders.VERTICAL_ALIGN_CENTER)
- .addContent(chipBuilder.build())
- .build();
-
- return new CompactChip(tappableChip);
+ return new CompactChip(chipBuilder.build());
}
}
@@ -204,31 +204,30 @@
if (!checkTag(boxElement.getModifiers(), METADATA_TAG)) {
return null;
}
- // Now to check that inner content of the Box is CompactChip's Chip.
- LayoutElement innerElement = boxElement.getContents().get(0);
- if (!(innerElement instanceof Box)) {
- return null;
- }
- Box innerBoxElement = (Box) innerElement;
- if (!checkTag(innerBoxElement.getModifiers(), METADATA_TAG)) {
- return null;
- }
// Now we are sure that this element is a CompactChip.
- return new CompactChip(boxElement);
+ return new CompactChip(new Chip(boxElement));
+ }
+
+ /**
+ * Returns whether the font padding for the primary label is excluded.
+ */
+ @ProtoLayoutExperimental
+ public boolean hasExcludeFontPadding() {
+ return mElement.hasPrimaryLabelExcludeFontPadding();
}
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@Override
public LayoutElementProto.LayoutElement toLayoutElementProto() {
- return mImpl.toLayoutElementProto();
+ return mElement.toLayoutElementProto();
}
@Nullable
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
public Fingerprint getFingerprint() {
- return mImpl.getFingerprint();
+ return mElement.getFingerprint();
}
}
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
index c9d8575..eb8d641 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
@@ -25,7 +25,6 @@
import static androidx.wear.protolayout.material.Typography.getFontStyleBuilder;
import static androidx.wear.protolayout.material.Typography.getLineHeightForTypography;
-import android.annotation.SuppressLint;
import android.content.Context;
import androidx.annotation.IntRange;
@@ -230,8 +229,8 @@
// other impacted UI Libraries - needs care as will have an impact on layout and needs to be
// communicated clearly.
@NonNull
- @SuppressLint("MissingGetterMatchingBuilder")
@ProtoLayoutExperimental
+ @SuppressWarnings("MissingGetterMatchingBuilder")
public Builder setExcludeFontPadding(boolean excludeFontPadding) {
this.mElementBuilder.setAndroidTextStyle(
new LayoutElementBuilders.AndroidTextStyle.Builder()
@@ -326,7 +325,7 @@
* excluded.
*/
@ProtoLayoutExperimental
- public boolean getExcludeFontPadding() {
+ public boolean hasExcludeFontPadding() {
return checkNotNull(mText.getAndroidTextStyle()).getExcludeFontPadding();
}
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/TitleChip.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/TitleChip.java
index dc7ee6e..46e2cec 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/TitleChip.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/TitleChip.java
@@ -30,6 +30,7 @@
import androidx.annotation.Dimension;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters;
@@ -39,6 +40,7 @@
import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement;
import androidx.wear.protolayout.ModifiersBuilders.Clickable;
import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.expression.ProtoLayoutExperimental;
import androidx.wear.protolayout.proto.LayoutElementProto;
/**
@@ -95,6 +97,7 @@
// Indicates that the width isn't set, so it will be automatically set by Chip.Builder
// constructor.
@Nullable private ContainerDimension mWidth = null;
+ private boolean mIsFontPaddingExcluded = false;
/**
* Creates a builder for the {@link TitleChip} with associated action and the given text
@@ -156,9 +159,24 @@
return this;
}
+ /**
+ * Sets whether the font padding is excluded or not. If not set, default to false, meaning
+ * that text will have font padding included.
+ *
+ * <p>Setting this to {@code true} will perfectly align the text label.
+ */
+ @NonNull
+ @ProtoLayoutExperimental
+ @SuppressWarnings("MissingGetterMatchingBuilder")
+ public Builder setExcludeFontPadding(boolean excluded) {
+ this.mIsFontPaddingExcluded = excluded;
+ return this;
+ }
+
/** Constructs and returns {@link TitleChip} with the provided content and look. */
@NonNull
@Override
+ @OptIn(markerClass = ProtoLayoutExperimental.class)
public TitleChip build() {
Chip.Builder chipBuilder =
new Chip.Builder(mContext, mClickable, mDeviceParameters)
@@ -171,6 +189,7 @@
.setHorizontalPadding(TITLE_HORIZONTAL_PADDING)
.setPrimaryLabelContent(mText)
.setPrimaryLabelTypography(Typography.TYPOGRAPHY_TITLE2)
+ .setPrimaryLabelExcludeFontPadding(mIsFontPaddingExcluded)
.setIsPrimaryLabelScalable(false);
if (mWidth != null) {
@@ -238,6 +257,14 @@
return new TitleChip(new Chip(boxElement));
}
+ /**
+ * Returns whether the font padding for the primary label is excluded.
+ */
+ @ProtoLayoutExperimental
+ public boolean hasExcludeFontPadding() {
+ return mElement.hasPrimaryLabelExcludeFontPadding();
+ }
+
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@Override
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/LayoutDefaults.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/LayoutDefaults.java
index 0f1d947..8afa1e2 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/LayoutDefaults.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/LayoutDefaults.java
@@ -110,7 +110,7 @@
/**
* The maximum number of button that can be added to the {@link MultiButtonLayout}.
*
- * @deprecated Use {@link MultiButtonLayoutDefaults#BUTTON_MAX_NUMBER} instead.
+ * @deprecated Use {@link MultiButtonLayoutDefaults#MAX_BUTTONS} instead.
*/
@Deprecated public static final int MULTI_BUTTON_MAX_NUMBER = 7;
@@ -120,7 +120,8 @@
}
/** The maximum number of button that can be added to the {@link MultiButtonLayout}. */
- public static final int BUTTON_MAX_NUMBER = 7;
+ @SuppressWarnings("MinMaxConstant")
+ public static final int MAX_BUTTONS = 7;
/**
* The default size of button in case when there are 3 or more buttons in the {@link
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/MultiButtonLayout.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/MultiButtonLayout.java
index 28c88dc..26617e3 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/MultiButtonLayout.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/MultiButtonLayout.java
@@ -21,10 +21,10 @@
import static androidx.wear.protolayout.material.Helper.checkTag;
import static androidx.wear.protolayout.material.Helper.getMetadataTagName;
import static androidx.wear.protolayout.material.Helper.getTagBytes;
-import static androidx.wear.protolayout.material.layouts.LayoutDefaults.MultiButtonLayoutDefaults.BUTTON_MAX_NUMBER;
import static androidx.wear.protolayout.material.layouts.LayoutDefaults.MultiButtonLayoutDefaults.BUTTON_SIZE_FOR_1_BUTTON;
import static androidx.wear.protolayout.material.layouts.LayoutDefaults.MultiButtonLayoutDefaults.BUTTON_SIZE_FOR_2_BUTTONS;
import static androidx.wear.protolayout.material.layouts.LayoutDefaults.MultiButtonLayoutDefaults.BUTTON_SIZE_FOR_3_PLUS_BUTTONS;
+import static androidx.wear.protolayout.material.layouts.LayoutDefaults.MultiButtonLayoutDefaults.MAX_BUTTONS;
import static androidx.wear.protolayout.material.layouts.LayoutDefaults.MultiButtonLayoutDefaults.SPACER_HEIGHT;
import static androidx.wear.protolayout.material.layouts.LayoutDefaults.MultiButtonLayoutDefaults.SPACER_WIDTH;
@@ -52,10 +52,10 @@
/**
* Opinionated ProtoLayout layout, that can contain between 1 and {@link
- * LayoutDefaults.MultiButtonLayoutDefaults#BUTTON_MAX_NUMBER} number of buttons arranged
+ * LayoutDefaults.MultiButtonLayoutDefaults#MAX_BUTTONS} number of buttons arranged
* inline with the Material
* guidelines. Can be used as a content passed in to the {@link PrimaryLayout}, but if there is
- * {@link LayoutDefaults.MultiButtonLayoutDefaults#BUTTON_MAX_NUMBER} buttons it should be used
+ * {@link LayoutDefaults.MultiButtonLayoutDefaults#MAX_BUTTONS} buttons it should be used
* on its own.
*
* <p>When accessing the contents of a container for testing, note that this element can't be simply
@@ -115,7 +115,7 @@
* Add one new button to the layout. Note that it is accepted to pass in any {@link
* LayoutElement}, but it is strongly recommended to add a {@link Button} as the layout is
* optimized for it. Any button added after
- * {@link LayoutDefaults.MultiButtonLayoutDefaults#BUTTON_MAX_NUMBER} is reached will be
+ * {@link LayoutDefaults.MultiButtonLayoutDefaults#MAX_BUTTONS} is reached will be
* discarded.
*/
@NonNull
@@ -143,10 +143,10 @@
@Override
public MultiButtonLayout build() {
int buttonNum = mButtonsContent.size();
- if (buttonNum > BUTTON_MAX_NUMBER) {
+ if (buttonNum > MAX_BUTTONS) {
throw new IllegalArgumentException(
"Too many buttons are added. Maximum number is "
- + BUTTON_MAX_NUMBER
+ + MAX_BUTTONS
+ ".");
}
@@ -249,10 +249,10 @@
mButtonsContent.get(6),
BUTTON_SIZE_FOR_3_PLUS_BUTTONS))
.build();
+ default:
+ throw new IllegalArgumentException(
+ "Too many buttons are added. Maximum number is " + MAX_BUTTONS + ".");
}
- // This shouldn't happen, but return an empty Box instead of having this method nullable
- // and checks above.
- return new Box.Builder().build();
}
@NonNull
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/PrimaryLayout.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/PrimaryLayout.java
index 800606d..edae5f3 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/PrimaryLayout.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/layouts/PrimaryLayout.java
@@ -20,7 +20,7 @@
import static androidx.wear.protolayout.DimensionBuilders.dp;
import static androidx.wear.protolayout.DimensionBuilders.expand;
import static androidx.wear.protolayout.DimensionBuilders.wrap;
-import static androidx.wear.protolayout.material.ChipDefaults.COMPACT_HEIGHT_TAPPABLE;
+import static androidx.wear.protolayout.material.ChipDefaults.MIN_TAPPABLE_HEIGHT;
import static androidx.wear.protolayout.material.Helper.checkNotNull;
import static androidx.wear.protolayout.material.Helper.checkTag;
import static androidx.wear.protolayout.material.Helper.getMetadataTagBytes;
@@ -258,7 +258,7 @@
float horizontalPadding = getHorizontalPadding();
float horizontalChipPadding = getChipHorizontalPadding();
- float primaryChipHeight = mPrimaryChip != null ? COMPACT_HEIGHT_TAPPABLE.getValue() : 0;
+ float primaryChipHeight = mPrimaryChip != null ? MIN_TAPPABLE_HEIGHT.getValue() : 0;
DpProp mainContentHeight =
dp(
diff --git a/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/TextTest.java b/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/TextTest.java
index a9957f4..ea6f7b9 100644
--- a/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/TextTest.java
+++ b/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/TextTest.java
@@ -215,7 +215,7 @@
assertThat(actualText.getMaxLines()).isEqualTo(2);
assertThat(actualText.getLineHeight())
.isEqualTo(getLineHeightForTypography(TYPOGRAPHY_TITLE1).getValue());
- assertThat(actualText.getExcludeFontPadding()).isTrue();
+ assertThat(actualText.hasExcludeFontPadding()).isTrue();
}
private void assertFontStyle(
diff --git a/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/layouts/MultiButtonLayoutTest.java b/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/layouts/MultiButtonLayoutTest.java
index c90bb91..d40f264 100644
--- a/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/layouts/MultiButtonLayoutTest.java
+++ b/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/layouts/MultiButtonLayoutTest.java
@@ -106,7 +106,7 @@
public void test_too_many_button() {
Button button = new Button.Builder(CONTEXT, CLICKABLE).setTextContent("1").build();
MultiButtonLayout.Builder layoutBuilder = new MultiButtonLayout.Builder();
- for (int i = 0; i < LayoutDefaults.MultiButtonLayoutDefaults.BUTTON_MAX_NUMBER + 1; i++) {
+ for (int i = 0; i < LayoutDefaults.MultiButtonLayoutDefaults.MAX_BUTTONS + 1; i++) {
layoutBuilder.addButtonContent(button);
}
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/color.proto b/wear/protolayout/protolayout-proto/src/main/proto/color.proto
index f5535d9..d19205a 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/color.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/color.proto
@@ -10,9 +10,15 @@
// A property defining a color.
message ColorProp {
- // The color value, in ARGB format.
+ // The static color value, in ARGB format. If a dynamic value is also set and the
+ // renderer supports dynamic values for the corresponding field, this static
+ // value will be ignored. If the static value is not specified, zero
+ // (equivalent to {@link Color#TRANSPARENT}) will be used instead.
optional uint32 argb = 1;
- // The dynamic value.
+ // The dynamic value. Note that when setting this value, the static value is
+ // still required to be set to support older renderers that only read the
+ // static value. If {@code dynamicValue} has an invalid result, the provided
+ // static value will be used instead.
androidx.wear.protolayout.expression.proto.DynamicColor dynamic_value = 2;
}
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/dimension.proto b/wear/protolayout/protolayout-proto/src/main/proto/dimension.proto
index 2a15694..5ff8223 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/dimension.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/dimension.proto
@@ -12,10 +12,15 @@
// A type for linear dimensions, measured in dp.
message DpProp {
- // The value, in dp.
+ // The static value, in dp. If a dynamic value is also set and the renderer supports
+ // dynamic values for the corresponding field, this static value will be
+ // ignored. If the static value is not specified, zero will be used instead.
optional float value = 1;
- // The dynamic value, in dp.
+ // The dynamic value, in dp. Note that when setting this value, the static value is
+ // still required to be set to support older renderers that only read the
+ // static value. If {@code dynamicValue} has an invalid result, the provided
+ // static value will be used instead.
androidx.wear.protolayout.expression.proto.DynamicFloat dynamic_value = 2;
oneof optional_value_for_layout {
@@ -77,10 +82,15 @@
// A type for angular dimensions, measured in degrees.
message DegreesProp {
- // The value, in degrees.
+ // The static value, in degrees. If a dynamic value is also set and the renderer
+ // supports dynamic values for the corresponding field, this static value will be
+ // ignored. If the static value is not specified, zero will be used instead.
optional float value = 1;
- // The dynamic value, in degrees.
+ // The dynamic value, in degrees. Note that when setting this value, the static value is
+ // still required to be set to support older renderers that only read the
+ // static value. If {@code dynamicValue} has an invalid result, the provided
+ // static value will be used instead.
androidx.wear.protolayout.expression.proto.DynamicFloat dynamic_value = 2;
oneof optional_value_for_layout {
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/types.proto b/wear/protolayout/protolayout-proto/src/main/proto/types.proto
index 9d9227f..e5d68f0 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/types.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/types.proto
@@ -11,8 +11,11 @@
// An int32 type.
message Int32Prop {
- // The value.
- int32 value = 1;
+
+ oneof optional_value {
+ // The static value.
+ int32 value = 1;
+ }
// The dynamic value.
androidx.wear.protolayout.expression.proto.DynamicInt32 dynamic_value = 2;
@@ -22,11 +25,17 @@
message StringProp {
oneof optional_value {
- // The value.
+ // The static value. If a dynamic value is also set and the renderer supports
+ // dynamic values for the corresponding field, this static value will be
+ // ignored. If the static value is not specified, {@code null} will be used
+ // instead.
string value = 1;
}
- // The dynamic value.
+ // The dynamic value. Note that when setting this value, the static value is
+ // still required to be set to support older renderers that only read the
+ // static value. If {@code dynamicValue} has an invalid result, the provided
+ // static value will be used instead.
androidx.wear.protolayout.expression.proto.DynamicString dynamic_value = 2;
oneof optional_value_for_layout {
@@ -42,17 +51,25 @@
// A float type.
message FloatProp {
- // The value.
+ // The static value. If a dynamic value is also set and the renderer supports
+ // dynamic values for the corresponding field, this static value will be
+ // ignored. If the static value is not specified, zero will be used instead.
optional float value = 1;
- // The dynamic value.
+ // The dynamic value. Note that when setting this value, the static value is
+ // still required to be set to support older renderers that only read the
+ // static value. If {@code dynamicValue} has an invalid result, the provided
+ // static value will be used instead.
androidx.wear.protolayout.expression.proto.DynamicFloat dynamic_value = 2;
}
// A boolean type.
message BoolProp {
- // The value.
- bool value = 1;
+
+ oneof optional_value {
+ // The static value.
+ bool value = 1;
+ }
// The dynamic value.
androidx.wear.protolayout.expression.proto.DynamicBool dynamic_value = 2;
diff --git a/wear/protolayout/protolayout-renderer/api/restricted_current.txt b/wear/protolayout/protolayout-renderer/api/restricted_current.txt
index 97e844a..e393e1d 100644
--- a/wear/protolayout/protolayout-renderer/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-renderer/api/restricted_current.txt
@@ -12,7 +12,7 @@
method public com.google.common.util.concurrent.ListeningExecutorService getBgExecutorService();
method public String getClickableIdExtra();
method public androidx.wear.protolayout.renderer.impl.ProtoLayoutViewInstance.LoadActionListener getLoadActionListener();
- method public androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway? getSensorGateway();
+ method public java.util.Map<androidx.wear.protolayout.expression.pipeline.PlatformDataProvider!,java.util.Set<androidx.wear.protolayout.expression.PlatformDataKey<?>!>!> getPlatformDataProviders();
method public androidx.wear.protolayout.expression.pipeline.StateStore? getStateStore();
method public android.content.Context getUiContext();
method public com.google.common.util.concurrent.ListeningExecutorService getUiExecutorService();
@@ -20,9 +20,9 @@
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final class ProtoLayoutViewInstance.Config.Builder {
ctor public ProtoLayoutViewInstance.Config.Builder(android.content.Context, com.google.common.util.concurrent.ListeningExecutorService, com.google.common.util.concurrent.ListeningExecutorService, String);
+ method public androidx.wear.protolayout.renderer.impl.ProtoLayoutViewInstance.Config.Builder addPlatformDataProvider(androidx.wear.protolayout.expression.pipeline.PlatformDataProvider, androidx.wear.protolayout.expression.PlatformDataKey<?>!...);
method public androidx.wear.protolayout.renderer.impl.ProtoLayoutViewInstance.Config build();
method public androidx.wear.protolayout.renderer.impl.ProtoLayoutViewInstance.Config.Builder setLoadActionListener(androidx.wear.protolayout.renderer.impl.ProtoLayoutViewInstance.LoadActionListener);
- method public androidx.wear.protolayout.renderer.impl.ProtoLayoutViewInstance.Config.Builder setSensorGateway(androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway);
method public androidx.wear.protolayout.renderer.impl.ProtoLayoutViewInstance.Config.Builder setStateStore(androidx.wear.protolayout.expression.pipeline.StateStore);
}
diff --git a/wear/protolayout/protolayout-renderer/build.gradle b/wear/protolayout/protolayout-renderer/build.gradle
index f449584..b8c0903 100644
--- a/wear/protolayout/protolayout-renderer/build.gradle
+++ b/wear/protolayout/protolayout-renderer/build.gradle
@@ -35,7 +35,6 @@
implementation "androidx.concurrent:concurrent-futures:1.1.0"
implementation("androidx.core:core:1.7.0")
implementation("androidx.vectordrawable:vectordrawable-seekable:1.0.0-beta01")
- implementation("androidx.collection:collection:1.2.0")
implementation("androidx.wear:wear:1.3.0-alpha04")
testImplementation(libs.mockitoCore4)
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/NodeInfo.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/NodeInfo.java
index eda231e..3a9fa49 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/NodeInfo.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/NodeInfo.java
@@ -141,7 +141,7 @@
@Override
public void destroy() {
mActiveBoundTypes.forEach(BoundDynamicType::close);
- mResolvedAvds.forEach(ResolvedAvd::unregisterCallback);
+ stopAvdAnimations();
}
/** Returns the number of active bound dynamic types. */
@@ -151,7 +151,7 @@
return mActiveBoundTypes.stream().mapToInt(BoundDynamicType::getDynamicNodeCount).sum();
}
- /** Play the animation with the given trigger type */
+ /** Play the animation with the given trigger type. */
@UiThread
void playAvdAnimations(@NonNull InnerCase triggerCase) {
for (ResolvedAvd entry : mResolvedAvds) {
@@ -161,7 +161,7 @@
continue;
}
if ((triggerCase == InnerCase.ON_VISIBLE_ONCE_TRIGGER
- || triggerCase == InnerCase.ON_LOAD_TRIGGER)
+ || triggerCase == InnerCase.ON_LOAD_TRIGGER)
&& entry.mPlayedAtLeastOnce) {
continue;
}
@@ -185,7 +185,7 @@
mActiveBoundTypes.forEach(n -> n.setAnimationVisibility(visible));
}
- /** Reset the avd animations with the given trigger type */
+ /** Reset the avd animations with the given trigger type. */
@UiThread
void resetAvdAnimations(@NonNull InnerCase triggerCase) {
for (ResolvedAvd entry : mResolvedAvds) {
@@ -195,7 +195,7 @@
}
}
- /** Reset the avd animations with the given trigger type */
+ /** Stop the avd animations with the given trigger type. */
@UiThread
void stopAvdAnimations(@NonNull InnerCase triggerCase) {
for (ResolvedAvd entry : mResolvedAvds) {
@@ -208,6 +208,14 @@
}
}
+ /** Stop all running avd animations. */
+ @UiThread
+ void stopAvdAnimations() {
+ for (InnerCase triggerCase : InnerCase.values()) {
+ stopAvdAnimations(triggerCase);
+ }
+ }
+
/**
* Returns the total duration in milliseconds of the animated drawable associated with a
* StateSource with the given key name; or null if no such SourceKey exists.
@@ -228,12 +236,13 @@
int getRunningAnimationCount() {
return (int)
(mActiveBoundTypes.stream()
- .mapToInt(BoundDynamicType::getRunningAnimationCount)
- .sum()
+ .mapToInt(BoundDynamicType::getRunningAnimationCount).sum()
+ mResolvedAvds.stream().filter(avd -> avd.mDrawable.isRunning()).count());
}
- /** Returns how many expression nodes evaluated. */
+ /**
+ * Returns how many expression nodes evaluated.
+ */
@VisibleForTesting
public int getExpressionNodesCount() {
return mActiveBoundTypes.stream().mapToInt(BoundDynamicType::getDynamicNodeCount).sum();
@@ -276,10 +285,6 @@
this.mDrawable.registerAnimationCallback(callback);
}
- void unregisterCallback() {
- mDrawable.unregisterAnimationCallback(mCallback);
- }
-
void startAnimation() {
this.mDrawable.start();
this.mCallback.mIsUsingQuota.set(true);
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipeline.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipeline.java
index 88f1373..869004e 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipeline.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipeline.java
@@ -24,8 +24,6 @@
import android.annotation.SuppressLint;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.icu.util.ULocale;
-import android.os.Handler;
-import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -40,18 +38,17 @@
import androidx.collection.ArrayMap;
import androidx.collection.ArraySet;
import androidx.vectordrawable.graphics.drawable.SeekableAnimatedVectorDrawable;
-import androidx.wear.protolayout.expression.PlatformHealthSources;
+import androidx.wear.protolayout.expression.PlatformDataKey;
import androidx.wear.protolayout.expression.pipeline.BoundDynamicType;
import androidx.wear.protolayout.expression.pipeline.DynamicTypeBindingRequest;
import androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator;
import androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator.EvaluationException;
import androidx.wear.protolayout.expression.pipeline.DynamicTypeValueReceiver;
import androidx.wear.protolayout.expression.pipeline.FixedQuotaManagerImpl;
+import androidx.wear.protolayout.expression.pipeline.PlatformDataProvider;
+import androidx.wear.protolayout.expression.pipeline.PlatformTimeUpdateNotifierImpl;
import androidx.wear.protolayout.expression.pipeline.QuotaManager;
-import androidx.wear.protolayout.expression.pipeline.SensorGatewaySingleDataProvider;
import androidx.wear.protolayout.expression.pipeline.StateStore;
-import androidx.wear.protolayout.expression.pipeline.TimeGatewayImpl;
-import androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway;
import androidx.wear.protolayout.expression.proto.DynamicProto.DynamicBool;
import androidx.wear.protolayout.expression.proto.DynamicProto.DynamicColor;
import androidx.wear.protolayout.expression.proto.DynamicProto.DynamicFloat;
@@ -67,7 +64,6 @@
import androidx.wear.protolayout.renderer.dynamicdata.NodeInfo.ResolvedAvd;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -98,16 +94,16 @@
boolean mFullyVisible;
@NonNull final QuotaManager mAnimationQuotaManager;
@NonNull private final DynamicTypeEvaluator mEvaluator;
- @NonNull private final TimeGatewayImpl mTimeGateway;
+ @NonNull private final PlatformTimeUpdateNotifierImpl mTimeNotifier;
/** Creates a {@link ProtoLayoutDynamicDataPipeline} without animation support. */
@RestrictTo(Scope.LIBRARY_GROUP)
public ProtoLayoutDynamicDataPipeline(
- @Nullable SensorGateway sensorGateway,
+ @NonNull Map<PlatformDataProvider, Set<PlatformDataKey<?>>> platformDataProviders,
@NonNull StateStore stateStore) {
// Build pipeline with quota that doesn't allow any animations.
this(
- sensorGateway,
+ platformDataProviders,
stateStore,
/* enableAnimations= */ false,
DISABLED_ANIMATIONS_QUOTA_MANAGER,
@@ -120,12 +116,12 @@
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public ProtoLayoutDynamicDataPipeline(
- @Nullable SensorGateway sensorGateway,
+ @NonNull Map<PlatformDataProvider, Set<PlatformDataKey<?>>> platformDataProviders,
@NonNull StateStore stateStore,
@NonNull QuotaManager animationQuotaManager,
@NonNull QuotaManager dynamicNodesQuotaManager) {
this(
- sensorGateway,
+ platformDataProviders,
stateStore,
/* enableAnimations= */ true,
animationQuotaManager,
@@ -134,36 +130,27 @@
/** Creates a {@link ProtoLayoutDynamicDataPipeline}. */
private ProtoLayoutDynamicDataPipeline(
- @Nullable SensorGateway sensorGateway,
+ @NonNull Map<PlatformDataProvider, Set<PlatformDataKey<?>>> platformDataProviders,
@NonNull StateStore stateStore,
boolean enableAnimations,
@NonNull QuotaManager animationQuotaManager,
@NonNull QuotaManager dynamicNodeQuotaManager) {
this.mEnableAnimations = enableAnimations;
this.mAnimationQuotaManager = animationQuotaManager;
- this.mTimeGateway = new TimeGatewayImpl(new Handler(Looper.getMainLooper()));
DynamicTypeEvaluator.Config.Builder evaluatorConfigBuilder =
- new DynamicTypeEvaluator.Config.Builder()
- .setTimeGateway(mTimeGateway)
- .setStateStore(stateStore);
+ new DynamicTypeEvaluator.Config.Builder().setStateStore(stateStore);
evaluatorConfigBuilder.setDynamicTypesQuotaManager(dynamicNodeQuotaManager);
- if (sensorGateway != null) {
+ this.mTimeNotifier = new PlatformTimeUpdateNotifierImpl();
+ evaluatorConfigBuilder.setPlatformTimeUpdateNotifier(this.mTimeNotifier);
+ for (Map.Entry<PlatformDataProvider, Set<PlatformDataKey<?>>> providerEntry :
+ platformDataProviders.entrySet()) {
evaluatorConfigBuilder.addPlatformDataProvider(
- new SensorGatewaySingleDataProvider(
- sensorGateway, PlatformHealthSources.Keys.HEART_RATE_BPM),
- Collections.singleton(PlatformHealthSources.Keys.HEART_RATE_BPM)
- );
- evaluatorConfigBuilder.addPlatformDataProvider(
- new SensorGatewaySingleDataProvider(
- sensorGateway, PlatformHealthSources.Keys.DAILY_STEPS),
- Collections.singleton(PlatformHealthSources.Keys.DAILY_STEPS)
- );
+ providerEntry.getKey(), providerEntry.getValue());
}
if (enableAnimations) {
evaluatorConfigBuilder.setAnimationQuotaManager(animationQuotaManager);
}
- DynamicTypeEvaluator.Config evaluatorConfig = evaluatorConfigBuilder.build();
- this.mEvaluator = new DynamicTypeEvaluator(evaluatorConfig);
+ this.mEvaluator = new DynamicTypeEvaluator(evaluatorConfigBuilder.build());
}
/** Returns the number of active dynamic types in this pipeline. */
@@ -212,13 +199,7 @@
@SuppressWarnings("RestrictTo")
@RestrictTo(Scope.LIBRARY_GROUP)
public void setUpdatesEnabled(boolean canUpdate) {
- // SensorGateway is not owned by ProtoLayoutDynamicDataPipeline, so the callers who create
- // it are responsible for updates.
- if (canUpdate) {
- mTimeGateway.enableUpdates();
- } else {
- mTimeGateway.disableUpdates();
- }
+ mTimeNotifier.setUpdatesEnabled(canUpdate);
}
/** Closes existing gateways. */
@@ -226,7 +207,7 @@
@SuppressWarnings("RestrictTo")
public void close() {
mPositionIdTree.clear();
- mTimeGateway.close();
+ mTimeNotifier.setUpdatesEnabled(false);
}
/**
@@ -656,8 +637,8 @@
@NonNull String posId,
@NonNull DynamicTypeValueReceiver<Float> consumer) {
DynamicTypeBindingRequest bindingRequest =
- DynamicTypeBindingRequest.forDynamicFloatInternal(dpProp.getDynamicValue(),
- consumer);
+ DynamicTypeBindingRequest.forDynamicFloatInternal(
+ dpProp.getDynamicValue(), consumer);
tryBindRequest(posId, bindingRequest, consumer::onInvalidated);
return this;
}
@@ -978,10 +959,7 @@
mPositionIdTree.forEach(info -> info.setVisibility(visible));
}
- /**
- * Reset the avd animations with the given trigger type.
- *
- */
+ /** Reset the avd animations with the given trigger type. */
@UiThread
@VisibleForTesting
@RestrictTo(Scope.LIBRARY_GROUP)
@@ -989,10 +967,7 @@
mPositionIdTree.forEach(info -> info.resetAvdAnimations(triggerCase));
}
- /**
- * Stops running avd animations and releases their quota.
- *
- */
+ /** Stops running avd animations and releases their quota. */
@UiThread
@VisibleForTesting
@RestrictTo(Scope.LIBRARY_GROUP)
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/impl/ProtoLayoutViewInstance.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/impl/ProtoLayoutViewInstance.java
index b496675..1445157 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/impl/ProtoLayoutViewInstance.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/impl/ProtoLayoutViewInstance.java
@@ -34,9 +34,11 @@
import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
+import androidx.collection.ArrayMap;
+import androidx.wear.protolayout.expression.PlatformDataKey;
import androidx.wear.protolayout.expression.pipeline.FixedQuotaManagerImpl;
+import androidx.wear.protolayout.expression.pipeline.PlatformDataProvider;
import androidx.wear.protolayout.expression.pipeline.StateStore;
-import androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway;
import androidx.wear.protolayout.proto.LayoutElementProto.Layout;
import androidx.wear.protolayout.proto.ResourceProto;
import androidx.wear.protolayout.proto.StateProto.State;
@@ -53,11 +55,14 @@
import androidx.wear.protolayout.renderer.inflater.ResourceResolvers;
import androidx.wear.protolayout.renderer.inflater.StandardResourceResolvers;
+import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.SettableFuture;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
@@ -297,7 +302,10 @@
@NonNull private final Resources mRendererResources;
@NonNull private final ResourceResolversProvider mResourceResolversProvider;
@NonNull private final ProtoLayoutTheme mProtoLayoutTheme;
- @Nullable private final SensorGateway mSensorGateway;
+
+ @NonNull
+ private final Map<PlatformDataProvider, Set<PlatformDataKey<?>>> mPlatformDataProviders;
+
@Nullable private final StateStore mStateStore;
@NonNull private final LoadActionListener mLoadActionListener;
@NonNull private final ListeningExecutorService mUiExecutorService;
@@ -316,7 +324,7 @@
@NonNull Resources rendererResources,
@NonNull ResourceResolversProvider resourceResolversProvider,
@NonNull ProtoLayoutTheme protoLayoutTheme,
- @Nullable SensorGateway sensorGateway,
+ @NonNull Map<PlatformDataProvider, Set<PlatformDataKey<?>>> platformDataProviders,
@Nullable StateStore stateStore,
@NonNull LoadActionListener loadActionListener,
@NonNull ListeningExecutorService uiExecutorService,
@@ -332,7 +340,7 @@
this.mRendererResources = rendererResources;
this.mResourceResolversProvider = resourceResolversProvider;
this.mProtoLayoutTheme = protoLayoutTheme;
- this.mSensorGateway = sensorGateway;
+ this.mPlatformDataProviders = platformDataProviders;
this.mStateStore = stateStore;
this.mLoadActionListener = loadActionListener;
this.mUiExecutorService = uiExecutorService;
@@ -368,14 +376,15 @@
/** Returns theme used for this instance. */
@NonNull
- ProtoLayoutTheme getProtoLayoutTheme() {
+ @RestrictTo(Scope.LIBRARY)
+ public ProtoLayoutTheme getProtoLayoutTheme() {
return mProtoLayoutTheme;
}
- /** Returns gateway for sensor data. */
- @Nullable
- public SensorGateway getSensorGateway() {
- return mSensorGateway;
+ /** Returns the registered platform data providers. */
+ @NonNull
+ public Map<PlatformDataProvider, Set<PlatformDataKey<?>>> getPlatformDataProviders() {
+ return mPlatformDataProviders;
}
/** Returns state store. */
@@ -452,7 +461,11 @@
@Nullable private Resources mRendererResources;
@Nullable private ResourceResolversProvider mResourceResolversProvider;
@Nullable private ProtoLayoutTheme mProtoLayoutTheme;
- @Nullable private SensorGateway mSensorGateway;
+
+ @NonNull
+ private final Map<PlatformDataProvider, Set<PlatformDataKey<?>>>
+ mPlatformDataProviders = new ArrayMap<>();
+
@Nullable private StateStore mStateStore;
@Nullable private LoadActionListener mLoadActionListener;
@NonNull private final ListeningExecutorService mUiExecutorService;
@@ -508,12 +521,22 @@
}
/**
- * Sets the gateway for accessing sensor data. If not set, sensor data won't be
- * accessible.
+ * Sets theme for this ProtoLayout instance. If not set, default theme would be used.
*/
+ @RestrictTo(Scope.LIBRARY)
@NonNull
- public Builder setSensorGateway(@NonNull SensorGateway sensorGateway) {
- this.mSensorGateway = sensorGateway;
+ public Builder setProtoLayoutTheme(@NonNull ProtoLayoutTheme protoLayoutTheme) {
+ this.mProtoLayoutTheme = protoLayoutTheme;
+ return this;
+ }
+
+ /** Adds a {@link PlatformDataProvider} for accessing {@code supportedKeys}. */
+ @NonNull
+ public Builder addPlatformDataProvider(
+ @NonNull PlatformDataProvider platformDataProvider,
+ @NonNull PlatformDataKey<?>... supportedKeys) {
+ this.mPlatformDataProviders.put(
+ platformDataProvider, ImmutableSet.copyOf(supportedKeys));
return this;
}
@@ -614,7 +637,7 @@
mRendererResources,
mResourceResolversProvider,
mProtoLayoutTheme,
- mSensorGateway,
+ mPlatformDataProviders,
mStateStore,
loadActionListener,
mUiExecutorService,
@@ -649,12 +672,12 @@
mDataPipeline =
config.getAnimationEnabled()
? new ProtoLayoutDynamicDataPipeline(
- config.getSensorGateway(),
+ config.getPlatformDataProviders(),
stateStore,
new FixedQuotaManagerImpl(config.getRunningAnimationsLimit()),
new FixedQuotaManagerImpl(DYNAMIC_NODES_MAX_COUNT))
: new ProtoLayoutDynamicDataPipeline(
- config.getSensorGateway(), stateStore);
+ config.getPlatformDataProviders(), stateStore);
mDataPipeline.setFullyVisible(config.getIsViewFullyVisible());
} else {
mDataPipeline = null;
@@ -818,9 +841,10 @@
if (mRenderFuture == null) {
mPrevLayout = layout;
mRenderFuture =
- mBgExecutorService.submit(() ->
- renderOrComputeMutations(
- layout, resources, prevRenderedMetadata));
+ mBgExecutorService.submit(
+ () ->
+ renderOrComputeMutations(
+ layout, resources, prevRenderedMetadata));
mCanReattachWithoutRendering = false;
}
SettableFuture<Void> result = SettableFuture.create();
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
index cc1b1a1..fa5d576 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
@@ -1584,8 +1584,8 @@
}
@Nullable
- private static TruncateAt textTruncationToEllipsize(TextOverflowProp type) {
- switch (type.getValue()) {
+ private static TruncateAt textTruncationToEllipsize(TextOverflow overflowValue) {
+ switch (overflowValue) {
case TEXT_OVERFLOW_TRUNCATE:
// A null TruncateAt disables adding an ellipsis.
return null;
@@ -2108,11 +2108,15 @@
.applyPendingChildLayoutParams(layoutParams));
}
- private static void applyTextOverflow(
+ private void applyTextOverflow(
TextView textView, TextOverflowProp overflow, MarqueeParameters marqueeParameters) {
- textView.setEllipsize(textTruncationToEllipsize(overflow));
- if (overflow.getValue() == TextOverflow.TEXT_OVERFLOW_MARQUEE
- && textView.getMaxLines() == 1) {
+ TextOverflow overflowValue = overflow.getValue();
+ if (!mAnimationEnabled && overflowValue == TextOverflow.TEXT_OVERFLOW_MARQUEE) {
+ overflowValue = TextOverflow.TEXT_OVERFLOW_UNDEFINED;
+ }
+
+ textView.setEllipsize(textTruncationToEllipsize(overflowValue));
+ if (overflowValue == TextOverflow.TEXT_OVERFLOW_MARQUEE && textView.getMaxLines() == 1) {
int marqueeIterations =
marqueeParameters.hasIterations()
? marqueeParameters.getIterations()
diff --git a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/NodeInfoTest.java b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/NodeInfoTest.java
new file mode 100644
index 0000000..9a39ce8
--- /dev/null
+++ b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/NodeInfoTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.protolayout.renderer.dynamicdata;
+
+import static androidx.wear.protolayout.renderer.common.ProtoLayoutDiffer.FIRST_CHILD_INDEX;
+import static androidx.wear.protolayout.renderer.common.ProtoLayoutDiffer.ROOT_NODE_ID;
+import static androidx.wear.protolayout.renderer.common.ProtoLayoutDiffer.createNodePosId;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.wear.protolayout.expression.pipeline.QuotaManager;
+import androidx.wear.protolayout.proto.TriggerProto.OnLoadTrigger;
+import androidx.wear.protolayout.proto.TriggerProto.Trigger;
+import androidx.wear.protolayout.proto.TriggerProto.Trigger.InnerCase;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class NodeInfoTest {
+ private static final String POS_ID = createNodePosId(ROOT_NODE_ID, FIRST_CHILD_INDEX);
+ @Rule public final MockitoRule mocks = MockitoJUnit.rule();
+ @Mock private QuotaManager mMockQuotaManager;
+ private NodeInfo mNodeInfoUnderTest;
+
+ @Before
+ public void setUp() {
+ mNodeInfoUnderTest = new NodeInfo(POS_ID, mMockQuotaManager);
+ }
+
+ @Test
+ public void destroy_releasesAvdQuota() {
+ when(mMockQuotaManager.tryAcquireQuota(anyInt())).thenReturn(true);
+ TestAnimatedVectorDrawable drawableAvd = new TestAnimatedVectorDrawable();
+ mNodeInfoUnderTest.addResolvedAvd(
+ drawableAvd,
+ Trigger.newBuilder().setOnLoadTrigger(OnLoadTrigger.getDefaultInstance()).build());
+ mNodeInfoUnderTest.playAvdAnimations(InnerCase.ON_LOAD_TRIGGER);
+ verify(mMockQuotaManager).tryAcquireQuota(eq(1));
+
+ mNodeInfoUnderTest.destroy();
+
+ verify(mMockQuotaManager).releaseQuota(1);
+ }
+}
diff --git a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipelineTest.java b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipelineTest.java
index 12e7936..f4a1cfa 100644
--- a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipelineTest.java
+++ b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipelineTest.java
@@ -51,6 +51,7 @@
import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationSpec;
import androidx.wear.protolayout.expression.proto.AnimationParameterProto.RepeatMode;
import androidx.wear.protolayout.expression.proto.AnimationParameterProto.Repeatable;
+import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableDynamicColor;
import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableDynamicFloat;
import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableFixedColor;
@@ -72,7 +73,6 @@
import androidx.wear.protolayout.expression.proto.FixedProto.FixedFloat;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedInt32;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedString;
-import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
import androidx.wear.protolayout.proto.ColorProto.ColorProp;
import androidx.wear.protolayout.proto.DimensionProto.DegreesProp;
import androidx.wear.protolayout.proto.DimensionProto.DpProp;
@@ -380,7 +380,7 @@
.build();
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -446,7 +446,7 @@
DynamicInt32 dynamicInt = fixedDynamicInt32(1);
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -466,7 +466,7 @@
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -496,7 +496,7 @@
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -524,7 +524,7 @@
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -580,7 +580,7 @@
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -618,7 +618,7 @@
List<String> expected = Arrays.asList(NODE_1_1, NODE_1_1_1);
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -639,7 +639,7 @@
public void resolvedAnimatedImage_canStorePlayAndResetOnVisible() {
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -672,7 +672,7 @@
public void resolvedAnimatedImage_canStoreAndPlayOnVisibleOnce() {
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -703,7 +703,7 @@
public void resolvedAnimatedImage_canStorePlayAndResetOnLoad() {
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -731,7 +731,7 @@
String boolStateKey = "KEY";
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -768,7 +768,7 @@
String boolStateKey = "KEY";
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -788,7 +788,7 @@
String boolStateKey = "KEY";
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -810,7 +810,7 @@
FixedQuotaManagerImpl quotaManager = new FixedQuotaManagerImpl(MAX_VALUE);
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
quotaManager,
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -843,7 +843,7 @@
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
quotaManager);
@@ -880,7 +880,7 @@
FixedQuotaManagerImpl quotaManager = new FixedQuotaManagerImpl(/* quotaCap= */ 0);
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
quotaManager);
@@ -907,7 +907,7 @@
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
quotaManager);
@@ -944,7 +944,7 @@
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
quotaManager);
@@ -993,7 +993,7 @@
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
quotaManager);
@@ -1024,7 +1024,7 @@
FixedQuotaManagerImpl quotaManager = new FixedQuotaManagerImpl(/* quotaCap= */ 0);
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
quotaManager,
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -1108,7 +1108,7 @@
public void resolvedSeekableAnimatedImage_canStoreAndRegisterWithAnimatableFixedFloat() {
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -1140,7 +1140,7 @@
public void resolvedSeekableAnimatedImage_canStoreAndRegisterWithAnimatableDynamicFloat() {
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -1185,7 +1185,7 @@
public void resolvedSeekableAnimatedImage_getSeekableAnimationTotalDurationMillis() {
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -1208,7 +1208,7 @@
public void whenInvisible_pausesAvds() {
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -1243,7 +1243,7 @@
public void visibilityChange_avdsStatusChange() {
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -1355,7 +1355,7 @@
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
quotaManager,
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -1408,7 +1408,7 @@
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
quotaManager,
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -1464,7 +1464,7 @@
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
quotaManager,
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -1521,7 +1521,7 @@
FixedQuotaManagerImpl quotaManager = new FixedQuotaManagerImpl(1);
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
quotaManager,
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -1771,7 +1771,7 @@
Trigger.newBuilder().setOnLoadTrigger(OnLoadTrigger.getDefaultInstance()).build();
ProtoLayoutDynamicDataPipeline pipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
quotaManager,
new FixedQuotaManagerImpl(MAX_VALUE));
@@ -1815,12 +1815,12 @@
ProtoLayoutDynamicDataPipeline pipeline =
enableAnimations
? new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
new FixedQuotaManagerImpl(MAX_VALUE),
new FixedQuotaManagerImpl(MAX_VALUE))
: new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null, mStateStore);
+ /* platformDataProviders= */ ImmutableMap.of(), mStateStore);
shadowOf(getMainLooper()).idle();
pipeline.setFullyVisible(true);
@@ -1843,7 +1843,8 @@
AddToListCallback<Float> receiver =
new AddToListCallback<>(results, /* invalidList= */ null);
ProtoLayoutDynamicDataPipeline pipeline =
- new ProtoLayoutDynamicDataPipeline(/* sensorGateway= */ null, mStateStore);
+ new ProtoLayoutDynamicDataPipeline(
+ /* platformDataProviders= */ ImmutableMap.of(), mStateStore);
shadowOf(getMainLooper()).idle();
pipeline.setFullyVisible(true);
@@ -1861,7 +1862,8 @@
AddToListCallback<Integer> receiver =
new AddToListCallback<>(results, /* invalidList= */ null);
ProtoLayoutDynamicDataPipeline pipeline =
- new ProtoLayoutDynamicDataPipeline(/* sensorGateway= */ null, mStateStore);
+ new ProtoLayoutDynamicDataPipeline(
+ /* platformDataProviders= */ ImmutableMap.of(), mStateStore);
shadowOf(getMainLooper()).idle();
pipeline.setFullyVisible(true);
@@ -1879,7 +1881,8 @@
AddToListCallback<Float> receiver =
new AddToListCallback<>(results, /* invalidList= */ null);
ProtoLayoutDynamicDataPipeline pipeline =
- new ProtoLayoutDynamicDataPipeline(/* sensorGateway= */ null, mStateStore);
+ new ProtoLayoutDynamicDataPipeline(
+ /* platformDataProviders= */ ImmutableMap.of(), mStateStore);
shadowOf(getMainLooper()).idle();
pipeline.setFullyVisible(true);
@@ -1897,7 +1900,8 @@
AddToListCallback<Float> receiver =
new AddToListCallback<>(results, /* invalidList= */ null);
ProtoLayoutDynamicDataPipeline pipeline =
- new ProtoLayoutDynamicDataPipeline(/* sensorGateway= */ null, mStateStore);
+ new ProtoLayoutDynamicDataPipeline(
+ /* platformDataProviders= */ ImmutableMap.of(), mStateStore);
shadowOf(getMainLooper()).idle();
pipeline.setFullyVisible(true);
@@ -1915,7 +1919,8 @@
AddToListCallback<Integer> receiver =
new AddToListCallback<>(results, /* invalidList= */ null);
ProtoLayoutDynamicDataPipeline pipeline =
- new ProtoLayoutDynamicDataPipeline(/* sensorGateway= */ null, mStateStore);
+ new ProtoLayoutDynamicDataPipeline(
+ /* platformDataProviders= */ ImmutableMap.of(), mStateStore);
shadowOf(getMainLooper()).idle();
pipeline.setFullyVisible(true);
@@ -1983,54 +1988,4 @@
return null;
}
}
-
- private static class TestAnimatedVectorDrawable extends AnimatedVectorDrawable {
- public boolean started = false;
- public boolean reset = false;
-
- // We need to intercept callbacks and save it in this test class as shadow drawable doesn't
- // seem to call onEnd listener, meaning that quota won't be freed and we would get failing
- // test.
- private final List<AnimationCallback> mAnimationCallbacks = new ArrayList<>();
-
- @Override
- public void start() {
- super.start();
- started = true;
- reset = false;
- }
-
- @Override
- public void registerAnimationCallback(@NonNull AnimationCallback callback) {
- super.registerAnimationCallback(callback);
- mAnimationCallbacks.add(callback);
- }
-
- @Override
- public boolean unregisterAnimationCallback(@NonNull AnimationCallback callback) {
- mAnimationCallbacks.remove(callback);
- return super.unregisterAnimationCallback(callback);
- }
-
- @Override
- public void stop() {
- super.stop();
- started = false;
- mAnimationCallbacks.forEach(c -> c.onAnimationEnd(this));
- }
-
- @Override
- public void reset() {
- super.reset();
- started = false;
- reset = true;
- mAnimationCallbacks.forEach(c -> c.onAnimationEnd(this));
- }
-
- @Override
- public boolean isRunning() {
- super.isRunning();
- return started;
- }
- }
}
diff --git a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/TestAnimatedVectorDrawable.java b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/TestAnimatedVectorDrawable.java
new file mode 100644
index 0000000..3bb97b4
--- /dev/null
+++ b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/TestAnimatedVectorDrawable.java
@@ -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.wear.protolayout.renderer.dynamicdata;
+
+import android.graphics.drawable.AnimatedVectorDrawable;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/* A testable AVD implementation. */
+class TestAnimatedVectorDrawable extends AnimatedVectorDrawable {
+ public boolean started = false;
+ public boolean reset = false;
+
+ // We need to intercept callbacks and save it in this test class as shadow drawable doesn't seem
+ // to call onEnd listener, meaning that quota won't be freed and we would get failing test.
+ private final List<AnimationCallback> mAnimationCallbacks = new ArrayList<>();
+
+ @Override
+ public void start() {
+ super.start();
+ started = true;
+ reset = false;
+ }
+
+ @Override
+ public void registerAnimationCallback(@NonNull AnimationCallback callback) {
+ super.registerAnimationCallback(callback);
+ mAnimationCallbacks.add(callback);
+ }
+
+ @Override
+ public boolean unregisterAnimationCallback(@NonNull AnimationCallback callback) {
+ mAnimationCallbacks.remove(callback);
+ return super.unregisterAnimationCallback(callback);
+ }
+
+ @Override
+ public void stop() {
+ super.stop();
+ started = false;
+ mAnimationCallbacks.forEach(c -> c.onAnimationEnd(this));
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ started = false;
+ reset = true;
+ mAnimationCallbacks.forEach(c -> c.onAnimationEnd(this));
+ }
+
+ @Override
+ public boolean isRunning() {
+ super.isRunning();
+ return started;
+ }
+}
diff --git a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
index 1eb0e31..a635ba4 100644
--- a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
+++ b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
@@ -1828,6 +1828,31 @@
}
@Test
+ public void inflate_textView_marquee_animationsDisabled() {
+ String textContents = "Marquee Animation";
+ LayoutElement root =
+ LayoutElement.newBuilder()
+ .setText(
+ Text.newBuilder()
+ .setText(string(textContents))
+ .setMaxLines(Int32Prop.newBuilder().setValue(1))
+ .setOverflow(
+ TextOverflowProp.newBuilder()
+ .setValue(
+ TextOverflow.TEXT_OVERFLOW_MARQUEE)
+ .build()))
+ .build();
+
+ FrameLayout rootLayout =
+ renderer(
+ newRendererConfigBuilder(fingerprintedLayout(root))
+ .setAnimationEnabled(false))
+ .inflate();
+ TextView tv = (TextView) rootLayout.getChildAt(0);
+ expect.that(tv.getEllipsize()).isNull();
+ }
+
+ @Test
public void inflate_textView_marqueeAnimationInMultiLine() {
String textContents = "Marquee Animation";
LayoutElement root =
@@ -3384,7 +3409,7 @@
FixedQuotaManagerImpl quotaManager) {
mDataPipeline =
new ProtoLayoutDynamicDataPipeline(
- /* sensorGateway= */ null,
+ /* platformDataProviders= */ ImmutableMap.of(),
mStateStore,
quotaManager,
new FixedQuotaManagerImpl(MAX_VALUE));
diff --git a/wear/protolayout/protolayout/api/current.txt b/wear/protolayout/protolayout/api/current.txt
index 2544ad2..cfb4842 100644
--- a/wear/protolayout/protolayout/api/current.txt
+++ b/wear/protolayout/protolayout/api/current.txt
@@ -32,7 +32,7 @@
method public boolean getValue();
}
- public static final class ActionBuilders.AndroidBooleanExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ public static final class ActionBuilders.AndroidBooleanExtra.Builder {
ctor public ActionBuilders.AndroidBooleanExtra.Builder();
method public androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra build();
method public androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra.Builder setValue(boolean);
@@ -42,7 +42,7 @@
method public double getValue();
}
- public static final class ActionBuilders.AndroidDoubleExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ public static final class ActionBuilders.AndroidDoubleExtra.Builder {
ctor public ActionBuilders.AndroidDoubleExtra.Builder();
method public androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra build();
method public androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra.Builder setValue(double);
@@ -51,15 +51,11 @@
public static interface ActionBuilders.AndroidExtra {
}
- public static interface ActionBuilders.AndroidExtra.Builder {
- method public androidx.wear.protolayout.ActionBuilders.AndroidExtra build();
- }
-
public static final class ActionBuilders.AndroidIntExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
method public int getValue();
}
- public static final class ActionBuilders.AndroidIntExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ public static final class ActionBuilders.AndroidIntExtra.Builder {
ctor public ActionBuilders.AndroidIntExtra.Builder();
method public androidx.wear.protolayout.ActionBuilders.AndroidIntExtra build();
method public androidx.wear.protolayout.ActionBuilders.AndroidIntExtra.Builder setValue(int);
@@ -69,7 +65,7 @@
method public long getValue();
}
- public static final class ActionBuilders.AndroidLongExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ public static final class ActionBuilders.AndroidLongExtra.Builder {
ctor public ActionBuilders.AndroidLongExtra.Builder();
method public androidx.wear.protolayout.ActionBuilders.AndroidLongExtra build();
method public androidx.wear.protolayout.ActionBuilders.AndroidLongExtra.Builder setValue(long);
@@ -79,7 +75,7 @@
method public String getValue();
}
- public static final class ActionBuilders.AndroidStringExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ public static final class ActionBuilders.AndroidStringExtra.Builder {
ctor public ActionBuilders.AndroidStringExtra.Builder();
method public androidx.wear.protolayout.ActionBuilders.AndroidStringExtra build();
method public androidx.wear.protolayout.ActionBuilders.AndroidStringExtra.Builder setValue(String);
@@ -363,7 +359,7 @@
method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp? getVerticalAlign();
}
- public static final class LayoutElementBuilders.Arc.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Arc.Builder {
ctor public LayoutElementBuilders.Arc.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement);
method public androidx.wear.protolayout.LayoutElementBuilders.Arc build();
@@ -381,7 +377,7 @@
method public androidx.wear.protolayout.TypeBuilders.BoolProp? getRotateContents();
}
- public static final class LayoutElementBuilders.ArcAdapter.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ public static final class LayoutElementBuilders.ArcAdapter.Builder {
ctor public LayoutElementBuilders.ArcAdapter.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter build();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter.Builder setContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
@@ -402,10 +398,6 @@
public static interface LayoutElementBuilders.ArcLayoutElement {
}
- public static interface LayoutElementBuilders.ArcLayoutElement.Builder {
- method public androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement build();
- }
-
public static final class LayoutElementBuilders.ArcLine implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
method public androidx.wear.protolayout.DimensionBuilders.AngularLayoutConstraint? getLayoutConstraintsForDynamicLength();
@@ -415,7 +407,7 @@
method public androidx.wear.protolayout.DimensionBuilders.DpProp? getThickness();
}
- public static final class LayoutElementBuilders.ArcLine.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ public static final class LayoutElementBuilders.ArcLine.Builder {
ctor public LayoutElementBuilders.ArcLine.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine build();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
@@ -433,7 +425,7 @@
method public androidx.wear.protolayout.DimensionBuilders.DpProp? getThickness();
}
- public static final class LayoutElementBuilders.ArcSpacer.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ public static final class LayoutElementBuilders.ArcSpacer.Builder {
ctor public LayoutElementBuilders.ArcSpacer.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer build();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer.Builder setLength(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
@@ -447,7 +439,7 @@
method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
}
- public static final class LayoutElementBuilders.ArcText.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ public static final class LayoutElementBuilders.ArcText.Builder {
ctor public LayoutElementBuilders.ArcText.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcText build();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
@@ -465,7 +457,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
}
- public static final class LayoutElementBuilders.Box.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Box.Builder {
ctor public LayoutElementBuilders.Box.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.LayoutElementBuilders.Box build();
@@ -496,7 +488,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
}
- public static final class LayoutElementBuilders.Column.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Column.Builder {
ctor public LayoutElementBuilders.Column.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.LayoutElementBuilders.Column build();
@@ -524,7 +516,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ExtensionDimension? getWidth();
}
- public static final class LayoutElementBuilders.ExtensionLayoutElement.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.ExtensionLayoutElement.Builder {
ctor public LayoutElementBuilders.ExtensionLayoutElement.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.ExtensionLayoutElement build();
method public androidx.wear.protolayout.LayoutElementBuilders.ExtensionLayoutElement.Builder setExtensionId(String);
@@ -612,7 +604,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ImageDimension? getWidth();
}
- public static final class LayoutElementBuilders.Image.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Image.Builder {
ctor public LayoutElementBuilders.Image.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Image build();
method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setColorFilter(androidx.wear.protolayout.LayoutElementBuilders.ColorFilter);
@@ -641,10 +633,6 @@
public static interface LayoutElementBuilders.LayoutElement {
}
- public static interface LayoutElementBuilders.LayoutElement.Builder {
- method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement build();
- }
-
public static final class LayoutElementBuilders.Row implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getContents();
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getHeight();
@@ -653,7 +641,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
}
- public static final class LayoutElementBuilders.Row.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Row.Builder {
ctor public LayoutElementBuilders.Row.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.LayoutElementBuilders.Row build();
@@ -672,7 +660,7 @@
method public androidx.wear.protolayout.DimensionBuilders.SpacerDimension? getWidth();
}
- public static final class LayoutElementBuilders.Spacer.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Spacer.Builder {
ctor public LayoutElementBuilders.Spacer.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Spacer build();
method public androidx.wear.protolayout.LayoutElementBuilders.Spacer.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.SpacerDimension);
@@ -685,10 +673,6 @@
public static interface LayoutElementBuilders.Span {
}
- public static interface LayoutElementBuilders.Span.Builder {
- method public androidx.wear.protolayout.LayoutElementBuilders.Span build();
- }
-
public static final class LayoutElementBuilders.SpanImage implements androidx.wear.protolayout.LayoutElementBuilders.Span {
method public androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp? getAlignment();
method public androidx.wear.protolayout.DimensionBuilders.DpProp? getHeight();
@@ -697,7 +681,7 @@
method public androidx.wear.protolayout.DimensionBuilders.DpProp? getWidth();
}
- public static final class LayoutElementBuilders.SpanImage.Builder implements androidx.wear.protolayout.LayoutElementBuilders.Span.Builder {
+ public static final class LayoutElementBuilders.SpanImage.Builder {
ctor public LayoutElementBuilders.SpanImage.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage build();
method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setAlignment(androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp);
@@ -716,7 +700,7 @@
method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
}
- public static final class LayoutElementBuilders.SpanText.Builder implements androidx.wear.protolayout.LayoutElementBuilders.Span.Builder {
+ public static final class LayoutElementBuilders.SpanText.Builder {
ctor public LayoutElementBuilders.SpanText.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.SpanText build();
method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setAndroidTextStyle(androidx.wear.protolayout.LayoutElementBuilders.AndroidTextStyle);
@@ -746,7 +730,7 @@
method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.Span!> getSpans();
}
- public static final class LayoutElementBuilders.Spannable.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Spannable.Builder {
ctor public LayoutElementBuilders.Spannable.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder addSpan(androidx.wear.protolayout.LayoutElementBuilders.Span);
method public androidx.wear.protolayout.LayoutElementBuilders.Spannable build();
@@ -784,7 +768,7 @@
method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
}
- public static final class LayoutElementBuilders.Text.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Text.Builder {
ctor public LayoutElementBuilders.Text.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Text build();
method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setAndroidTextStyle(androidx.wear.protolayout.LayoutElementBuilders.AndroidTextStyle);
@@ -1189,7 +1173,7 @@
}
public static final class StateBuilders.State {
- method public java.util.Map<java.lang.String!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!> getIdToValueMapping();
+ method public java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!> getKeyToValueMapping();
method public String getLastClickableId();
method public static int getMaxStateEntryCount();
}
diff --git a/wear/protolayout/protolayout/api/restricted_current.txt b/wear/protolayout/protolayout/api/restricted_current.txt
index 2544ad2..cfb4842 100644
--- a/wear/protolayout/protolayout/api/restricted_current.txt
+++ b/wear/protolayout/protolayout/api/restricted_current.txt
@@ -32,7 +32,7 @@
method public boolean getValue();
}
- public static final class ActionBuilders.AndroidBooleanExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ public static final class ActionBuilders.AndroidBooleanExtra.Builder {
ctor public ActionBuilders.AndroidBooleanExtra.Builder();
method public androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra build();
method public androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra.Builder setValue(boolean);
@@ -42,7 +42,7 @@
method public double getValue();
}
- public static final class ActionBuilders.AndroidDoubleExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ public static final class ActionBuilders.AndroidDoubleExtra.Builder {
ctor public ActionBuilders.AndroidDoubleExtra.Builder();
method public androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra build();
method public androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra.Builder setValue(double);
@@ -51,15 +51,11 @@
public static interface ActionBuilders.AndroidExtra {
}
- public static interface ActionBuilders.AndroidExtra.Builder {
- method public androidx.wear.protolayout.ActionBuilders.AndroidExtra build();
- }
-
public static final class ActionBuilders.AndroidIntExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
method public int getValue();
}
- public static final class ActionBuilders.AndroidIntExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ public static final class ActionBuilders.AndroidIntExtra.Builder {
ctor public ActionBuilders.AndroidIntExtra.Builder();
method public androidx.wear.protolayout.ActionBuilders.AndroidIntExtra build();
method public androidx.wear.protolayout.ActionBuilders.AndroidIntExtra.Builder setValue(int);
@@ -69,7 +65,7 @@
method public long getValue();
}
- public static final class ActionBuilders.AndroidLongExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ public static final class ActionBuilders.AndroidLongExtra.Builder {
ctor public ActionBuilders.AndroidLongExtra.Builder();
method public androidx.wear.protolayout.ActionBuilders.AndroidLongExtra build();
method public androidx.wear.protolayout.ActionBuilders.AndroidLongExtra.Builder setValue(long);
@@ -79,7 +75,7 @@
method public String getValue();
}
- public static final class ActionBuilders.AndroidStringExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ public static final class ActionBuilders.AndroidStringExtra.Builder {
ctor public ActionBuilders.AndroidStringExtra.Builder();
method public androidx.wear.protolayout.ActionBuilders.AndroidStringExtra build();
method public androidx.wear.protolayout.ActionBuilders.AndroidStringExtra.Builder setValue(String);
@@ -363,7 +359,7 @@
method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp? getVerticalAlign();
}
- public static final class LayoutElementBuilders.Arc.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Arc.Builder {
ctor public LayoutElementBuilders.Arc.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement);
method public androidx.wear.protolayout.LayoutElementBuilders.Arc build();
@@ -381,7 +377,7 @@
method public androidx.wear.protolayout.TypeBuilders.BoolProp? getRotateContents();
}
- public static final class LayoutElementBuilders.ArcAdapter.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ public static final class LayoutElementBuilders.ArcAdapter.Builder {
ctor public LayoutElementBuilders.ArcAdapter.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter build();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter.Builder setContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
@@ -402,10 +398,6 @@
public static interface LayoutElementBuilders.ArcLayoutElement {
}
- public static interface LayoutElementBuilders.ArcLayoutElement.Builder {
- method public androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement build();
- }
-
public static final class LayoutElementBuilders.ArcLine implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
method public androidx.wear.protolayout.DimensionBuilders.AngularLayoutConstraint? getLayoutConstraintsForDynamicLength();
@@ -415,7 +407,7 @@
method public androidx.wear.protolayout.DimensionBuilders.DpProp? getThickness();
}
- public static final class LayoutElementBuilders.ArcLine.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ public static final class LayoutElementBuilders.ArcLine.Builder {
ctor public LayoutElementBuilders.ArcLine.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine build();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
@@ -433,7 +425,7 @@
method public androidx.wear.protolayout.DimensionBuilders.DpProp? getThickness();
}
- public static final class LayoutElementBuilders.ArcSpacer.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ public static final class LayoutElementBuilders.ArcSpacer.Builder {
ctor public LayoutElementBuilders.ArcSpacer.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer build();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer.Builder setLength(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
@@ -447,7 +439,7 @@
method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
}
- public static final class LayoutElementBuilders.ArcText.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ public static final class LayoutElementBuilders.ArcText.Builder {
ctor public LayoutElementBuilders.ArcText.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcText build();
method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
@@ -465,7 +457,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
}
- public static final class LayoutElementBuilders.Box.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Box.Builder {
ctor public LayoutElementBuilders.Box.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.LayoutElementBuilders.Box build();
@@ -496,7 +488,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
}
- public static final class LayoutElementBuilders.Column.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Column.Builder {
ctor public LayoutElementBuilders.Column.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.LayoutElementBuilders.Column build();
@@ -524,7 +516,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ExtensionDimension? getWidth();
}
- public static final class LayoutElementBuilders.ExtensionLayoutElement.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.ExtensionLayoutElement.Builder {
ctor public LayoutElementBuilders.ExtensionLayoutElement.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.ExtensionLayoutElement build();
method public androidx.wear.protolayout.LayoutElementBuilders.ExtensionLayoutElement.Builder setExtensionId(String);
@@ -612,7 +604,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ImageDimension? getWidth();
}
- public static final class LayoutElementBuilders.Image.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Image.Builder {
ctor public LayoutElementBuilders.Image.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Image build();
method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setColorFilter(androidx.wear.protolayout.LayoutElementBuilders.ColorFilter);
@@ -641,10 +633,6 @@
public static interface LayoutElementBuilders.LayoutElement {
}
- public static interface LayoutElementBuilders.LayoutElement.Builder {
- method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement build();
- }
-
public static final class LayoutElementBuilders.Row implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getContents();
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getHeight();
@@ -653,7 +641,7 @@
method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
}
- public static final class LayoutElementBuilders.Row.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Row.Builder {
ctor public LayoutElementBuilders.Row.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
method public androidx.wear.protolayout.LayoutElementBuilders.Row build();
@@ -672,7 +660,7 @@
method public androidx.wear.protolayout.DimensionBuilders.SpacerDimension? getWidth();
}
- public static final class LayoutElementBuilders.Spacer.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Spacer.Builder {
ctor public LayoutElementBuilders.Spacer.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Spacer build();
method public androidx.wear.protolayout.LayoutElementBuilders.Spacer.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.SpacerDimension);
@@ -685,10 +673,6 @@
public static interface LayoutElementBuilders.Span {
}
- public static interface LayoutElementBuilders.Span.Builder {
- method public androidx.wear.protolayout.LayoutElementBuilders.Span build();
- }
-
public static final class LayoutElementBuilders.SpanImage implements androidx.wear.protolayout.LayoutElementBuilders.Span {
method public androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp? getAlignment();
method public androidx.wear.protolayout.DimensionBuilders.DpProp? getHeight();
@@ -697,7 +681,7 @@
method public androidx.wear.protolayout.DimensionBuilders.DpProp? getWidth();
}
- public static final class LayoutElementBuilders.SpanImage.Builder implements androidx.wear.protolayout.LayoutElementBuilders.Span.Builder {
+ public static final class LayoutElementBuilders.SpanImage.Builder {
ctor public LayoutElementBuilders.SpanImage.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage build();
method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setAlignment(androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp);
@@ -716,7 +700,7 @@
method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
}
- public static final class LayoutElementBuilders.SpanText.Builder implements androidx.wear.protolayout.LayoutElementBuilders.Span.Builder {
+ public static final class LayoutElementBuilders.SpanText.Builder {
ctor public LayoutElementBuilders.SpanText.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.SpanText build();
method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setAndroidTextStyle(androidx.wear.protolayout.LayoutElementBuilders.AndroidTextStyle);
@@ -746,7 +730,7 @@
method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.Span!> getSpans();
}
- public static final class LayoutElementBuilders.Spannable.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Spannable.Builder {
ctor public LayoutElementBuilders.Spannable.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder addSpan(androidx.wear.protolayout.LayoutElementBuilders.Span);
method public androidx.wear.protolayout.LayoutElementBuilders.Spannable build();
@@ -784,7 +768,7 @@
method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
}
- public static final class LayoutElementBuilders.Text.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ public static final class LayoutElementBuilders.Text.Builder {
ctor public LayoutElementBuilders.Text.Builder();
method public androidx.wear.protolayout.LayoutElementBuilders.Text build();
method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setAndroidTextStyle(androidx.wear.protolayout.LayoutElementBuilders.AndroidTextStyle);
@@ -1189,7 +1173,7 @@
}
public static final class StateBuilders.State {
- method public java.util.Map<java.lang.String!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!> getIdToValueMapping();
+ method public java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!> getKeyToValueMapping();
method public String getLastClickableId();
method public static int getMaxStateEntryCount();
}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ActionBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ActionBuilders.java
index 2007acc..bb10d85 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ActionBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ActionBuilders.java
@@ -131,12 +131,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static AndroidStringExtra fromProto(@NonNull ActionProto.AndroidStringExtra proto) {
- return new AndroidStringExtra(proto, null);
+ public static AndroidStringExtra fromProto(
+ @NonNull ActionProto.AndroidStringExtra proto, @Nullable Fingerprint fingerprint) {
+ return new AndroidStringExtra(proto, fingerprint);
}
@NonNull
+ static AndroidStringExtra fromProto(@NonNull ActionProto.AndroidStringExtra proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
ActionProto.AndroidStringExtra toProto() {
return mImpl;
}
@@ -148,6 +158,12 @@
return ActionProto.AndroidExtra.newBuilder().setStringVal(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "AndroidStringExtra{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link AndroidStringExtra}. */
public static final class Builder implements AndroidExtra.Builder {
private final ActionProto.AndroidStringExtra.Builder mImpl =
@@ -206,12 +222,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static AndroidIntExtra fromProto(@NonNull ActionProto.AndroidIntExtra proto) {
- return new AndroidIntExtra(proto, null);
+ public static AndroidIntExtra fromProto(
+ @NonNull ActionProto.AndroidIntExtra proto, @Nullable Fingerprint fingerprint) {
+ return new AndroidIntExtra(proto, fingerprint);
}
@NonNull
+ static AndroidIntExtra fromProto(@NonNull ActionProto.AndroidIntExtra proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
ActionProto.AndroidIntExtra toProto() {
return mImpl;
}
@@ -223,6 +249,12 @@
return ActionProto.AndroidExtra.newBuilder().setIntVal(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "AndroidIntExtra{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link AndroidIntExtra}. */
public static final class Builder implements AndroidExtra.Builder {
private final ActionProto.AndroidIntExtra.Builder mImpl =
@@ -281,12 +313,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static AndroidLongExtra fromProto(@NonNull ActionProto.AndroidLongExtra proto) {
- return new AndroidLongExtra(proto, null);
+ public static AndroidLongExtra fromProto(
+ @NonNull ActionProto.AndroidLongExtra proto, @Nullable Fingerprint fingerprint) {
+ return new AndroidLongExtra(proto, fingerprint);
}
@NonNull
+ static AndroidLongExtra fromProto(@NonNull ActionProto.AndroidLongExtra proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
ActionProto.AndroidLongExtra toProto() {
return mImpl;
}
@@ -298,6 +340,12 @@
return ActionProto.AndroidExtra.newBuilder().setLongVal(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "AndroidLongExtra{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link AndroidLongExtra}. */
public static final class Builder implements AndroidExtra.Builder {
private final ActionProto.AndroidLongExtra.Builder mImpl =
@@ -356,12 +404,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static AndroidDoubleExtra fromProto(@NonNull ActionProto.AndroidDoubleExtra proto) {
- return new AndroidDoubleExtra(proto, null);
+ public static AndroidDoubleExtra fromProto(
+ @NonNull ActionProto.AndroidDoubleExtra proto, @Nullable Fingerprint fingerprint) {
+ return new AndroidDoubleExtra(proto, fingerprint);
}
@NonNull
+ static AndroidDoubleExtra fromProto(@NonNull ActionProto.AndroidDoubleExtra proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
ActionProto.AndroidDoubleExtra toProto() {
return mImpl;
}
@@ -373,6 +431,12 @@
return ActionProto.AndroidExtra.newBuilder().setDoubleVal(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "AndroidDoubleExtra{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link AndroidDoubleExtra}. */
public static final class Builder implements AndroidExtra.Builder {
private final ActionProto.AndroidDoubleExtra.Builder mImpl =
@@ -431,12 +495,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static AndroidBooleanExtra fromProto(@NonNull ActionProto.AndroidBooleanExtra proto) {
- return new AndroidBooleanExtra(proto, null);
+ public static AndroidBooleanExtra fromProto(
+ @NonNull ActionProto.AndroidBooleanExtra proto, @Nullable Fingerprint fingerprint) {
+ return new AndroidBooleanExtra(proto, fingerprint);
}
@NonNull
+ static AndroidBooleanExtra fromProto(@NonNull ActionProto.AndroidBooleanExtra proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
ActionProto.AndroidBooleanExtra toProto() {
return mImpl;
}
@@ -448,6 +522,12 @@
return ActionProto.AndroidExtra.newBuilder().setBooleanVal(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "AndroidBooleanExtra{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link AndroidBooleanExtra}. */
public static final class Builder implements AndroidExtra.Builder {
private final ActionProto.AndroidBooleanExtra.Builder mImpl =
@@ -484,24 +564,18 @@
* @since 1.0
*/
public interface AndroidExtra {
- /**
- * Get the protocol buffer representation of this object.
- *
- */
+ /** Get the protocol buffer representation of this object. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
ActionProto.AndroidExtra toAndroidExtraProto();
- /**
- * Get the fingerprint for this object or null if unknown.
- *
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
Fingerprint getFingerprint();
/** Builder to create {@link AndroidExtra} objects. */
- @SuppressLint("StaticFinalBuilder")
+ @RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
/** Builds an instance with values accumulated in this Builder. */
@@ -510,26 +584,34 @@
}
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static AndroidExtra androidExtraFromProto(@NonNull ActionProto.AndroidExtra proto) {
+ public static AndroidExtra androidExtraFromProto(
+ @NonNull ActionProto.AndroidExtra proto, @Nullable Fingerprint fingerprint) {
if (proto.hasStringVal()) {
- return AndroidStringExtra.fromProto(proto.getStringVal());
+ return AndroidStringExtra.fromProto(proto.getStringVal(), fingerprint);
}
if (proto.hasIntVal()) {
- return AndroidIntExtra.fromProto(proto.getIntVal());
+ return AndroidIntExtra.fromProto(proto.getIntVal(), fingerprint);
}
if (proto.hasLongVal()) {
- return AndroidLongExtra.fromProto(proto.getLongVal());
+ return AndroidLongExtra.fromProto(proto.getLongVal(), fingerprint);
}
if (proto.hasDoubleVal()) {
- return AndroidDoubleExtra.fromProto(proto.getDoubleVal());
+ return AndroidDoubleExtra.fromProto(proto.getDoubleVal(), fingerprint);
}
if (proto.hasBooleanVal()) {
- return AndroidBooleanExtra.fromProto(proto.getBooleanVal());
+ return AndroidBooleanExtra.fromProto(proto.getBooleanVal(), fingerprint);
}
throw new IllegalStateException("Proto was not a recognised instance of AndroidExtra");
}
+ @NonNull
+ static AndroidExtra androidExtraFromProto(@NonNull ActionProto.AndroidExtra proto) {
+ return androidExtraFromProto(proto, null);
+ }
+
/**
* A launch action to send an intent to an Android activity.
*
@@ -579,26 +661,46 @@
return Collections.unmodifiableMap(map);
}
- /**
- * Get the fingerprint for this object, or null if unknown.
- *
- */
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static AndroidActivity fromProto(@NonNull ActionProto.AndroidActivity proto) {
- return new AndroidActivity(proto, null);
+ public static AndroidActivity fromProto(
+ @NonNull ActionProto.AndroidActivity proto, @Nullable Fingerprint fingerprint) {
+ return new AndroidActivity(proto, fingerprint);
}
@NonNull
- ActionProto.AndroidActivity toProto() {
+ static AndroidActivity fromProto(@NonNull ActionProto.AndroidActivity proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ActionProto.AndroidActivity toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "AndroidActivity{"
+ + "packageName="
+ + getPackageName()
+ + ", className="
+ + getClassName()
+ + ", keyToExtraMapping="
+ + getKeyToExtraMapping()
+ + "}";
+ }
+
/** Builder for {@link AndroidActivity} */
public static final class Builder {
private final ActionProto.AndroidActivity.Builder mImpl =
@@ -691,12 +793,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static LaunchAction fromProto(@NonNull ActionProto.LaunchAction proto) {
- return new LaunchAction(proto, null);
+ public static LaunchAction fromProto(
+ @NonNull ActionProto.LaunchAction proto, @Nullable Fingerprint fingerprint) {
+ return new LaunchAction(proto, fingerprint);
}
@NonNull
+ static LaunchAction fromProto(@NonNull ActionProto.LaunchAction proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
ActionProto.LaunchAction toProto() {
return mImpl;
}
@@ -708,6 +820,12 @@
return ActionProto.Action.newBuilder().setLaunchAction(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "LaunchAction{" + "androidActivity=" + getAndroidActivity() + "}";
+ }
+
/** Builder for {@link LaunchAction}. */
public static final class Builder implements Action.Builder {
private final ActionProto.LaunchAction.Builder mImpl = ActionProto.LaunchAction.newBuilder();
@@ -773,12 +891,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static LoadAction fromProto(@NonNull ActionProto.LoadAction proto) {
- return new LoadAction(proto, null);
+ public static LoadAction fromProto(
+ @NonNull ActionProto.LoadAction proto, @Nullable Fingerprint fingerprint) {
+ return new LoadAction(proto, fingerprint);
}
@NonNull
+ static LoadAction fromProto(@NonNull ActionProto.LoadAction proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
ActionProto.LoadAction toProto() {
return mImpl;
}
@@ -790,6 +918,12 @@
return ActionProto.Action.newBuilder().setLoadAction(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "LoadAction{" + "requestState=" + getRequestState() + "}";
+ }
+
/** Builder for {@link LoadAction}. */
public static final class Builder implements Action.Builder {
private final ActionProto.LoadAction.Builder mImpl = ActionProto.LoadAction.newBuilder();
@@ -826,24 +960,17 @@
* @since 1.0
*/
public interface Action {
- /**
- * Get the protocol buffer representation of this object.
- *
- */
+ /** Get the protocol buffer representation of this object. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
ActionProto.Action toActionProto();
- /**
- * Get the fingerprint for this object or null if unknown.
- *
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
Fingerprint getFingerprint();
/** Builder to create {@link Action} objects. */
- @SuppressLint("StaticFinalBuilder")
@RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
@@ -853,14 +980,22 @@
}
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Action actionFromProto(@NonNull ActionProto.Action proto) {
+ public static Action actionFromProto(
+ @NonNull ActionProto.Action proto, @Nullable Fingerprint fingerprint) {
if (proto.hasLaunchAction()) {
- return LaunchAction.fromProto(proto.getLaunchAction());
+ return LaunchAction.fromProto(proto.getLaunchAction(), fingerprint);
}
if (proto.hasLoadAction()) {
- return LoadAction.fromProto(proto.getLoadAction());
+ return LoadAction.fromProto(proto.getLoadAction(), fingerprint);
}
throw new IllegalStateException("Proto was not a recognised instance of Action");
}
+
+ @NonNull
+ static Action actionFromProto(@NonNull ActionProto.Action proto) {
+ return actionFromProto(proto, null);
+ }
}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ColorBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ColorBuilders.java
index e70f637..6f28d39 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ColorBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ColorBuilders.java
@@ -18,6 +18,8 @@
import static androidx.wear.protolayout.expression.Preconditions.checkNotNull;
+import android.graphics.Color;
+
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -32,7 +34,11 @@
public final class ColorBuilders {
private ColorBuilders() {}
- /** Shortcut for building a {@link ColorProp} using an ARGB value. */
+ /**
+ * Shortcut for building a {@link ColorProp} using an ARGB value.
+ *
+ * @since 1.0
+ */
@NonNull
public static ColorProp argb(@ColorInt int colorArgb) {
return new ColorProp.Builder().setArgb(colorArgb).build();
@@ -53,7 +59,10 @@
}
/**
- * Gets the color value, in ARGB format.
+ * Gets the static color value, in ARGB format. If a dynamic value is also set and the
+ * renderer supports dynamic values for the corresponding field, this static value will be
+ * ignored. If the static value is not specified, zero (equivalent to {@link
+ * Color#TRANSPARENT}) will be used instead.
*
* @since 1.0
*/
@@ -63,7 +72,9 @@
}
/**
- * Gets the dynamic value.
+ * Gets the dynamic value. Note that when setting this value, the static value is still
+ * required to be set to support older renderers that only read the static value. If {@code
+ * dynamicValue} has an invalid result, the provided static value will be used instead.
*
* @since 1.2
*/
@@ -83,13 +94,23 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static ColorProp fromProto(@NonNull ColorProto.ColorProp proto) {
- return new ColorProp(proto, null);
+ public static ColorProp fromProto(
+ @NonNull ColorProto.ColorProp proto, @Nullable Fingerprint fingerprint) {
+ return new ColorProp(proto, fingerprint);
}
@NonNull
- ColorProto.ColorProp toProto() {
+ static ColorProp fromProto(@NonNull ColorProto.ColorProp proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ColorProto.ColorProp toProto() {
return mImpl;
}
@@ -115,9 +136,10 @@
}
/**
- * Sets the color value, in ARGB format.
- * If a dynamic value is also set and the renderer supports dynamic values for the
- * corresponding field, this static value will be ignored.
+ * Sets the static color value, in ARGB format. If a dynamic value is also set and the
+ * renderer supports dynamic values for the corresponding field, this static value
+ * will be ignored. If the static value is not specified, zero (equivalent to {@link
+ * Color#TRANSPARENT}) will be used instead.
*
* @since 1.0
*/
@@ -130,7 +152,9 @@
/**
* Sets the dynamic value. Note that when setting this value, the static value is still
- * required to be set to support older renderers that only read the static value.
+ * required to be set to support older renderers that only read the static value. If
+ * {@code dynamicValue} has an invalid result, the provided static value will be used
+ * instead.
*
* @since 1.2
*/
@@ -142,7 +166,13 @@
return this;
}
- /** Builds an instance from accumulated values. */
+ /**
+ * Builds an instance from accumulated values.
+ *
+ * @throws IllegalStateException if a dynamic value is set using {@link
+ * #setDynamicValue(DynamicColor)} but neither {@link #Builder(int)} nor {@link
+ * #setArgb(int)} is used to provide a static value.
+ */
@NonNull
public ColorProp build() {
if (mImpl.hasDynamicValue() && !mImpl.hasArgb()) {
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DeviceParametersBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DeviceParametersBuilders.java
index b614944..e49c922 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DeviceParametersBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DeviceParametersBuilders.java
@@ -23,6 +23,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.wear.protolayout.expression.ProtoLayoutExperimental;
@@ -167,8 +168,8 @@
/**
* Gets the maximum schema version supported by the current renderer. When building a layout
- * that uses features not available on schema version 1.0 , the result of this method can be
- * used to conditionally choose which feature to use.
+ * that uses features not available on schema version 1.0 , this can be used to conditionally
+ * choose which feature to use.
*
* @since 1.2
*/
@@ -196,11 +197,7 @@
}
}
- /**
- * Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
- * created using this method can't be added to any other wrapper.
- *
- */
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static DeviceParameters fromProto(
@@ -208,16 +205,37 @@
return new DeviceParameters(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DeviceParametersProto.DeviceParameters toProto() {
return mImpl;
}
+ @Override
+ @OptIn(markerClass = ProtoLayoutExperimental.class)
+ @NonNull
+ public String toString() {
+ return "DeviceParameters{"
+ + "screenWidthDp="
+ + getScreenWidthDp()
+ + ", screenHeightDp="
+ + getScreenHeightDp()
+ + ", screenDensity="
+ + getScreenDensity()
+ + ", fontScale="
+ + getFontScale()
+ + ", devicePlatform="
+ + getDevicePlatform()
+ + ", screenShape="
+ + getScreenShape()
+ + ", rendererSchemaVersion="
+ + getRendererSchemaVersion()
+ + ", capabilities="
+ + getCapabilities()
+ + "}";
+ }
+
/** Builder for {@link DeviceParameters} */
public static final class Builder {
private final DeviceParametersProto.DeviceParameters.Builder mImpl =
@@ -296,8 +314,9 @@
}
/**
- * Sets the maximum schema version supported by the current renderer. If not set defaults
- * to schema version 1.0
+ * Sets the maximum schema version supported by the current renderer. When building a layout
+ * that uses features not available on schema version 1.0 , this can be used to conditionally
+ * choose which feature to use.
*
* @since 1.2
*/
@@ -328,10 +347,10 @@
}
/**
- * {@link Capabilities} describing the features that the renderer supports. These features can
- * are not necessarily tied to a specific schema version. Layout providers can use these
- * information to conditionally generate different layouts based on the presence/value of a
- * feature.
+ * {@link Capabilities} describing the features that the renderer supports. These features are not
+ * necessarily tied to a specific schema version. {@link
+ * androidx.wear.protolayout.LayoutElementBuilders.Layout} providers can use these information to
+ * conditionally generate different layouts based on the presence/value of a feature.
*
* @since 1.2
*/
@@ -355,16 +374,29 @@
return mImpl.getMinimumFreshnessLimitMillis();
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Capabilities fromProto(@NonNull DeviceParametersProto.Capabilities proto) {
+ public static Capabilities fromProto(@NonNull DeviceParametersProto.Capabilities proto) {
return new Capabilities(proto);
}
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- DeviceParametersProto.Capabilities toProto() {
+ public DeviceParametersProto.Capabilities toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Capabilities{"
+ + "minimumFreshnessLimitMillis="
+ + getMinimumFreshnessLimitMillis()
+ + "}";
+ }
+
/** Builder for {@link Capabilities} */
public static final class Builder {
private final DeviceParametersProto.Capabilities.Builder mImpl =
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DimensionBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DimensionBuilders.java
index 55627c1..870c33e 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DimensionBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DimensionBuilders.java
@@ -53,11 +53,7 @@
return new SpProp.Builder().setValue(valueSp).build();
}
- /**
- * Shortcut for building a {@link EmProp} using a measurement in EM.
- *
- * @since 1.0
- */
+ /** Shortcut for building a {@link EmProp} using a measurement in EM. */
@NonNull
public static EmProp em(int valueEm) {
return new EmProp.Builder().setValue(valueEm).build();
@@ -105,6 +101,11 @@
return WRAP;
}
+ /**
+ * A type for linear dimensions, measured in dp.
+ *
+ * @since 1.0
+ */
@OptIn(markerClass = ExperimentalProtoLayoutExtensionApi.class)
public static final class DpProp
implements ContainerDimension, ImageDimension, SpacerDimension, ExtensionDimension {
@@ -117,7 +118,9 @@
}
/**
- * Gets the static value, in dp.
+ * Gets the static value, in dp. If a dynamic value is also set and the renderer supports
+ * dynamic values for the corresponding field, this static value will be ignored. If the
+ * static value is not specified, zero will be used instead.
*
* @since 1.0
*/
@@ -127,7 +130,10 @@
}
/**
- * Gets the dynamic value, in dp.
+ * Gets the dynamic value, in dp. Note that when setting this value, the static value is
+ * still required to be set to support older renderers that only read the static value. If
+ * {@code dynamicValue} has an invalid result, the provided static value will be used
+ * instead.
*
* @since 1.2
*/
@@ -199,7 +205,12 @@
@Override
@NonNull
public String toString() {
- return "DpProp{" + "value=" + getValue() + ", dynamicValue=" + getDynamicValue() + "}";
+ return "DpProp{"
+ + "value="
+ + getValue()
+ + ", dynamicValue="
+ + getDynamicValue()
+ + "}";
}
/** Builder for {@link DpProp}. */
@@ -229,7 +240,7 @@
/**
* Sets the static value, in dp. If a dynamic value is also set and the renderer
* supports dynamic values for the corresponding field, this static value will be
- * ignored.
+ * ignored. If the static value is not specified, zero will be used instead.
*
* @since 1.0
*/
@@ -243,6 +254,8 @@
/**
* Sets the dynamic value, in dp. Note that when setting this value, the static value is
* still required to be set to support older renderers that only read the static value.
+ * If {@code dynamicValue} has an invalid result, the provided static value will be used
+ * instead.
*
* @since 1.2
*/
@@ -254,6 +267,13 @@
return this;
}
+ /**
+ * Builds an instance from accumulated values.
+ *
+ * @throws IllegalStateException if a dynamic value is set using {@link
+ * #setDynamicValue(DynamicFloat)} but neither {@link #Builder(float)} nor {@link
+ * #setValue(float)} is used to provide a static value.
+ */
@Override
@NonNull
public DpProp build() {
@@ -525,8 +545,7 @@
public Builder() {}
/**
- * Sets the value, in sp. If a dynamic value is also set and the renderer supports
- * dynamic values for the corresponding field, this static value will be ignored.
+ * Sets the value, in sp.
*
* @since 1.0
*/
@@ -643,7 +662,9 @@
}
/**
- * Gets the static value, in degrees.
+ * Gets the static value, in degrees. If a dynamic value is also set and the renderer
+ * supports dynamic values for the corresponding field, this static value will be ignored.
+ * If the static value is not specified, zero will be used instead.
*
* @since 1.0
*/
@@ -652,7 +673,10 @@
}
/**
- * Gets the dynamic value, in degrees.
+ * Gets the dynamic value, in degrees. Note that when setting this value, the static value
+ * is still required to be set to support older renderers that only read the static value.
+ * If {@code dynamicValue} has an invalid result, the provided static value will be used
+ * instead.
*
* @since 1.2
*/
@@ -727,7 +751,7 @@
/**
* Sets the static value, in degrees. If a dynamic value is also set and the renderer
* supports dynamic values for the corresponding field, this static value will be
- * ignored.
+ * ignored. If the static value is not specified, zero will be used instead.
*
* @since 1.0
*/
@@ -741,7 +765,8 @@
/**
* Sets the dynamic value, in degrees. Note that when setting this value, the static
* value is still required to be set to support older renderers that only read the
- * static value.
+ * static value. If {@code dynamicValue} has an invalid result, the provided static
+ * value will be used instead.
*
* @since 1.2
*/
@@ -753,7 +778,13 @@
return this;
}
- /** Builds an instance from accumulated values. */
+ /**
+ * Builds an instance from accumulated values.
+ *
+ * @throws IllegalStateException if a dynamic value is set using {@link
+ * #setDynamicValue(DynamicFloat)} but neither {@link #Builder(float)} nor {@link
+ * #setValue(float)} is used to provide a static value.
+ */
@NonNull
public DegreesProp build() {
if (mImpl.hasDynamicValue() && !mImpl.hasValue()) {
@@ -950,6 +981,12 @@
return DimensionProto.ImageDimension.newBuilder().setExpandedDimension(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ExpandedDimensionProp{" + "layoutWeight=" + getLayoutWeight() + "}";
+ }
+
/** Builder for {@link ExpandedDimensionProp}. */
public static final class Builder
implements ContainerDimension.Builder, ImageDimension.Builder {
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
index 1930199..fff3924 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2022 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.
@@ -70,27 +70,49 @@
public final class LayoutElementBuilders {
private LayoutElementBuilders() {}
- /** The weight to be applied to the font. */
+ /**
+ * The weight to be applied to the font.
+ *
+ * @since 1.0
+ */
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({FONT_WEIGHT_UNDEFINED, FONT_WEIGHT_NORMAL, FONT_WEIGHT_MEDIUM, FONT_WEIGHT_BOLD})
@Retention(RetentionPolicy.SOURCE)
public @interface FontWeight {}
- /** Font weight is undefined. */
+ /**
+ * Font weight is undefined.
+ *
+ * @since 1.0
+ */
public static final int FONT_WEIGHT_UNDEFINED = 0;
- /** Normal font weight. */
+ /**
+ * Normal font weight.
+ *
+ * @since 1.0
+ */
public static final int FONT_WEIGHT_NORMAL = 400;
- /** Medium font weight. */
+ /**
+ * Medium font weight.
+ *
+ * @since 1.0
+ */
@ProtoLayoutExperimental public static final int FONT_WEIGHT_MEDIUM = 500;
- /** Bold font weight. */
+ /**
+ * Bold font weight.
+ *
+ * @since 1.0
+ */
public static final int FONT_WEIGHT_BOLD = 700;
/**
* The variant of a font. Some renderers may use different fonts for title and body text, which
* can be selected using this field.
+ *
+ * @since 1.0
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
@@ -103,13 +125,25 @@
@OptIn(markerClass = ProtoLayoutExperimental.class)
public @interface FontVariant {}
- /** Font variant is undefined. */
+ /**
+ * Font variant is undefined.
+ *
+ * @since 1.0
+ */
public static final int FONT_VARIANT_UNDEFINED = 0;
- /** Font variant suited for title text. */
+ /**
+ * Font variant suited for title text.
+ *
+ * @since 1.0
+ */
public static final int FONT_VARIANT_TITLE = 1;
- /** Font variant suited for body text. */
+ /**
+ * Font variant suited for body text.
+ *
+ * @since 1.0
+ */
public static final int FONT_VARIANT_BODY = 2;
/** Renderer dependent Font variant. If not supported, will behave similar to
@@ -122,6 +156,8 @@
/**
* The alignment of a {@link SpanImage} within the line height of the surrounding {@link
* Spannable}.
+ *
+ * @since 1.0
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
@@ -132,13 +168,19 @@
@Retention(RetentionPolicy.SOURCE)
public @interface SpanVerticalAlignment {}
- /** Alignment is undefined. */
+ /**
+ * Alignment is undefined.
+ *
+ * @since 1.0
+ */
public static final int SPAN_VERTICAL_ALIGN_UNDEFINED = 0;
/**
* Align to the bottom of the line (descent of the largest text in this line). If there is no
* text in the line containing this image, this will align to the bottom of the line, where the
* line height is defined as the height of the largest image in the line.
+ *
+ * @since 1.0
*/
public static final int SPAN_VERTICAL_ALIGN_BOTTOM = 1;
@@ -146,6 +188,8 @@
* Align to the baseline of the text. Note that if the line in the {@link Spannable} which
* contains this image does not contain any text, the effects of using this alignment are
* undefined.
+ *
+ * @since 1.0
*/
public static final int SPAN_VERTICAL_ALIGN_TEXT_BASELINE = 2;
@@ -200,6 +244,8 @@
/**
* How content which does not match the dimensions of its bounds (e.g. an image resource being
* drawn inside an {@link Image}) will be resized to fit its bounds.
+ *
+ * @since 1.0
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
@@ -211,13 +257,19 @@
@Retention(RetentionPolicy.SOURCE)
public @interface ContentScaleMode {}
- /** Content scaling is undefined. */
+ /**
+ * Content scaling is undefined.
+ *
+ * @since 1.0
+ */
public static final int CONTENT_SCALE_MODE_UNDEFINED = 0;
/**
* Content will be scaled to fit inside its bounds, proportionally. As an example, If a 10x5
* image was going to be drawn inside a 50x50 {@link Image} element, the actual image resource
* would be drawn as a 50x25 image, centered within the 50x50 bounds.
+ *
+ * @since 1.0
*/
public static final int CONTENT_SCALE_MODE_FIT = 1;
@@ -226,6 +278,8 @@
* outside of the bounds will be cropped. As an example, if a 10x5 image was going to be drawn
* inside a 50x50 {@link Image} element, the image resource would be drawn as a 100x50 image,
* centered within its bounds (and with 25px cropped from both the left and right sides).
+ *
+ * @since 1.0
*/
public static final int CONTENT_SCALE_MODE_CROP = 2;
@@ -233,6 +287,8 @@
* Content will be resized to fill its bounds, without taking into account the aspect ratio. If
* a 10x5 image was going to be drawn inside a 50x50 {@link Image} element, the image would be
* drawn as a 50x50 image, stretched vertically.
+ *
+ * @since 1.0
*/
public static final int CONTENT_SCALE_MODE_FILL_BOUNDS = 3;
@@ -276,7 +332,11 @@
*/
public static final int STROKE_CAP_SQUARE = 3;
- /** An extensible {@code FontWeight} property. */
+ /**
+ * An extensible {@code FontWeight} property.
+ *
+ * @since 1.0
+ */
public static final class FontWeightProp {
private final LayoutElementProto.FontWeightProp mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -286,7 +346,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the value. Intended for testing purposes only. */
+ /**
+ * Gets the value.
+ *
+ * @since 1.0
+ */
@FontWeight
public int getValue() {
return mImpl.getValue().getNumber();
@@ -299,25 +363,46 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static FontWeightProp fromProto(@NonNull LayoutElementProto.FontWeightProp proto) {
- return new FontWeightProp(proto, null);
+ public static FontWeightProp fromProto(
+ @NonNull LayoutElementProto.FontWeightProp proto,
+ @Nullable Fingerprint fingerprint) {
+ return new FontWeightProp(proto, fingerprint);
}
@NonNull
- LayoutElementProto.FontWeightProp toProto() {
+ static FontWeightProp fromProto(@NonNull LayoutElementProto.FontWeightProp proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.FontWeightProp toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "FontWeightProp{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link FontWeightProp} */
public static final class Builder {
private final LayoutElementProto.FontWeightProp.Builder mImpl =
LayoutElementProto.FontWeightProp.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(1793388920);
+ private final Fingerprint mFingerprint = new Fingerprint(-1485961687);
public Builder() {}
- /** Sets the value. */
+ /**
+ * Sets the value.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setValue(@FontWeight int value) {
mImpl.setValue(LayoutElementProto.FontWeight.forNumber(value));
@@ -333,7 +418,11 @@
}
}
- /** An extensible {@code FontVariant} property. */
+ /**
+ * An extensible {@code FontVariant} property.
+ *
+ * @since 1.0
+ */
@ProtoLayoutExperimental
public static final class FontVariantProp {
private final LayoutElementProto.FontVariantProp mImpl;
@@ -345,7 +434,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the value. Intended for testing purposes only. */
+ /**
+ * Gets the value.
+ *
+ * @since 1.0
+ */
@FontVariant
public int getValue() {
return mImpl.getValue().getNumber();
@@ -358,25 +451,46 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static FontVariantProp fromProto(@NonNull LayoutElementProto.FontVariantProp proto) {
- return new FontVariantProp(proto, null);
+ public static FontVariantProp fromProto(
+ @NonNull LayoutElementProto.FontVariantProp proto,
+ @Nullable Fingerprint fingerprint) {
+ return new FontVariantProp(proto, fingerprint);
}
@NonNull
- LayoutElementProto.FontVariantProp toProto() {
+ static FontVariantProp fromProto(@NonNull LayoutElementProto.FontVariantProp proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.FontVariantProp toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "FontVariantProp{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link FontVariantProp} */
public static final class Builder {
private final LayoutElementProto.FontVariantProp.Builder mImpl =
LayoutElementProto.FontVariantProp.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(-293831500);
+ private final Fingerprint mFingerprint = new Fingerprint(-295272526);
public Builder() {}
- /** Sets the value. */
+ /**
+ * Sets the value.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setValue(@FontVariant int value) {
mImpl.setValue(LayoutElementProto.FontVariant.forNumber(value));
@@ -392,7 +506,11 @@
}
}
- /** An extensible {@code SpanVerticalAlignment} property. */
+ /**
+ * An extensible {@code SpanVerticalAlignment} property.
+ *
+ * @since 1.0
+ */
public static final class SpanVerticalAlignmentProp {
private final LayoutElementProto.SpanVerticalAlignmentProp mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -404,7 +522,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the value. Intended for testing purposes only. */
+ /**
+ * Gets the value.
+ *
+ * @since 1.0
+ */
@SpanVerticalAlignment
public int getValue() {
return mImpl.getValue().getNumber();
@@ -417,26 +539,47 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static SpanVerticalAlignmentProp fromProto(
- @NonNull LayoutElementProto.SpanVerticalAlignmentProp proto) {
- return new SpanVerticalAlignmentProp(proto, null);
+ public static SpanVerticalAlignmentProp fromProto(
+ @NonNull LayoutElementProto.SpanVerticalAlignmentProp proto,
+ @Nullable Fingerprint fingerprint) {
+ return new SpanVerticalAlignmentProp(proto, fingerprint);
}
@NonNull
- LayoutElementProto.SpanVerticalAlignmentProp toProto() {
+ static SpanVerticalAlignmentProp fromProto(
+ @NonNull LayoutElementProto.SpanVerticalAlignmentProp proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.SpanVerticalAlignmentProp toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "SpanVerticalAlignmentProp{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link SpanVerticalAlignmentProp} */
public static final class Builder {
private final LayoutElementProto.SpanVerticalAlignmentProp.Builder mImpl =
LayoutElementProto.SpanVerticalAlignmentProp.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(1008812329);
+ private final Fingerprint mFingerprint = new Fingerprint(-1822193880);
public Builder() {}
- /** Sets the value. */
+ /**
+ * Sets the value.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setValue(@SpanVerticalAlignment int value) {
mImpl.setValue(LayoutElementProto.SpanVerticalAlignment.forNumber(value));
@@ -452,7 +595,11 @@
}
}
- /** The styling of a font (e.g. font size, and metrics). */
+ /**
+ * The styling of a font (e.g. font size, and metrics).
+ *
+ * @since 1.0
+ */
public static final class FontStyle {
private final LayoutElementProto.FontStyle mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -464,7 +611,9 @@
/**
* Gets the size of the font, in scaled pixels (sp). If not specified, defaults to the size
- * of the system's "body" font. Intended for testing purposes only.
+ * of the system's "body" font.
+ *
+ * @since 1.0
*/
@Nullable
public SpProp getSize() {
@@ -477,7 +626,9 @@
/**
* Gets whether the text should be rendered in a italic typeface. If not specified, defaults
- * to "false". Intended for testing purposes only.
+ * to "false".
+ *
+ * @since 1.0
*/
@Nullable
public BoolProp getItalic() {
@@ -490,7 +641,9 @@
/**
* Gets whether the text should be rendered with an underline. If not specified, defaults to
- * "false". Intended for testing purposes only.
+ * "false".
+ *
+ * @since 1.0
*/
@Nullable
public BoolProp getUnderline() {
@@ -518,7 +671,9 @@
/**
* Gets the weight of the font. If the provided value is not supported on a platform, the
* nearest supported value will be used. If not defined, or when set to an invalid value,
- * defaults to "normal". Intended for testing purposes only.
+ * defaults to "normal".
+ *
+ * @since 1.0
*/
@Nullable
public FontWeightProp getWeight() {
@@ -531,8 +686,9 @@
/**
* Gets the text letter-spacing. Positive numbers increase the space between letters while
- * negative numbers tighten the space. If not specified, defaults to 0. Intended for testing
- * purposes only.
+ * negative numbers tighten the space. If not specified, defaults to 0.
+ *
+ * @since 1.0
*/
@Nullable
public EmProp getLetterSpacing() {
@@ -546,7 +702,8 @@
/**
* Gets the variant of a font. Some renderers may use different fonts for title and body
* text, which can be selected using this field. If not specified, defaults to "body".
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@ProtoLayoutExperimental
@Nullable
@@ -565,9 +722,17 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public static FontStyle fromProto(
+ @NonNull LayoutElementProto.FontStyle proto, @Nullable Fingerprint fingerprint) {
+ return new FontStyle(proto, fingerprint);
+ }
+
@NonNull
static FontStyle fromProto(@NonNull LayoutElementProto.FontStyle proto) {
- return new FontStyle(proto, null);
+ return fromProto(proto, null);
}
/** Returns the internal proto instance. */
@@ -577,17 +742,41 @@
return mImpl;
}
+ @Override
+ @OptIn(markerClass = ProtoLayoutExperimental.class)
+ @NonNull
+ public String toString() {
+ return "FontStyle{"
+ + "size="
+ + getSize()
+ + ", italic="
+ + getItalic()
+ + ", underline="
+ + getUnderline()
+ + ", color="
+ + getColor()
+ + ", weight="
+ + getWeight()
+ + ", letterSpacing="
+ + getLetterSpacing()
+ + ", variant="
+ + getVariant()
+ + "}";
+ }
+
/** Builder for {@link FontStyle} */
public static final class Builder {
private final LayoutElementProto.FontStyle.Builder mImpl =
LayoutElementProto.FontStyle.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(181264306);
+ private final Fingerprint mFingerprint = new Fingerprint(-374492482);
public Builder() {}
/**
* Sets the size of the font, in scaled pixels (sp). If not specified, defaults to the
* size of the system's "body" font.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setSize(@NonNull SpProp size) {
@@ -600,6 +789,8 @@
/**
* Sets whether the text should be rendered in a italic typeface. If not specified,
* defaults to "false".
+ *
+ * @since 1.0
*/
@NonNull
public Builder setItalic(@NonNull BoolProp italic) {
@@ -621,6 +812,8 @@
/**
* Sets whether the text should be rendered with an underline. If not specified,
* defaults to "false".
+ *
+ * @since 1.0
*/
@NonNull
public Builder setUnderline(@NonNull BoolProp underline) {
@@ -660,6 +853,8 @@
* Sets the weight of the font. If the provided value is not supported on a platform,
* the nearest supported value will be used. If not defined, or when set to an invalid
* value, defaults to "normal".
+ *
+ * @since 1.0
*/
@NonNull
public Builder setWeight(@NonNull FontWeightProp weight) {
@@ -668,22 +863,28 @@
5, checkNotNull(weight.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the weight of the font. If the provided value is not supported on a platform,
* the nearest supported value will be used. If not defined, or when set to an invalid
* value, defaults to "normal".
+ *
+ * @since 1.0
*/
@NonNull
public Builder setWeight(@FontWeight int weight) {
mImpl.setWeight(
LayoutElementProto.FontWeightProp.newBuilder()
.setValue(LayoutElementProto.FontWeight.forNumber(weight)));
+ mFingerprint.recordPropertyUpdate(5, weight);
return this;
}
/**
* Sets the text letter-spacing. Positive numbers increase the space between letters
* while negative numbers tighten the space. If not specified, defaults to 0.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setLetterSpacing(@NonNull EmProp letterSpacing) {
@@ -696,16 +897,23 @@
/**
* Sets the variant of a font. Some renderers may use different fonts for title and body
* text, which can be selected using this field. If not specified, defaults to "body".
+ *
+ * @since 1.0
*/
@ProtoLayoutExperimental
@NonNull
public Builder setVariant(@NonNull FontVariantProp variant) {
mImpl.setVariant(variant.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 7, checkNotNull(variant.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the variant of a font. Some renderers may use different fonts for title and body
* text, which can be selected using this field. If not specified, defaults to "body".
+ *
+ * @since 1.0
*/
@ProtoLayoutExperimental
@NonNull
@@ -713,6 +921,7 @@
mImpl.setVariant(
LayoutElementProto.FontVariantProp.newBuilder()
.setValue(LayoutElementProto.FontVariant.forNumber(variant)));
+ mFingerprint.recordPropertyUpdate(7, variant);
return this;
}
@@ -992,7 +1201,11 @@
}
}
- /** A text string. */
+ /**
+ * A text string.
+ *
+ * @since 1.0
+ */
public static final class Text implements LayoutElement {
private final LayoutElementProto.Text mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -1033,7 +1246,9 @@
/**
* Gets the style of font to use (size, bold etc). If not specified, defaults to the
- * platform's default body font. Intended for testing purposes only.
+ * platform's default body font.
+ *
+ * @since 1.0
*/
@Nullable
public FontStyle getFontStyle() {
@@ -1046,7 +1261,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public Modifiers getModifiers() {
@@ -1059,8 +1275,9 @@
/**
* Gets the maximum number of lines that can be represented by the {@link Text} element. If
- * not defined, the {@link Text} element will be treated as a single-line element. Intended
- * for testing purposes only.
+ * not defined, the {@link Text} element will be treated as a single-line element.
+ *
+ * @since 1.0
*/
@Nullable
public Int32Prop getMaxLines() {
@@ -1076,7 +1293,9 @@
* itself to wrap its contents, so this option is meaningless for single-line text (for
* that, use alignment of the outer container). For multi-line text, however, this will set
* the alignment of lines relative to the {@link Text} element bounds. If not defined,
- * defaults to TEXT_ALIGN_CENTER. Intended for testing purposes only.
+ * defaults to TEXT_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@Nullable
public TextAlignmentProp getMultilineAlignment() {
@@ -1092,7 +1311,9 @@
* Text} element will grow as large as possible inside its parent container (while still
* respecting max_lines); if it cannot grow large enough to render all of its text, the text
* which cannot fit inside its container will be truncated. If not defined, defaults to
- * TEXT_OVERFLOW_TRUNCATE. Intended for testing purposes only.
+ * TEXT_OVERFLOW_TRUNCATE.
+ *
+ * @since 1.0
*/
@Nullable
public TextOverflowProp getOverflow() {
@@ -1106,7 +1327,9 @@
/**
* Gets the explicit height between lines of text. This is equivalent to the vertical
* distance between subsequent baselines. If not specified, defaults the font's recommended
- * interline spacing. Intended for testing purposes only.
+ * interline spacing.
+ *
+ * @since 1.0
*/
@Nullable
public SpProp getLineHeight() {
@@ -1152,12 +1375,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Text fromProto(@NonNull LayoutElementProto.Text proto) {
- return new Text(proto, null);
+ public static Text fromProto(
+ @NonNull LayoutElementProto.Text proto, @Nullable Fingerprint fingerprint) {
+ return new Text(proto, fingerprint);
}
@NonNull
+ static Text fromProto(@NonNull LayoutElementProto.Text proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.Text toProto() {
return mImpl;
}
@@ -1169,11 +1402,35 @@
return LayoutElementProto.LayoutElement.newBuilder().setText(mImpl).build();
}
+ @Override
+ @OptIn(markerClass = ProtoLayoutExperimental.class)
+ @NonNull
+ public String toString() {
+ return "Text{"
+ + "text="
+ + getText()
+ + ", fontStyle="
+ + getFontStyle()
+ + ", modifiers="
+ + getModifiers()
+ + ", maxLines="
+ + getMaxLines()
+ + ", multilineAlignment="
+ + getMultilineAlignment()
+ + ", overflow="
+ + getOverflow()
+ + ", lineHeight="
+ + getLineHeight()
+ + ", androidTextStyle="
+ + getAndroidTextStyle()
+ + "}";
+ }
+
/** Builder for {@link Text}. */
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Text.Builder mImpl =
LayoutElementProto.Text.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(1976530157);
+ private final Fingerprint mFingerprint = new Fingerprint(814133697);
public Builder() {}
@@ -1229,6 +1486,8 @@
/**
* Sets the style of font to use (size, bold etc). If not specified, defaults to the
* platform's default body font.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setFontStyle(@NonNull FontStyle fontStyle) {
@@ -1240,6 +1499,8 @@
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull Modifiers modifiers) {
@@ -1252,6 +1513,8 @@
/**
* Sets the maximum number of lines that can be represented by the {@link Text} element.
* If not defined, the {@link Text} element will be treated as a single-line element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setMaxLines(@NonNull Int32Prop maxLines) {
@@ -1276,6 +1539,8 @@
* (for that, use alignment of the outer container). For multi-line text, however, this
* will set the alignment of lines relative to the {@link Text} element bounds. If not
* defined, defaults to TEXT_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setMultilineAlignment(@NonNull TextAlignmentProp multilineAlignment) {
@@ -1284,12 +1549,15 @@
5, checkNotNull(multilineAlignment.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets alignment of the text within its bounds. Note that a {@link Text} element will
* size itself to wrap its contents, so this option is meaningless for single-line text
* (for that, use alignment of the outer container). For multi-line text, however, this
* will set the alignment of lines relative to the {@link Text} element bounds. If not
* defined, defaults to TEXT_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setMultilineAlignment(@TextAlignment int multilineAlignment) {
@@ -1307,6 +1575,8 @@
* (while still respecting max_lines); if it cannot grow large enough to render all of
* its text, the text which cannot fit inside its container will be truncated. If not
* defined, defaults to TEXT_OVERFLOW_TRUNCATE.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setOverflow(@NonNull TextOverflowProp overflow) {
@@ -1315,12 +1585,15 @@
6, checkNotNull(overflow.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets how to handle text which overflows the bound of the {@link Text} element. A
* {@link Text} element will grow as large as possible inside its parent container
* (while still respecting max_lines); if it cannot grow large enough to render all of
* its text, the text which cannot fit inside its container will be truncated. If not
* defined, defaults to TEXT_OVERFLOW_TRUNCATE.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setOverflow(@TextOverflow int overflow) {
@@ -1334,6 +1607,8 @@
* Sets the explicit height between lines of text. This is equivalent to the vertical
* distance between subsequent baselines. If not specified, defaults the font's
* recommended interline spacing.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setLineHeight(@NonNull SpProp lineHeight) {
@@ -1389,7 +1664,11 @@
}
}
- /** An extensible {@code ContentScaleMode} property. */
+ /**
+ * An extensible {@code ContentScaleMode} property.
+ *
+ * @since 1.0
+ */
public static final class ContentScaleModeProp {
private final LayoutElementProto.ContentScaleModeProp mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -1400,7 +1679,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the value. Intended for testing purposes only. */
+ /**
+ * Gets the value.
+ *
+ * @since 1.0
+ */
@ContentScaleMode
public int getValue() {
return mImpl.getValue().getNumber();
@@ -1413,26 +1696,47 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static ContentScaleModeProp fromProto(
- @NonNull LayoutElementProto.ContentScaleModeProp proto) {
- return new ContentScaleModeProp(proto, null);
+ public static ContentScaleModeProp fromProto(
+ @NonNull LayoutElementProto.ContentScaleModeProp proto,
+ @Nullable Fingerprint fingerprint) {
+ return new ContentScaleModeProp(proto, fingerprint);
}
@NonNull
- LayoutElementProto.ContentScaleModeProp toProto() {
+ static ContentScaleModeProp fromProto(
+ @NonNull LayoutElementProto.ContentScaleModeProp proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.ContentScaleModeProp toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ContentScaleModeProp{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link ContentScaleModeProp} */
public static final class Builder {
private final LayoutElementProto.ContentScaleModeProp.Builder mImpl =
LayoutElementProto.ContentScaleModeProp.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(-893830536);
+ private final Fingerprint mFingerprint = new Fingerprint(1200564005);
public Builder() {}
- /** Sets the value. */
+ /**
+ * Sets the value.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setValue(@ContentScaleMode int value) {
mImpl.setValue(LayoutElementProto.ContentScaleMode.forNumber(value));
@@ -1448,7 +1752,11 @@
}
}
- /** Filtering parameters used for images. This can be used to apply a color tint to images. */
+ /**
+ * Filtering parameters used for images. This can be used to apply a color tint to images.
+ *
+ * @since 1.0
+ */
public static final class ColorFilter {
private final LayoutElementProto.ColorFilter mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -1484,21 +1792,37 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static ColorFilter fromProto(@NonNull LayoutElementProto.ColorFilter proto) {
- return new ColorFilter(proto, null);
+ public static ColorFilter fromProto(
+ @NonNull LayoutElementProto.ColorFilter proto, @Nullable Fingerprint fingerprint) {
+ return new ColorFilter(proto, fingerprint);
}
@NonNull
- LayoutElementProto.ColorFilter toProto() {
+ static ColorFilter fromProto(@NonNull LayoutElementProto.ColorFilter proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.ColorFilter toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ColorFilter{" + "tint=" + getTint() + "}";
+ }
+
/** Builder for {@link ColorFilter} */
public static final class Builder {
private final LayoutElementProto.ColorFilter.Builder mImpl =
LayoutElementProto.ColorFilter.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(181311326);
+ private final Fingerprint mFingerprint = new Fingerprint(1912021459);
public Builder() {}
@@ -1537,6 +1861,8 @@
* <p>Images used in this element must exist in the resource bundle that corresponds to this
* layout. Images must have their dimension specified, and will be rendered at this width and
* height, regardless of their native dimension.
+ *
+ * @since 1.0
*/
public static final class Image implements LayoutElement {
private final LayoutElementProto.Image mImpl;
@@ -1549,7 +1875,9 @@
/**
* Gets the resource_id of the image to render. This must exist in the supplied resource
- * bundle. Intended for testing purposes only.
+ * bundle.
+ *
+ * @since 1.0
*/
@Nullable
public StringProp getResourceId() {
@@ -1561,8 +1889,9 @@
}
/**
- * Gets the width of this image. If not defined, the image will not be rendered. Intended
- * for testing purposes only.
+ * Gets the width of this image. If not defined, the image will not be rendered.
+ *
+ * @since 1.0
*/
@Nullable
public ImageDimension getWidth() {
@@ -1574,8 +1903,9 @@
}
/**
- * Gets the height of this image. If not defined, the image will not be rendered. Intended
- * for testing purposes only.
+ * Gets the height of this image. If not defined, the image will not be rendered.
+ *
+ * @since 1.0
*/
@Nullable
public ImageDimension getHeight() {
@@ -1588,8 +1918,9 @@
/**
* Gets how to scale the image resource inside the bounds specified by width/height if its
- * size does not match those bounds. Defaults to CONTENT_SCALE_MODE_FIT. Intended for
- * testing purposes only.
+ * size does not match those bounds. Defaults to CONTENT_SCALE_MODE_FIT.
+ *
+ * @since 1.0
*/
@Nullable
public ContentScaleModeProp getContentScaleMode() {
@@ -1602,7 +1933,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public Modifiers getModifiers() {
@@ -1615,7 +1947,8 @@
/**
* Gets filtering parameters for this image. If not specified, defaults to no filtering.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public ColorFilter getColorFilter() {
@@ -1633,12 +1966,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Image fromProto(@NonNull LayoutElementProto.Image proto) {
- return new Image(proto, null);
+ public static Image fromProto(
+ @NonNull LayoutElementProto.Image proto, @Nullable Fingerprint fingerprint) {
+ return new Image(proto, fingerprint);
}
@NonNull
+ static Image fromProto(@NonNull LayoutElementProto.Image proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.Image toProto() {
return mImpl;
}
@@ -1650,11 +1993,30 @@
return LayoutElementProto.LayoutElement.newBuilder().setImage(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Image{"
+ + "resourceId="
+ + getResourceId()
+ + ", width="
+ + getWidth()
+ + ", height="
+ + getHeight()
+ + ", contentScaleMode="
+ + getContentScaleMode()
+ + ", modifiers="
+ + getModifiers()
+ + ", colorFilter="
+ + getColorFilter()
+ + "}";
+ }
+
/** Builder for {@link Image}. */
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Image.Builder mImpl =
LayoutElementProto.Image.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(-543078544);
+ private final Fingerprint mFingerprint = new Fingerprint(-48009959);
public Builder() {}
@@ -1677,9 +2039,12 @@
1, checkNotNull(resourceId.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the resource_id of the image to render. This must exist in the supplied resource
* bundle.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setResourceId(@NonNull String resourceId) {
@@ -1687,7 +2052,11 @@
return this;
}
- /** Sets the width of this image. If not defined, the image will not be rendered. */
+ /**
+ * Sets the width of this image. If not defined, the image will not be rendered.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setWidth(@NonNull ImageDimension width) {
mImpl.setWidth(width.toImageDimensionProto());
@@ -1696,7 +2065,11 @@
return this;
}
- /** Sets the height of this image. If not defined, the image will not be rendered. */
+ /**
+ * Sets the height of this image. If not defined, the image will not be rendered.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setHeight(@NonNull ImageDimension height) {
mImpl.setHeight(height.toImageDimensionProto());
@@ -1708,6 +2081,8 @@
/**
* Sets how to scale the image resource inside the bounds specified by width/height if
* its size does not match those bounds. Defaults to CONTENT_SCALE_MODE_FIT.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setContentScaleMode(@NonNull ContentScaleModeProp contentScaleMode) {
@@ -1716,9 +2091,12 @@
4, checkNotNull(contentScaleMode.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets how to scale the image resource inside the bounds specified by width/height if
* its size does not match those bounds. Defaults to CONTENT_SCALE_MODE_FIT.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setContentScaleMode(@ContentScaleMode int contentScaleMode) {
@@ -1727,11 +2105,14 @@
.setValue(
LayoutElementProto.ContentScaleMode.forNumber(
contentScaleMode)));
+ mFingerprint.recordPropertyUpdate(4, contentScaleMode);
return this;
}
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull Modifiers modifiers) {
@@ -1743,6 +2124,8 @@
/**
* Sets filtering parameters for this image. If not specified, defaults to no filtering.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setColorFilter(@NonNull ColorFilter colorFilter) {
@@ -1760,7 +2143,11 @@
}
}
- /** A simple spacer, typically used to provide padding between adjacent elements. */
+ /**
+ * A simple spacer, typically used to provide padding between adjacent elements.
+ *
+ * @since 1.0
+ */
public static final class Spacer implements LayoutElement {
private final LayoutElementProto.Spacer mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -1833,6 +2220,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
* Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public Modifiers getModifiers() {
@@ -1850,12 +2239,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Spacer fromProto(@NonNull LayoutElementProto.Spacer proto) {
- return new Spacer(proto, null);
+ public static Spacer fromProto(
+ @NonNull LayoutElementProto.Spacer proto, @Nullable Fingerprint fingerprint) {
+ return new Spacer(proto, fingerprint);
}
@NonNull
+ static Spacer fromProto(@NonNull LayoutElementProto.Spacer proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.Spacer toProto() {
return mImpl;
}
@@ -1867,11 +2266,24 @@
return LayoutElementProto.LayoutElement.newBuilder().setSpacer(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Spacer{"
+ + "width="
+ + getWidth()
+ + ", height="
+ + getHeight()
+ + ", modifiers="
+ + getModifiers()
+ + "}";
+ }
+
/** Builder for {@link Spacer}. */
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Spacer.Builder mImpl =
LayoutElementProto.Spacer.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(-1748084575);
+ private final Fingerprint mFingerprint = new Fingerprint(-156449821);
public Builder() {}
@@ -1969,6 +2381,8 @@
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull Modifiers modifiers) {
@@ -2001,6 +2415,8 @@
/**
* A container which stacks all of its children on top of one another. This also allows to add a
* background color, or to have a border around them with some padding.
+ *
+ * @since 1.0
*/
public static final class Box implements LayoutElement {
private final LayoutElementProto.Box mImpl;
@@ -2011,7 +2427,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the child element(s) to wrap. Intended for testing purposes only. */
+ /**
+ * Gets the child element(s) to wrap.
+ *
+ * @since 1.0
+ */
@NonNull
public List<LayoutElement> getContents() {
List<LayoutElement> list = new ArrayList<>();
@@ -2023,7 +2443,9 @@
/**
* Gets the height of this {@link Box}. If not defined, this will size itself to fit all of
- * its children (i.e. a WrappedDimension). Intended for testing purposes only.
+ * its children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@Nullable
public ContainerDimension getHeight() {
@@ -2036,7 +2458,9 @@
/**
* Gets the width of this {@link Box}. If not defined, this will size itself to fit all of
- * its children (i.e. a WrappedDimension). Intended for testing purposes only.
+ * its children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@Nullable
public ContainerDimension getWidth() {
@@ -2049,7 +2473,9 @@
/**
* Gets the horizontal alignment of the element inside this {@link Box}. If not defined,
- * defaults to HORIZONTAL_ALIGN_CENTER. Intended for testing purposes only.
+ * defaults to HORIZONTAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@Nullable
public HorizontalAlignmentProp getHorizontalAlignment() {
@@ -2062,7 +2488,9 @@
/**
* Gets the vertical alignment of the element inside this {@link Box}. If not defined,
- * defaults to VERTICAL_ALIGN_CENTER. Intended for testing purposes only.
+ * defaults to VERTICAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@Nullable
public VerticalAlignmentProp getVerticalAlignment() {
@@ -2075,7 +2503,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public Modifiers getModifiers() {
@@ -2093,12 +2522,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Box fromProto(@NonNull LayoutElementProto.Box proto) {
- return new Box(proto, null);
+ public static Box fromProto(
+ @NonNull LayoutElementProto.Box proto, @Nullable Fingerprint fingerprint) {
+ return new Box(proto, fingerprint);
}
@NonNull
+ static Box fromProto(@NonNull LayoutElementProto.Box proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.Box toProto() {
return mImpl;
}
@@ -2110,15 +2549,38 @@
return LayoutElementProto.LayoutElement.newBuilder().setBox(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Box{"
+ + "contents="
+ + getContents()
+ + ", height="
+ + getHeight()
+ + ", width="
+ + getWidth()
+ + ", horizontalAlignment="
+ + getHorizontalAlignment()
+ + ", verticalAlignment="
+ + getVerticalAlignment()
+ + ", modifiers="
+ + getModifiers()
+ + "}";
+ }
+
/** Builder for {@link Box}. */
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Box.Builder mImpl =
LayoutElementProto.Box.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(-1881256071);
+ private final Fingerprint mFingerprint = new Fingerprint(-2113485818);
public Builder() {}
- /** Adds one item to the child element(s) to wrap. */
+ /**
+ * Adds one item to the child element(s) to wrap.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder addContent(@NonNull LayoutElement content) {
mImpl.addContents(content.toLayoutElementProto());
@@ -2129,6 +2591,8 @@
/**
* Sets the height of this {@link Box}. If not defined, this will size itself to fit all
* of its children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@NonNull
public Builder setHeight(@NonNull ContainerDimension height) {
@@ -2141,6 +2605,8 @@
/**
* Sets the width of this {@link Box}. If not defined, this will size itself to fit all
* of its children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@NonNull
public Builder setWidth(@NonNull ContainerDimension width) {
@@ -2153,6 +2619,8 @@
/**
* Sets the horizontal alignment of the element inside this {@link Box}. If not defined,
* defaults to HORIZONTAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setHorizontalAlignment(
@@ -2167,6 +2635,8 @@
/**
* Sets the horizontal alignment of the element inside this {@link Box}. If not defined,
* defaults to HORIZONTAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setHorizontalAlignment(@HorizontalAlignment int horizontalAlignment) {
@@ -2175,12 +2645,15 @@
.setValue(
AlignmentProto.HorizontalAlignment.forNumber(
horizontalAlignment)));
+ mFingerprint.recordPropertyUpdate(4, horizontalAlignment);
return this;
}
/**
* Sets the vertical alignment of the element inside this {@link Box}. If not defined,
* defaults to VERTICAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setVerticalAlignment(@NonNull VerticalAlignmentProp verticalAlignment) {
@@ -2189,9 +2662,12 @@
5, checkNotNull(verticalAlignment.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the vertical alignment of the element inside this {@link Box}. If not defined,
* defaults to VERTICAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setVerticalAlignment(@VerticalAlignment int verticalAlignment) {
@@ -2200,11 +2676,14 @@
.setValue(
AlignmentProto.VerticalAlignment.forNumber(
verticalAlignment)));
+ mFingerprint.recordPropertyUpdate(5, verticalAlignment);
return this;
}
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull Modifiers modifiers) {
@@ -2226,6 +2705,8 @@
* A portion of text which can be added to a {@link Span}. Two different {@link SpanText}
* elements on the same line will be aligned to the same baseline, regardless of the size of
* each {@link SpanText}.
+ *
+ * @since 1.0
*/
public static final class SpanText implements Span {
private final LayoutElementProto.SpanText mImpl;
@@ -2236,7 +2717,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the text to render. Intended for testing purposes only. */
+ /**
+ * Gets the text to render.
+ *
+ * @since 1.0
+ */
@Nullable
public StringProp getText() {
if (mImpl.hasText()) {
@@ -2248,7 +2733,9 @@
/**
* Gets the style of font to use (size, bold etc). If not specified, defaults to the
- * platform's default body font. Intended for testing purposes only.
+ * platform's default body font.
+ *
+ * @since 1.0
*/
@Nullable
public FontStyle getFontStyle() {
@@ -2261,7 +2748,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public SpanModifiers getModifiers() {
@@ -2295,12 +2783,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static SpanText fromProto(@NonNull LayoutElementProto.SpanText proto) {
- return new SpanText(proto, null);
+ public static SpanText fromProto(
+ @NonNull LayoutElementProto.SpanText proto, @Nullable Fingerprint fingerprint) {
+ return new SpanText(proto, fingerprint);
}
@NonNull
+ static SpanText fromProto(@NonNull LayoutElementProto.SpanText proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.SpanText toProto() {
return mImpl;
}
@@ -2312,11 +2810,27 @@
return LayoutElementProto.Span.newBuilder().setText(mImpl).build();
}
+ @Override
+ @OptIn(markerClass = ProtoLayoutExperimental.class)
+ @NonNull
+ public String toString() {
+ return "SpanText{"
+ + "text="
+ + getText()
+ + ", fontStyle="
+ + getFontStyle()
+ + ", modifiers="
+ + getModifiers()
+ + ", androidTextStyle="
+ + getAndroidTextStyle()
+ + "}";
+ }
+
/** Builder for {@link SpanText}. */
public static final class Builder implements Span.Builder {
private final LayoutElementProto.SpanText.Builder mImpl =
LayoutElementProto.SpanText.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(-221774557);
+ private final Fingerprint mFingerprint = new Fingerprint(266451531);
public Builder() {}
@@ -2338,7 +2852,11 @@
1, checkNotNull(text.getFingerprint()).aggregateValueAsInt());
return this;
}
- /** Sets the text to render. */
+ /**
+ * Sets the text to render.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setText(@NonNull String text) {
mImpl.setText(TypesProto.StringProp.newBuilder().setValue(text));
@@ -2348,6 +2866,8 @@
/**
* Sets the style of font to use (size, bold etc). If not specified, defaults to the
* platform's default body font.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setFontStyle(@NonNull FontStyle fontStyle) {
@@ -2359,6 +2879,8 @@
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull SpanModifiers modifiers) {
@@ -2391,7 +2913,11 @@
}
}
- /** An image which can be added to a {@link Span}. */
+ /**
+ * An image which can be added to a {@link Span}.
+ *
+ * @since 1.0
+ */
public static final class SpanImage implements Span {
private final LayoutElementProto.SpanImage mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -2403,7 +2929,9 @@
/**
* Gets the resource_id of the image to render. This must exist in the supplied resource
- * bundle. Intended for testing purposes only.
+ * bundle.
+ *
+ * @since 1.0
*/
@Nullable
public StringProp getResourceId() {
@@ -2415,8 +2943,9 @@
}
/**
- * Gets the width of this image. If not defined, the image will not be rendered. Intended
- * for testing purposes only.
+ * Gets the width of this image. If not defined, the image will not be rendered.
+ *
+ * @since 1.0
*/
@Nullable
public DpProp getWidth() {
@@ -2428,8 +2957,9 @@
}
/**
- * Gets the height of this image. If not defined, the image will not be rendered. Intended
- * for testing purposes only.
+ * Gets the height of this image. If not defined, the image will not be rendered.
+ *
+ * @since 1.0
*/
@Nullable
public DpProp getHeight() {
@@ -2442,7 +2972,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public SpanModifiers getModifiers() {
@@ -2455,7 +2986,9 @@
/**
* Gets alignment of this image within the line height of the surrounding {@link Spannable}.
- * If undefined, defaults to SPAN_VERTICAL_ALIGN_BOTTOM. Intended for testing purposes only.
+ * If undefined, defaults to SPAN_VERTICAL_ALIGN_BOTTOM.
+ *
+ * @since 1.0
*/
@Nullable
public SpanVerticalAlignmentProp getAlignment() {
@@ -2473,12 +3006,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static SpanImage fromProto(@NonNull LayoutElementProto.SpanImage proto) {
- return new SpanImage(proto, null);
+ public static SpanImage fromProto(
+ @NonNull LayoutElementProto.SpanImage proto, @Nullable Fingerprint fingerprint) {
+ return new SpanImage(proto, fingerprint);
}
@NonNull
+ static SpanImage fromProto(@NonNull LayoutElementProto.SpanImage proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.SpanImage toProto() {
return mImpl;
}
@@ -2490,11 +3033,28 @@
return LayoutElementProto.Span.newBuilder().setImage(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "SpanImage{"
+ + "resourceId="
+ + getResourceId()
+ + ", width="
+ + getWidth()
+ + ", height="
+ + getHeight()
+ + ", modifiers="
+ + getModifiers()
+ + ", alignment="
+ + getAlignment()
+ + "}";
+ }
+
/** Builder for {@link SpanImage}. */
public static final class Builder implements Span.Builder {
private final LayoutElementProto.SpanImage.Builder mImpl =
LayoutElementProto.SpanImage.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(502289772);
+ private final Fingerprint mFingerprint = new Fingerprint(920832637);
public Builder() {}
@@ -2520,6 +3080,8 @@
/**
* Sets the resource_id of the image to render. This must exist in the supplied resource
* bundle.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setResourceId(@NonNull String resourceId) {
@@ -2565,6 +3127,8 @@
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull SpanModifiers modifiers) {
@@ -2577,6 +3141,8 @@
/**
* Sets alignment of this image within the line height of the surrounding {@link
* Spannable}. If undefined, defaults to SPAN_VERTICAL_ALIGN_BOTTOM.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setAlignment(@NonNull SpanVerticalAlignmentProp alignment) {
@@ -2585,9 +3151,12 @@
5, checkNotNull(alignment.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets alignment of this image within the line height of the surrounding {@link
* Spannable}. If undefined, defaults to SPAN_VERTICAL_ALIGN_BOTTOM.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setAlignment(@SpanVerticalAlignment int alignment) {
@@ -2596,6 +3165,7 @@
.setValue(
LayoutElementProto.SpanVerticalAlignment.forNumber(
alignment)));
+ mFingerprint.recordPropertyUpdate(5, alignment);
return this;
}
@@ -2611,6 +3181,8 @@
* Interface defining a single {@link Span}. Each {@link Span} forms part of a larger {@link
* Spannable} widget. At the moment, the only widgets which can be added to {@link Spannable}
* containers are {@link SpanText} and {@link SpanImage} elements.
+ *
+ * @since 1.0
*/
public interface Span {
/** Get the protocol buffer representation of this object. */
@@ -2624,7 +3196,7 @@
Fingerprint getFingerprint();
/** Builder to create {@link Span} objects. */
- @SuppressLint("StaticFinalBuilder")
+ @RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
/** Builds an instance with values accumulated in this Builder. */
@@ -2633,22 +3205,32 @@
}
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Span spanFromProto(@NonNull LayoutElementProto.Span proto) {
+ public static Span spanFromProto(
+ @NonNull LayoutElementProto.Span proto, @Nullable Fingerprint fingerprint) {
if (proto.hasText()) {
- return SpanText.fromProto(proto.getText());
+ return SpanText.fromProto(proto.getText(), fingerprint);
}
if (proto.hasImage()) {
- return SpanImage.fromProto(proto.getImage());
+ return SpanImage.fromProto(proto.getImage(), fingerprint);
}
throw new IllegalStateException("Proto was not a recognised instance of Span");
}
+ @NonNull
+ static Span spanFromProto(@NonNull LayoutElementProto.Span proto) {
+ return spanFromProto(proto, null);
+ }
+
/**
* A container of {@link Span} elements. Currently, this supports {@link SpanImage} and {@link
* SpanText} elements, where each individual {@link Span} can have different styling applied to
* it but the resulting text will flow naturally. This allows sections of a paragraph of text to
* have different styling applied to it, for example, making one or two words bold or italic.
+ *
+ * @since 1.0
*/
public static final class Spannable implements LayoutElement {
private final LayoutElementProto.Spannable mImpl;
@@ -2660,8 +3242,9 @@
}
/**
- * Gets the {@link Span} elements that form this {@link Spannable}. Intended for testing
- * purposes only.
+ * Gets the {@link Span} elements that form this {@link Spannable}.
+ *
+ * @since 1.0
*/
@NonNull
public List<Span> getSpans() {
@@ -2674,7 +3257,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public Modifiers getModifiers() {
@@ -2688,7 +3272,9 @@
/**
* Gets the maximum number of lines that can be represented by the {@link Spannable}
* element. If not defined, the {@link Spannable} element will be treated as a single-line
- * element. Intended for testing purposes only.
+ * element.
+ *
+ * @since 1.0
*/
@Nullable
public Int32Prop getMaxLines() {
@@ -2704,8 +3290,9 @@
* Spannable} element will size itself to wrap its contents, so this option is meaningless
* for single-line content (for that, use alignment of the outer container). For multi-line
* content, however, this will set the alignment of lines relative to the {@link Spannable}
- * element bounds. If not defined, defaults to TEXT_ALIGN_CENTER. Intended for testing
- * purposes only.
+ * element bounds. If not defined, defaults to TEXT_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@Nullable
public HorizontalAlignmentProp getMultilineAlignment() {
@@ -2721,7 +3308,9 @@
* {@link Spannable} element will grow as large as possible inside its parent container
* (while still respecting max_lines); if it cannot grow large enough to render all of its
* content, the content which cannot fit inside its container will be truncated. If not
- * defined, defaults to TEXT_OVERFLOW_TRUNCATE. Intended for testing purposes only.
+ * defined, defaults to TEXT_OVERFLOW_TRUNCATE.
+ *
+ * @since 1.0
*/
@Nullable
public TextOverflowProp getOverflow() {
@@ -2735,7 +3324,9 @@
/**
* Gets the explicit height between lines of text. This is equivalent to the vertical
* distance between subsequent baselines. If not specified, defaults the font's recommended
- * interline spacing. Intended for testing purposes only.
+ * interline spacing.
+ *
+ * @since 1.0
*/
@Nullable
public SpProp getLineHeight() {
@@ -2765,12 +3356,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Spannable fromProto(@NonNull LayoutElementProto.Spannable proto) {
- return new Spannable(proto, null);
+ public static Spannable fromProto(
+ @NonNull LayoutElementProto.Spannable proto, @Nullable Fingerprint fingerprint) {
+ return new Spannable(proto, fingerprint);
}
@NonNull
+ static Spannable fromProto(@NonNull LayoutElementProto.Spannable proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.Spannable toProto() {
return mImpl;
}
@@ -2782,15 +3383,38 @@
return LayoutElementProto.LayoutElement.newBuilder().setSpannable(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Spannable{"
+ + "spans="
+ + getSpans()
+ + ", modifiers="
+ + getModifiers()
+ + ", maxLines="
+ + getMaxLines()
+ + ", multilineAlignment="
+ + getMultilineAlignment()
+ + ", overflow="
+ + getOverflow()
+ + ", lineHeight="
+ + getLineHeight()
+ + "}";
+ }
+
/** Builder for {@link Spannable}. */
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Spannable.Builder mImpl =
LayoutElementProto.Spannable.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(-1690284372);
+ private final Fingerprint mFingerprint = new Fingerprint(-1111684471);
public Builder() {}
- /** Adds one item to the {@link Span} elements that form this {@link Spannable}. */
+ /**
+ * Adds one item to the {@link Span} elements that form this {@link Spannable}.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder addSpan(@NonNull Span span) {
mImpl.addSpans(span.toSpanProto());
@@ -2801,6 +3425,8 @@
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull Modifiers modifiers) {
@@ -2814,6 +3440,8 @@
* Sets the maximum number of lines that can be represented by the {@link Spannable}
* element. If not defined, the {@link Spannable} element will be treated as a
* single-line element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setMaxLines(@NonNull Int32Prop maxLines) {
@@ -2839,6 +3467,8 @@
* meaningless for single-line content (for that, use alignment of the outer container).
* For multi-line content, however, this will set the alignment of lines relative to the
* {@link Spannable} element bounds. If not defined, defaults to TEXT_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setMultilineAlignment(
@@ -2848,12 +3478,15 @@
4, checkNotNull(multilineAlignment.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets alignment of the {@link Spannable} content within its bounds. Note that a {@link
* Spannable} element will size itself to wrap its contents, so this option is
* meaningless for single-line content (for that, use alignment of the outer container).
* For multi-line content, however, this will set the alignment of lines relative to the
* {@link Spannable} element bounds. If not defined, defaults to TEXT_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setMultilineAlignment(@HorizontalAlignment int multilineAlignment) {
@@ -2862,6 +3495,7 @@
.setValue(
AlignmentProto.HorizontalAlignment.forNumber(
multilineAlignment)));
+ mFingerprint.recordPropertyUpdate(4, multilineAlignment);
return this;
}
@@ -2871,6 +3505,8 @@
* container (while still respecting max_lines); if it cannot grow large enough to
* render all of its content, the content which cannot fit inside its container will be
* truncated. If not defined, defaults to TEXT_OVERFLOW_TRUNCATE.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setOverflow(@NonNull TextOverflowProp overflow) {
@@ -2879,18 +3515,22 @@
5, checkNotNull(overflow.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets how to handle content which overflows the bound of the {@link Spannable}
* element. A {@link Spannable} element will grow as large as possible inside its parent
* container (while still respecting max_lines); if it cannot grow large enough to
* render all of its content, the content which cannot fit inside its container will be
* truncated. If not defined, defaults to TEXT_OVERFLOW_TRUNCATE.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setOverflow(@TextOverflow int overflow) {
mImpl.setOverflow(
LayoutElementProto.TextOverflowProp.newBuilder()
.setValue(LayoutElementProto.TextOverflow.forNumber(overflow)));
+ mFingerprint.recordPropertyUpdate(5, overflow);
return this;
}
@@ -2898,6 +3538,8 @@
* Sets the explicit height between lines of text. This is equivalent to the vertical
* distance between subsequent baselines. If not specified, defaults the font's
* recommended interline spacing.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setLineHeight(@NonNull SpProp lineHeight) {
@@ -2941,6 +3583,8 @@
* <p>If specified, horizontal_alignment can be used to control the gravity inside the
* container, affecting the horizontal placement of children whose width are smaller than the
* resulting column width.
+ *
+ * @since 1.0
*/
public static final class Column implements LayoutElement {
private final LayoutElementProto.Column mImpl;
@@ -2952,8 +3596,9 @@
}
/**
- * Gets the list of child elements to place inside this {@link Column}. Intended for testing
- * purposes only.
+ * Gets the list of child elements to place inside this {@link Column}.
+ *
+ * @since 1.0
*/
@NonNull
public List<LayoutElement> getContents() {
@@ -2967,7 +3612,8 @@
/**
* Gets the horizontal alignment of elements inside this column, if they are narrower than
* the resulting width of the column. If not defined, defaults to HORIZONTAL_ALIGN_CENTER.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public HorizontalAlignmentProp getHorizontalAlignment() {
@@ -2980,7 +3626,9 @@
/**
* Gets the width of this column. If not defined, this will size itself to fit all of its
- * children (i.e. a WrappedDimension). Intended for testing purposes only.
+ * children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@Nullable
public ContainerDimension getWidth() {
@@ -2993,7 +3641,9 @@
/**
* Gets the height of this column. If not defined, this will size itself to fit all of its
- * children (i.e. a WrappedDimension). Intended for testing purposes only.
+ * children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@Nullable
public ContainerDimension getHeight() {
@@ -3006,7 +3656,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public Modifiers getModifiers() {
@@ -3024,12 +3675,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Column fromProto(@NonNull LayoutElementProto.Column proto) {
- return new Column(proto, null);
+ public static Column fromProto(
+ @NonNull LayoutElementProto.Column proto, @Nullable Fingerprint fingerprint) {
+ return new Column(proto, fingerprint);
}
@NonNull
+ static Column fromProto(@NonNull LayoutElementProto.Column proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.Column toProto() {
return mImpl;
}
@@ -3041,15 +3702,36 @@
return LayoutElementProto.LayoutElement.newBuilder().setColumn(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Column{"
+ + "contents="
+ + getContents()
+ + ", horizontalAlignment="
+ + getHorizontalAlignment()
+ + ", width="
+ + getWidth()
+ + ", height="
+ + getHeight()
+ + ", modifiers="
+ + getModifiers()
+ + "}";
+ }
+
/** Builder for {@link Column}. */
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Column.Builder mImpl =
LayoutElementProto.Column.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(-1411218529);
+ private final Fingerprint mFingerprint = new Fingerprint(1676323158);
public Builder() {}
- /** Adds one item to the list of child elements to place inside this {@link Column}. */
+ /**
+ * Adds one item to the list of child elements to place inside this {@link Column}.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder addContent(@NonNull LayoutElement content) {
mImpl.addContents(content.toLayoutElementProto());
@@ -3061,6 +3743,8 @@
* Sets the horizontal alignment of elements inside this column, if they are narrower
* than the resulting width of the column. If not defined, defaults to
* HORIZONTAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setHorizontalAlignment(
@@ -3076,6 +3760,8 @@
* Sets the horizontal alignment of elements inside this column, if they are narrower
* than the resulting width of the column. If not defined, defaults to
* HORIZONTAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setHorizontalAlignment(@HorizontalAlignment int horizontalAlignment) {
@@ -3084,12 +3770,15 @@
.setValue(
AlignmentProto.HorizontalAlignment.forNumber(
horizontalAlignment)));
+ mFingerprint.recordPropertyUpdate(2, horizontalAlignment);
return this;
}
/**
* Sets the width of this column. If not defined, this will size itself to fit all of
* its children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@NonNull
public Builder setWidth(@NonNull ContainerDimension width) {
@@ -3102,6 +3791,8 @@
/**
* Sets the height of this column. If not defined, this will size itself to fit all of
* its children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@NonNull
public Builder setHeight(@NonNull ContainerDimension height) {
@@ -3113,6 +3804,8 @@
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull Modifiers modifiers) {
@@ -3150,8 +3843,9 @@
}
/**
- * Gets the list of child elements to place inside this {@link Row}. Intended for testing
- * purposes only.
+ * Gets the list of child elements to place inside this {@link Row}.
+ *
+ * @since 1.0
*/
@NonNull
public List<LayoutElement> getContents() {
@@ -3164,8 +3858,9 @@
/**
* Gets the vertical alignment of elements inside this row, if they are narrower than the
- * resulting height of the row. If not defined, defaults to VERTICAL_ALIGN_CENTER. Intended
- * for testing purposes only.
+ * resulting height of the row. If not defined, defaults to VERTICAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@Nullable
public VerticalAlignmentProp getVerticalAlignment() {
@@ -3178,7 +3873,9 @@
/**
* Gets the width of this row. If not defined, this will size itself to fit all of its
- * children (i.e. a WrappedDimension). Intended for testing purposes only.
+ * children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@Nullable
public ContainerDimension getWidth() {
@@ -3191,7 +3888,9 @@
/**
* Gets the height of this row. If not defined, this will size itself to fit all of its
- * children (i.e. a WrappedDimension). Intended for testing purposes only.
+ * children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@Nullable
public ContainerDimension getHeight() {
@@ -3204,7 +3903,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public Modifiers getModifiers() {
@@ -3222,12 +3922,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Row fromProto(@NonNull LayoutElementProto.Row proto) {
- return new Row(proto, null);
+ public static Row fromProto(
+ @NonNull LayoutElementProto.Row proto, @Nullable Fingerprint fingerprint) {
+ return new Row(proto, fingerprint);
}
@NonNull
+ static Row fromProto(@NonNull LayoutElementProto.Row proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.Row toProto() {
return mImpl;
}
@@ -3239,15 +3949,36 @@
return LayoutElementProto.LayoutElement.newBuilder().setRow(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Row{"
+ + "contents="
+ + getContents()
+ + ", verticalAlignment="
+ + getVerticalAlignment()
+ + ", width="
+ + getWidth()
+ + ", height="
+ + getHeight()
+ + ", modifiers="
+ + getModifiers()
+ + "}";
+ }
+
/** Builder for {@link Row}. */
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Row.Builder mImpl =
LayoutElementProto.Row.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(1537205448);
+ private final Fingerprint mFingerprint = new Fingerprint(1279502255);
public Builder() {}
- /** Adds one item to the list of child elements to place inside this {@link Row}. */
+ /**
+ * Adds one item to the list of child elements to place inside this {@link Row}.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder addContent(@NonNull LayoutElement content) {
mImpl.addContents(content.toLayoutElementProto());
@@ -3258,6 +3989,8 @@
/**
* Sets the vertical alignment of elements inside this row, if they are narrower than
* the resulting height of the row. If not defined, defaults to VERTICAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setVerticalAlignment(@NonNull VerticalAlignmentProp verticalAlignment) {
@@ -3270,6 +4003,8 @@
/**
* Sets the vertical alignment of elements inside this row, if they are narrower than
* the resulting height of the row. If not defined, defaults to VERTICAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setVerticalAlignment(@VerticalAlignment int verticalAlignment) {
@@ -3278,12 +4013,15 @@
.setValue(
AlignmentProto.VerticalAlignment.forNumber(
verticalAlignment)));
+ mFingerprint.recordPropertyUpdate(2, verticalAlignment);
return this;
}
/**
* Sets the width of this row. If not defined, this will size itself to fit all of its
* children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@NonNull
public Builder setWidth(@NonNull ContainerDimension width) {
@@ -3296,6 +4034,8 @@
/**
* Sets the height of this row. If not defined, this will size itself to fit all of its
* children (i.e. a WrappedDimension).
+ *
+ * @since 1.0
*/
@NonNull
public Builder setHeight(@NonNull ContainerDimension height) {
@@ -3307,6 +4047,8 @@
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull Modifiers modifiers) {
@@ -3328,6 +4070,8 @@
* An arc container. This container will fill itself to a circle, which fits inside its parent
* container, and all of its children will be placed on that circle. The fields anchor_angle and
* anchor_type can be used to specify where to draw children within this circle.
+ *
+ * @since 1.0
*/
public static final class Arc implements LayoutElement {
private final LayoutElementProto.Arc mImpl;
@@ -3338,7 +4082,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets contents of this container. Intended for testing purposes only. */
+ /**
+ * Gets contents of this container.
+ *
+ * @since 1.0
+ */
@NonNull
public List<ArcLayoutElement> getContents() {
List<ArcLayoutElement> list = new ArrayList<>();
@@ -3385,7 +4133,9 @@
/**
* Gets how to align the contents of this container relative to anchor_angle. If not
- * defined, defaults to ARC_ANCHOR_CENTER. Intended for testing purposes only.
+ * defined, defaults to ARC_ANCHOR_CENTER.
+ *
+ * @since 1.0
*/
@Nullable
public ArcAnchorTypeProp getAnchorType() {
@@ -3400,7 +4150,9 @@
* Gets vertical alignment of elements within the arc. If the {@link Arc}'s thickness is
* larger than the thickness of the element being drawn, this controls whether the element
* should be drawn towards the inner or outer edge of the arc, or drawn in the center. If
- * not defined, defaults to VERTICAL_ALIGN_CENTER. Intended for testing purposes only.
+ * not defined, defaults to VERTICAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@Nullable
public VerticalAlignmentProp getVerticalAlign() {
@@ -3413,7 +4165,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public Modifiers getModifiers() {
@@ -3431,12 +4184,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Arc fromProto(@NonNull LayoutElementProto.Arc proto) {
- return new Arc(proto, null);
+ public static Arc fromProto(
+ @NonNull LayoutElementProto.Arc proto, @Nullable Fingerprint fingerprint) {
+ return new Arc(proto, fingerprint);
}
@NonNull
+ static Arc fromProto(@NonNull LayoutElementProto.Arc proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.Arc toProto() {
return mImpl;
}
@@ -3448,15 +4211,36 @@
return LayoutElementProto.LayoutElement.newBuilder().setArc(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Arc{"
+ + "contents="
+ + getContents()
+ + ", anchorAngle="
+ + getAnchorAngle()
+ + ", anchorType="
+ + getAnchorType()
+ + ", verticalAlign="
+ + getVerticalAlign()
+ + ", modifiers="
+ + getModifiers()
+ + "}";
+ }
+
/** Builder for {@link Arc}. */
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Arc.Builder mImpl =
LayoutElementProto.Arc.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(299028337);
+ private final Fingerprint mFingerprint = new Fingerprint(-257261663);
public Builder() {}
- /** Adds one item to contents of this container. */
+ /**
+ * Adds one item to contents of this container.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder addContent(@NonNull ArcLayoutElement content) {
mImpl.addContents(content.toArcLayoutElementProto());
@@ -3511,6 +4295,8 @@
/**
* Sets how to align the contents of this container relative to anchor_angle. If not
* defined, defaults to ARC_ANCHOR_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setAnchorType(@NonNull ArcAnchorTypeProp anchorType) {
@@ -3523,12 +4309,15 @@
/**
* Sets how to align the contents of this container relative to anchor_angle. If not
* defined, defaults to ARC_ANCHOR_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setAnchorType(@ArcAnchorType int anchorType) {
mImpl.setAnchorType(
AlignmentProto.ArcAnchorTypeProp.newBuilder()
.setValue(AlignmentProto.ArcAnchorType.forNumber(anchorType)));
+ mFingerprint.recordPropertyUpdate(3, anchorType);
return this;
}
@@ -3537,6 +4326,8 @@
* larger than the thickness of the element being drawn, this controls whether the
* element should be drawn towards the inner or outer edge of the arc, or drawn in the
* center. If not defined, defaults to VERTICAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setVerticalAlign(@NonNull VerticalAlignmentProp verticalAlign) {
@@ -3545,11 +4336,14 @@
4, checkNotNull(verticalAlign.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets vertical alignment of elements within the arc. If the {@link Arc}'s thickness is
* larger than the thickness of the element being drawn, this controls whether the
* element should be drawn towards the inner or outer edge of the arc, or drawn in the
* center. If not defined, defaults to VERTICAL_ALIGN_CENTER.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setVerticalAlign(@VerticalAlignment int verticalAlign) {
@@ -3557,11 +4351,14 @@
AlignmentProto.VerticalAlignmentProp.newBuilder()
.setValue(
AlignmentProto.VerticalAlignment.forNumber(verticalAlign)));
+ mFingerprint.recordPropertyUpdate(4, verticalAlign);
return this;
}
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull Modifiers modifiers) {
@@ -3585,7 +4382,11 @@
}
}
- /** A text element that can be used in an {@link Arc}. */
+ /**
+ * A text element that can be used in an {@link Arc}.
+ *
+ * @since 1.0
+ */
public static final class ArcText implements ArcLayoutElement {
private final LayoutElementProto.ArcText mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -3595,7 +4396,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the text to render. Intended for testing purposes only. */
+ /**
+ * Gets the text to render.
+ *
+ * @since 1.0
+ */
@Nullable
public StringProp getText() {
if (mImpl.hasText()) {
@@ -3607,7 +4412,9 @@
/**
* Gets the style of font to use (size, bold etc). If not specified, defaults to the
- * platform's default body font. Intended for testing purposes only.
+ * platform's default body font.
+ *
+ * @since 1.0
*/
@Nullable
public FontStyle getFontStyle() {
@@ -3620,7 +4427,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public ArcModifiers getModifiers() {
@@ -3638,12 +4446,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static ArcText fromProto(@NonNull LayoutElementProto.ArcText proto) {
- return new ArcText(proto, null);
+ public static ArcText fromProto(
+ @NonNull LayoutElementProto.ArcText proto, @Nullable Fingerprint fingerprint) {
+ return new ArcText(proto, fingerprint);
}
@NonNull
+ static ArcText fromProto(@NonNull LayoutElementProto.ArcText proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.ArcText toProto() {
return mImpl;
}
@@ -3655,11 +4473,24 @@
return LayoutElementProto.ArcLayoutElement.newBuilder().setText(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ArcText{"
+ + "text="
+ + getText()
+ + ", fontStyle="
+ + getFontStyle()
+ + ", modifiers="
+ + getModifiers()
+ + "}";
+ }
+
/** Builder for {@link ArcText}. */
public static final class Builder implements ArcLayoutElement.Builder {
private final LayoutElementProto.ArcText.Builder mImpl =
LayoutElementProto.ArcText.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(434391973);
+ private final Fingerprint mFingerprint = new Fingerprint(-132896327);
public Builder() {}
@@ -3691,6 +4522,8 @@
/**
* Sets the style of font to use (size, bold etc). If not specified, defaults to the
* platform's default body font.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setFontStyle(@NonNull FontStyle fontStyle) {
@@ -3702,6 +4535,8 @@
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull ArcModifiers modifiers) {
@@ -3719,7 +4554,11 @@
}
}
- /** A line that can be used in an {@link Arc} and renders as a round progress bar. */
+ /**
+ * A line that can be used in an {@link Arc} and renders as a round progress bar.
+ *
+ * @since 1.0
+ */
public static final class ArcLine implements ArcLayoutElement {
private final LayoutElementProto.ArcLine mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -3761,6 +4600,8 @@
/**
* Gets the thickness of this line. If not defined, defaults to 0. Intended for testing
* purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public DpProp getThickness() {
@@ -3787,7 +4628,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public ArcModifiers getModifiers() {
@@ -3819,12 +4661,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static ArcLine fromProto(@NonNull LayoutElementProto.ArcLine proto) {
- return new ArcLine(proto, null);
+ public static ArcLine fromProto(
+ @NonNull LayoutElementProto.ArcLine proto, @Nullable Fingerprint fingerprint) {
+ return new ArcLine(proto, fingerprint);
}
@NonNull
+ static ArcLine fromProto(@NonNull LayoutElementProto.ArcLine proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.ArcLine toProto() {
return mImpl;
}
@@ -3836,6 +4688,23 @@
return LayoutElementProto.ArcLayoutElement.newBuilder().setLine(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ArcLine{"
+ + "length="
+ + getLength()
+ + ", thickness="
+ + getThickness()
+ + ", color="
+ + getColor()
+ + ", modifiers="
+ + getModifiers()
+ + ", strokeCap="
+ + getStrokeCap()
+ + "}";
+ }
+
/** Builder for {@link ArcLine}. */
public static final class Builder implements ArcLayoutElement.Builder {
private final LayoutElementProto.ArcLine.Builder mImpl =
@@ -3919,6 +4788,8 @@
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull ArcModifiers modifiers) {
@@ -4021,6 +4892,12 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "StrokeCapProp{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link StrokeCapProp} */
public static final class Builder {
private final LayoutElementProto.StrokeCapProp.Builder mImpl =
@@ -4049,7 +4926,11 @@
}
}
- /** A simple spacer used to provide padding between adjacent elements in an {@link Arc}. */
+ /**
+ * A simple spacer used to provide padding between adjacent elements in an {@link Arc}.
+ *
+ * @since 1.0
+ */
public static final class ArcSpacer implements ArcLayoutElement {
private final LayoutElementProto.ArcSpacer mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -4060,8 +4941,9 @@
}
/**
- * Gets the length of this spacer, in degrees. If not defined, defaults to 0. Intended for
- * testing purposes only.
+ * Gets the length of this spacer, in degrees. If not defined, defaults to 0.
+ *
+ * @since 1.0
*/
@Nullable
public DegreesProp getLength() {
@@ -4073,8 +4955,9 @@
}
/**
- * Gets the thickness of this spacer, in DP. If not defined, defaults to 0. Intended for
- * testing purposes only.
+ * Gets the thickness of this spacer, in DP. If not defined, defaults to 0.
+ *
+ * @since 1.0
*/
@Nullable
public DpProp getThickness() {
@@ -4087,7 +4970,8 @@
/**
* Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
- * Intended for testing purposes only.
+ *
+ * @since 1.0
*/
@Nullable
public ArcModifiers getModifiers() {
@@ -4105,12 +4989,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static ArcSpacer fromProto(@NonNull LayoutElementProto.ArcSpacer proto) {
- return new ArcSpacer(proto, null);
+ public static ArcSpacer fromProto(
+ @NonNull LayoutElementProto.ArcSpacer proto, @Nullable Fingerprint fingerprint) {
+ return new ArcSpacer(proto, fingerprint);
}
@NonNull
+ static ArcSpacer fromProto(@NonNull LayoutElementProto.ArcSpacer proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.ArcSpacer toProto() {
return mImpl;
}
@@ -4122,11 +5016,24 @@
return LayoutElementProto.ArcLayoutElement.newBuilder().setSpacer(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ArcSpacer{"
+ + "length="
+ + getLength()
+ + ", thickness="
+ + getThickness()
+ + ", modifiers="
+ + getModifiers()
+ + "}";
+ }
+
/** Builder for {@link ArcSpacer}. */
public static final class Builder implements ArcLayoutElement.Builder {
private final LayoutElementProto.ArcSpacer.Builder mImpl =
LayoutElementProto.ArcSpacer.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(-179760535);
+ private final Fingerprint mFingerprint = new Fingerprint(-1076667423);
public Builder() {}
@@ -4169,6 +5076,8 @@
/**
* Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setModifiers(@NonNull ArcModifiers modifiers) {
@@ -4186,7 +5095,11 @@
}
}
- /** A container that allows a standard {@link LayoutElement} to be added to an {@link Arc}. */
+ /**
+ * A container that allows a standard {@link LayoutElement} to be added to an {@link Arc}.
+ *
+ * @since 1.0
+ */
public static final class ArcAdapter implements ArcLayoutElement {
private final LayoutElementProto.ArcAdapter mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -4196,7 +5109,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the element to adapt to an {@link Arc}. Intended for testing purposes only. */
+ /**
+ * Gets the element to adapt to an {@link Arc}.
+ *
+ * @since 1.0
+ */
@Nullable
public LayoutElement getContent() {
if (mImpl.hasContent()) {
@@ -4212,8 +5129,9 @@
* ends up at the 3 o clock position. If rotate_contents = true, the image will be placed at
* the 3 o clock position, and will be rotated clockwise through 90 degrees. If
* rotate_contents = false, the image will be placed at the 3 o clock position, but itself
- * will not be rotated. If not defined, defaults to false. Intended for testing purposes
- * only.
+ * will not be rotated. If not defined, defaults to false.
+ *
+ * @since 1.0
*/
@Nullable
public BoolProp getRotateContents() {
@@ -4231,12 +5149,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static ArcAdapter fromProto(@NonNull LayoutElementProto.ArcAdapter proto) {
- return new ArcAdapter(proto, null);
+ public static ArcAdapter fromProto(
+ @NonNull LayoutElementProto.ArcAdapter proto, @Nullable Fingerprint fingerprint) {
+ return new ArcAdapter(proto, fingerprint);
}
@NonNull
+ static ArcAdapter fromProto(@NonNull LayoutElementProto.ArcAdapter proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
LayoutElementProto.ArcAdapter toProto() {
return mImpl;
}
@@ -4248,15 +5176,30 @@
return LayoutElementProto.ArcLayoutElement.newBuilder().setAdapter(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ArcAdapter{"
+ + "content="
+ + getContent()
+ + ", rotateContents="
+ + getRotateContents()
+ + "}";
+ }
+
/** Builder for {@link ArcAdapter}. */
public static final class Builder implements ArcLayoutElement.Builder {
private final LayoutElementProto.ArcAdapter.Builder mImpl =
LayoutElementProto.ArcAdapter.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(1696473935);
+ private final Fingerprint mFingerprint = new Fingerprint(-176086106);
public Builder() {}
- /** Sets the element to adapt to an {@link Arc}. */
+ /**
+ * Sets the element to adapt to an {@link Arc}.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setContent(@NonNull LayoutElement content) {
mImpl.setContent(content.toLayoutElementProto());
@@ -4271,6 +5214,8 @@
* be placed at the 3 o clock position, and will be rotated clockwise through 90
* degrees. If rotate_contents = false, the image will be placed at the 3 o clock
* position, but itself will not be rotated. If not defined, defaults to false.
+ *
+ * @since 1.0
*/
@NonNull
public Builder setRotateContents(@NonNull BoolProp rotateContents) {
@@ -4515,7 +5460,7 @@
Fingerprint getFingerprint();
/** Builder to create {@link LayoutElement} objects. */
- @SuppressLint("StaticFinalBuilder")
+ @RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
/** Builds an instance with values accumulated in this Builder. */
@@ -4529,40 +5474,47 @@
@NonNull
@OptIn(markerClass = ExperimentalProtoLayoutExtensionApi.class)
public static LayoutElement layoutElementFromProto(
- @NonNull LayoutElementProto.LayoutElement proto) {
+ @NonNull LayoutElementProto.LayoutElement proto, @Nullable Fingerprint fingerprint) {
if (proto.hasColumn()) {
- return Column.fromProto(proto.getColumn());
+ return Column.fromProto(proto.getColumn(), fingerprint);
}
if (proto.hasRow()) {
- return Row.fromProto(proto.getRow());
+ return Row.fromProto(proto.getRow(), fingerprint);
}
if (proto.hasBox()) {
- return Box.fromProto(proto.getBox());
+ return Box.fromProto(proto.getBox(), fingerprint);
}
if (proto.hasSpacer()) {
- return Spacer.fromProto(proto.getSpacer());
+ return Spacer.fromProto(proto.getSpacer(), fingerprint);
}
if (proto.hasText()) {
- return Text.fromProto(proto.getText());
+ return Text.fromProto(proto.getText(), fingerprint);
}
if (proto.hasImage()) {
- return Image.fromProto(proto.getImage());
+ return Image.fromProto(proto.getImage(), fingerprint);
}
if (proto.hasArc()) {
- return Arc.fromProto(proto.getArc());
+ return Arc.fromProto(proto.getArc(), fingerprint);
}
if (proto.hasSpannable()) {
- return Spannable.fromProto(proto.getSpannable());
+ return Spannable.fromProto(proto.getSpannable(), fingerprint);
}
if (proto.hasExtension()) {
- return ExtensionLayoutElement.fromProto(proto.getExtension());
+ return ExtensionLayoutElement.fromProto(proto.getExtension(), fingerprint);
}
throw new IllegalStateException("Proto was not a recognised instance of LayoutElement");
}
+ @NonNull
+ static LayoutElement layoutElementFromProto(@NonNull LayoutElementProto.LayoutElement proto) {
+ return layoutElementFromProto(proto, null);
+ }
+
/**
* Interface defining the root of all elements that can be used in an {@link Arc}. This exists
* to act as a holder for all of the actual arc layout elements above.
+ *
+ * @since 1.0
*/
public interface ArcLayoutElement {
/** Get the protocol buffer representation of this object. */
@@ -4576,7 +5528,7 @@
Fingerprint getFingerprint();
/** Builder to create {@link ArcLayoutElement} objects. */
- @SuppressLint("StaticFinalBuilder")
+ @RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
/** Builds an instance with values accumulated in this Builder. */
@@ -4585,25 +5537,37 @@
}
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static ArcLayoutElement arcLayoutElementFromProto(
- @NonNull LayoutElementProto.ArcLayoutElement proto) {
+ public static ArcLayoutElement arcLayoutElementFromProto(
+ @NonNull LayoutElementProto.ArcLayoutElement proto, @Nullable Fingerprint fingerprint) {
if (proto.hasText()) {
- return ArcText.fromProto(proto.getText());
+ return ArcText.fromProto(proto.getText(), fingerprint);
}
if (proto.hasLine()) {
- return ArcLine.fromProto(proto.getLine());
+ return ArcLine.fromProto(proto.getLine(), fingerprint);
}
if (proto.hasSpacer()) {
- return ArcSpacer.fromProto(proto.getSpacer());
+ return ArcSpacer.fromProto(proto.getSpacer(), fingerprint);
}
if (proto.hasAdapter()) {
- return ArcAdapter.fromProto(proto.getAdapter());
+ return ArcAdapter.fromProto(proto.getAdapter(), fingerprint);
}
throw new IllegalStateException("Proto was not a recognised instance of ArcLayoutElement");
}
- /** A complete layout. */
+ @NonNull
+ static ArcLayoutElement arcLayoutElementFromProto(
+ @NonNull LayoutElementProto.ArcLayoutElement proto) {
+ return arcLayoutElementFromProto(proto, null);
+ }
+
+ /**
+ * A complete layout.
+ *
+ * @since 1.0
+ */
public static final class Layout {
private final LayoutElementProto.Layout mImpl;
@@ -4611,7 +5575,11 @@
this.mImpl = impl;
}
- /** Gets the root element in the layout. Intended for testing purposes only. */
+ /**
+ * Gets the root element in the layout.
+ *
+ * @since 1.0
+ */
@Nullable
public LayoutElement getRoot() {
if (mImpl.hasRoot()) {
@@ -4660,6 +5628,12 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Layout{" + "root=" + getRoot() + "}";
+ }
+
/** Builder for {@link Layout} */
public static final class Builder {
private final LayoutElementProto.Layout.Builder mImpl =
@@ -4706,7 +5680,11 @@
}
}
- /** The horizontal alignment of an element within its container. */
+ /**
+ * The horizontal alignment of an element within its container.
+ *
+ * @since 1.0
+ */
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
HORIZONTAL_ALIGN_UNDEFINED,
@@ -4719,25 +5697,53 @@
@Retention(RetentionPolicy.SOURCE)
public @interface HorizontalAlignment {}
- /** Horizontal alignment is undefined. */
+ /**
+ * Horizontal alignment is undefined.
+ *
+ * @since 1.0
+ */
public static final int HORIZONTAL_ALIGN_UNDEFINED = 0;
- /** Horizontally align to the left. */
+ /**
+ * Horizontally align to the left.
+ *
+ * @since 1.0
+ */
public static final int HORIZONTAL_ALIGN_LEFT = 1;
- /** Horizontally align to center. */
+ /**
+ * Horizontally align to center.
+ *
+ * @since 1.0
+ */
public static final int HORIZONTAL_ALIGN_CENTER = 2;
- /** Horizontally align to the right. */
+ /**
+ * Horizontally align to the right.
+ *
+ * @since 1.0
+ */
public static final int HORIZONTAL_ALIGN_RIGHT = 3;
- /** Horizontally align to the content start (left in LTR layouts, right in RTL layouts). */
+ /**
+ * Horizontally align to the content start (left in LTR layouts, right in RTL layouts).
+ *
+ * @since 1.0
+ */
public static final int HORIZONTAL_ALIGN_START = 4;
- /** Horizontally align to the content end (right in LTR layouts, left in RTL layouts). */
+ /**
+ * Horizontally align to the content end (right in LTR layouts, left in RTL layouts).
+ *
+ * @since 1.0
+ */
public static final int HORIZONTAL_ALIGN_END = 5;
- /** The vertical alignment of an element within its container. */
+ /**
+ * The vertical alignment of an element within its container.
+ *
+ * @since 1.0
+ */
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
VERTICAL_ALIGN_UNDEFINED,
@@ -4748,42 +5754,72 @@
@Retention(RetentionPolicy.SOURCE)
public @interface VerticalAlignment {}
- /** Vertical alignment is undefined. */
+ /**
+ * Vertical alignment is undefined.
+ *
+ * @since 1.0
+ */
public static final int VERTICAL_ALIGN_UNDEFINED = 0;
- /** Vertically align to the top. */
+ /**
+ * Vertically align to the top.
+ *
+ * @since 1.0
+ */
public static final int VERTICAL_ALIGN_TOP = 1;
- /** Vertically align to center. */
+ /**
+ * Vertically align to center.
+ *
+ * @since 1.0
+ */
public static final int VERTICAL_ALIGN_CENTER = 2;
- /** Vertically align to the bottom. */
+ /**
+ * Vertically align to the bottom.
+ *
+ * @since 1.0
+ */
public static final int VERTICAL_ALIGN_BOTTOM = 3;
- /** Alignment of a text element. */
+ /**
+ * Alignment of a text element.
+ *
+ * @since 1.0
+ */
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({TEXT_ALIGN_UNDEFINED, TEXT_ALIGN_START, TEXT_ALIGN_CENTER, TEXT_ALIGN_END})
@Retention(RetentionPolicy.SOURCE)
public @interface TextAlignment {}
- /** Alignment is undefined. */
+ /**
+ * Alignment is undefined.
+ *
+ * @since 1.0
+ */
public static final int TEXT_ALIGN_UNDEFINED = 0;
/**
* Align to the "start" of the {@link androidx.wear.protolayout.LayoutElementBuilders.Text}
* element (left in LTR layouts, right in RTL layouts).
+ *
+ * @since 1.0
*/
public static final int TEXT_ALIGN_START = 1;
/**
* Align to the center of the {@link androidx.wear.protolayout.LayoutElementBuilders.Text}
* element.
+ *
+ * @since 1.0
*/
public static final int TEXT_ALIGN_CENTER = 2;
/**
* Align to the "end" of the {@link androidx.wear.protolayout.LayoutElementBuilders.Text}
* element (right in LTR layouts, left in RTL layouts).
+ *
+ * @since 1.0
*/
public static final int TEXT_ALIGN_END = 3;
@@ -4814,30 +5850,42 @@
* Hello World!
*
* }</pre>
+ *
+ * @since 1.0
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({ARC_ANCHOR_UNDEFINED, ARC_ANCHOR_START, ARC_ANCHOR_CENTER, ARC_ANCHOR_END})
@Retention(RetentionPolicy.SOURCE)
public @interface ArcAnchorType {}
- /** Anchor position is undefined. */
+ /**
+ * Anchor position is undefined.
+ *
+ * @since 1.0
+ */
public static final int ARC_ANCHOR_UNDEFINED = 0;
/**
* Anchor at the start of the elements. This will cause elements added to an arc to begin at the
* given anchor_angle, and sweep around to the right.
+ *
+ * @since 1.0
*/
public static final int ARC_ANCHOR_START = 1;
/**
* Anchor at the center of the elements. This will cause the center of the whole set of elements
* added to an arc to be pinned at the given anchor_angle.
+ *
+ * @since 1.0
*/
public static final int ARC_ANCHOR_CENTER = 2;
/**
* Anchor at the end of the elements. This will cause the set of elements inside the arc to end
* at the specified anchor_angle, i.e. all elements should be to the left of anchor_angle.
+ *
+ * @since 1.0
*/
public static final int ARC_ANCHOR_END = 3;
@@ -4892,7 +5940,11 @@
*/
public static final int ANGULAR_ALIGNMENT_END = 3;
- /** An extensible {@code HorizontalAlignment} property. */
+ /**
+ * An extensible {@code HorizontalAlignment} property.
+ *
+ * @since 1.0
+ */
public static final class HorizontalAlignmentProp {
private final AlignmentProto.HorizontalAlignmentProp mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -4903,7 +5955,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the value. Intended for testing purposes only. */
+ /**
+ * Gets the value.
+ *
+ * @since 1.0
+ */
@HorizontalAlignment
public int getValue() {
return mImpl.getValue().getNumber();
@@ -4916,26 +5972,47 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static HorizontalAlignmentProp fromProto(
- @NonNull AlignmentProto.HorizontalAlignmentProp proto) {
- return new HorizontalAlignmentProp(proto, null);
+ public static HorizontalAlignmentProp fromProto(
+ @NonNull AlignmentProto.HorizontalAlignmentProp proto,
+ @Nullable Fingerprint fingerprint) {
+ return new HorizontalAlignmentProp(proto, fingerprint);
}
@NonNull
- AlignmentProto.HorizontalAlignmentProp toProto() {
+ static HorizontalAlignmentProp fromProto(
+ @NonNull AlignmentProto.HorizontalAlignmentProp proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public AlignmentProto.HorizontalAlignmentProp toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "HorizontalAlignmentProp{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link HorizontalAlignmentProp} */
public static final class Builder {
private final AlignmentProto.HorizontalAlignmentProp.Builder mImpl =
AlignmentProto.HorizontalAlignmentProp.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(-384830516);
+ private final Fingerprint mFingerprint = new Fingerprint(1412659592);
public Builder() {}
- /** Sets the value. */
+ /**
+ * Sets the value.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setValue(@HorizontalAlignment int value) {
mImpl.setValue(AlignmentProto.HorizontalAlignment.forNumber(value));
@@ -4951,7 +6028,11 @@
}
}
- /** An extensible {@code VerticalAlignment} property. */
+ /**
+ * An extensible {@code VerticalAlignment} property.
+ *
+ * @since 1.0
+ */
public static final class VerticalAlignmentProp {
private final AlignmentProto.VerticalAlignmentProp mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -4962,7 +6043,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the value. Intended for testing purposes only. */
+ /**
+ * Gets the value.
+ *
+ * @since 1.0
+ */
@VerticalAlignment
public int getValue() {
return mImpl.getValue().getNumber();
@@ -4975,26 +6060,47 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static VerticalAlignmentProp fromProto(
- @NonNull AlignmentProto.VerticalAlignmentProp proto) {
- return new VerticalAlignmentProp(proto, null);
+ public static VerticalAlignmentProp fromProto(
+ @NonNull AlignmentProto.VerticalAlignmentProp proto,
+ @Nullable Fingerprint fingerprint) {
+ return new VerticalAlignmentProp(proto, fingerprint);
}
@NonNull
- AlignmentProto.VerticalAlignmentProp toProto() {
+ static VerticalAlignmentProp fromProto(
+ @NonNull AlignmentProto.VerticalAlignmentProp proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public AlignmentProto.VerticalAlignmentProp toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "VerticalAlignmentProp{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link VerticalAlignmentProp} */
public static final class Builder {
private final AlignmentProto.VerticalAlignmentProp.Builder mImpl =
AlignmentProto.VerticalAlignmentProp.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(1443510393);
+ private final Fingerprint mFingerprint = new Fingerprint(1488177384);
public Builder() {}
- /** Sets the value. */
+ /**
+ * Sets the value.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setValue(@VerticalAlignment int value) {
mImpl.setValue(AlignmentProto.VerticalAlignment.forNumber(value));
@@ -5010,7 +6116,11 @@
}
}
- /** An extensible {@code TextAlignment} property. */
+ /**
+ * An extensible {@code TextAlignment} property.
+ *
+ * @since 1.0
+ */
public static final class TextAlignmentProp {
private final AlignmentProto.TextAlignmentProp mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -5021,7 +6131,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the value. Intended for testing purposes only. */
+ /**
+ * Gets the value.
+ *
+ * @since 1.0
+ */
@TextAlignment
public int getValue() {
return mImpl.getValue().getNumber();
@@ -5034,25 +6148,46 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static TextAlignmentProp fromProto(@NonNull AlignmentProto.TextAlignmentProp proto) {
- return new TextAlignmentProp(proto, null);
+ public static TextAlignmentProp fromProto(
+ @NonNull AlignmentProto.TextAlignmentProp proto,
+ @Nullable Fingerprint fingerprint) {
+ return new TextAlignmentProp(proto, fingerprint);
}
@NonNull
- AlignmentProto.TextAlignmentProp toProto() {
+ static TextAlignmentProp fromProto(@NonNull AlignmentProto.TextAlignmentProp proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public AlignmentProto.TextAlignmentProp toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "TextAlignmentProp{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link TextAlignmentProp} */
public static final class Builder {
private final AlignmentProto.TextAlignmentProp.Builder mImpl =
AlignmentProto.TextAlignmentProp.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(797507251);
+ private final Fingerprint mFingerprint = new Fingerprint(1800500598);
public Builder() {}
- /** Sets the value. */
+ /**
+ * Sets the value.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setValue(@TextAlignment int value) {
mImpl.setValue(AlignmentProto.TextAlignment.forNumber(value));
@@ -5068,7 +6203,11 @@
}
}
- /** An extensible {@code ArcAnchorType} property. */
+ /**
+ * An extensible {@code ArcAnchorType} property.
+ *
+ * @since 1.0
+ */
public static final class ArcAnchorTypeProp {
private final AlignmentProto.ArcAnchorTypeProp mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -5079,7 +6218,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the value. Intended for testing purposes only. */
+ /**
+ * Gets the value.
+ *
+ * @since 1.0
+ */
@ArcAnchorType
public int getValue() {
return mImpl.getValue().getNumber();
@@ -5092,25 +6235,46 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static ArcAnchorTypeProp fromProto(@NonNull AlignmentProto.ArcAnchorTypeProp proto) {
- return new ArcAnchorTypeProp(proto, null);
+ public static ArcAnchorTypeProp fromProto(
+ @NonNull AlignmentProto.ArcAnchorTypeProp proto,
+ @Nullable Fingerprint fingerprint) {
+ return new ArcAnchorTypeProp(proto, fingerprint);
}
@NonNull
- AlignmentProto.ArcAnchorTypeProp toProto() {
+ static ArcAnchorTypeProp fromProto(@NonNull AlignmentProto.ArcAnchorTypeProp proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public AlignmentProto.ArcAnchorTypeProp toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ArcAnchorTypeProp{" + "value=" + getValue() + "}";
+ }
+
/** Builder for {@link ArcAnchorTypeProp} */
public static final class Builder {
private final AlignmentProto.ArcAnchorTypeProp.Builder mImpl =
AlignmentProto.ArcAnchorTypeProp.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(1193249074);
+ private final Fingerprint mFingerprint = new Fingerprint(-496387006);
public Builder() {}
- /** Sets the value. */
+ /**
+ * Sets the value.
+ *
+ * @since 1.0
+ */
@NonNull
public Builder setValue(@ArcAnchorType int value) {
mImpl.setValue(AlignmentProto.ArcAnchorType.forNumber(value));
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
index 4ee3ffe..5493def 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
@@ -24,6 +24,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.wear.protolayout.ActionBuilders.Action;
@@ -388,6 +389,12 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Clickable{" + "id=" + getId() + ", onClick=" + getOnClick() + "}";
+ }
+
/** Builder for {@link Clickable} */
public static final class Builder {
private final ModifiersProto.Clickable.Builder mImpl =
@@ -449,6 +456,9 @@
* Gets the content description associated with this element. This will be dictated when the
* element is focused by the screen reader.
*
+ * <p>While this field is statically accessible from 1.0, it's only bindable since version
+ * 1.2 and renderers supporting version 1.2 will use the dynamic value (if set).
+ *
* @since 1.0
*/
@Nullable
@@ -515,6 +525,19 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Semantics{"
+ + "contentDescription="
+ + getContentDescription()
+ + ", role="
+ + getRole()
+ + ", stateDescription="
+ + getStateDescription()
+ + "}";
+ }
+
/** Builder for {@link Semantics} */
public static final class Builder {
private final ModifiersProto.Semantics.Builder mImpl =
@@ -713,6 +736,23 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Padding{"
+ + "end="
+ + getEnd()
+ + ", start="
+ + getStart()
+ + ", top="
+ + getTop()
+ + ", bottom="
+ + getBottom()
+ + ", rtlAware="
+ + getRtlAware()
+ + "}";
+ }
+
/** Builder for {@link Padding} */
public static final class Builder {
private final ModifiersProto.Padding.Builder mImpl =
@@ -818,6 +858,8 @@
* start/end will follow the layout direction (i.e. start will refer to the right hand
* side of the container if the device is using an RTL locale). If false, start/end will
* always map to left/right, accordingly.
+ *
+ * @since 1.0
*/
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
@@ -877,6 +919,9 @@
/**
* Gets the color of the border.
*
+ * <p>While this field is statically accessible from 1.0, it's only bindable since version
+ * 1.2 and renderers supporting version 1.2 will use the dynamic value (if set).
+ *
* @since 1.0
*/
@Nullable
@@ -915,6 +960,12 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Border{" + "width=" + getWidth() + ", color=" + getColor() + "}";
+ }
+
/** Builder for {@link Border} */
public static final class Builder {
private final ModifiersProto.Border.Builder mImpl = ModifiersProto.Border.newBuilder();
@@ -1019,6 +1070,12 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Corner{" + "radius=" + getRadius() + "}";
+ }
+
/** Builder for {@link Corner} */
public static final class Builder {
private final ModifiersProto.Corner.Builder mImpl = ModifiersProto.Corner.newBuilder();
@@ -1070,6 +1127,9 @@
* Gets the background color for this element. If not defined, defaults to being
* transparent.
*
+ * <p>While this field is statically accessible from 1.0, it's only bindable since version
+ * 1.2 and renderers supporting version 1.2 will use the dynamic value (if set).
+ *
* @since 1.0
*/
@Nullable
@@ -1124,6 +1184,12 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Background{" + "color=" + getColor() + ", corner=" + getCorner() + "}";
+ }
+
/** Builder for {@link Background} */
public static final class Builder {
private final ModifiersProto.Background.Builder mImpl =
@@ -1225,6 +1291,12 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ElementMetadata{" + "tagData=" + Arrays.toString(getTagData()) + "}";
+ }
+
/** Builder for {@link ElementMetadata} */
public static final class Builder {
private final ModifiersProto.ElementMetadata.Builder mImpl =
@@ -1406,6 +1478,28 @@
return mImpl;
}
+ @Override
+ @OptIn(markerClass = ProtoLayoutExperimental.class)
+ @NonNull
+ public String toString() {
+ return "Modifiers{"
+ + "clickable="
+ + getClickable()
+ + ", semantics="
+ + getSemantics()
+ + ", padding="
+ + getPadding()
+ + ", border="
+ + getBorder()
+ + ", background="
+ + getBackground()
+ + ", metadata="
+ + getMetadata()
+ + ", contentUpdateAnimation="
+ + getContentUpdateAnimation()
+ + "}";
+ }
+
/** Builder for {@link Modifiers} */
public static final class Builder {
private final ModifiersProto.Modifiers.Builder mImpl =
@@ -2673,6 +2767,17 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ArcModifiers{"
+ + "clickable="
+ + getClickable()
+ + ", semantics="
+ + getSemantics()
+ + "}";
+ }
+
/** Builder for {@link ArcModifiers} */
public static final class Builder {
private final ModifiersProto.ArcModifiers.Builder mImpl =
@@ -2775,6 +2880,12 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "SpanModifiers{" + "clickable=" + getClickable() + "}";
+ }
+
/** Builder for {@link SpanModifiers} */
public static final class Builder {
private final ModifiersProto.SpanModifiers.Builder mImpl =
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java
index 5ac3531..b354f38 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java
@@ -126,10 +126,8 @@
public int getResourceId() {
return mImpl.getResourceId();
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static AndroidImageResourceByResId fromProto(
@@ -137,10 +135,7 @@
return new AndroidImageResourceByResId(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ResourceProto.AndroidImageResourceByResId toProto() {
@@ -237,10 +232,8 @@
public int getFormat() {
return mImpl.getFormat().getNumber();
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static InlineImageResource fromProto(
@@ -248,10 +241,7 @@
return new InlineImageResource(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ResourceProto.InlineImageResource toProto() {
@@ -385,10 +375,8 @@
return null;
}
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static AndroidAnimatedImageResourceByResId fromProto(
@@ -396,10 +384,7 @@
return new AndroidAnimatedImageResourceByResId(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ResourceProto.AndroidAnimatedImageResourceByResId toProto() {
@@ -523,10 +508,8 @@
return null;
}
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static AndroidSeekableAnimatedImageResourceByResId fromProto(
@@ -534,10 +517,7 @@
return new AndroidSeekableAnimatedImageResourceByResId(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ResourceProto.AndroidSeekableAnimatedImageResourceByResId toProto() {
@@ -688,20 +668,15 @@
return null;
}
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static ImageResource fromProto(@NonNull ResourceProto.ImageResource proto) {
return new ImageResource(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ResourceProto.ImageResource toProto() {
@@ -838,20 +813,14 @@
return Collections.unmodifiableMap(map);
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static Resources fromProto(@NonNull ResourceProto.Resources proto) {
return new Resources(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ResourceProto.Resources toProto() {
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/StateBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/StateBuilders.java
index 601ab2d..9740840 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/StateBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/StateBuilders.java
@@ -57,7 +57,7 @@
/**
* Returns the maximum number for state entries that can be added to the {@link State} using
- * {@link Builder#addIdToValueMapping(String, StateEntryValue)}.
+ * {@link Builder#addKeyToValueMapping(AppDataKey, DynamicDataValue)}.
*
* <p>The ProtoLayout state model is not designed to handle large volumes of layout provided
* state. So we limit the number of state entries to keep the on-the-wire size and state
@@ -82,12 +82,12 @@
* @since 1.2
*/
@NonNull
- public Map<String, DynamicDataValue> getIdToValueMapping() {
- Map<String, DynamicDataValue> map = new HashMap<>();
+ public Map<AppDataKey<?>, DynamicDataValue> getKeyToValueMapping() {
+ Map<AppDataKey<?>, DynamicDataValue> map = new HashMap<>();
for (Entry<String, DynamicDataProto.DynamicDataValue> entry :
mImpl.getIdToValueMap().entrySet()) {
map.put(
- entry.getKey(),
+ new AppDataKey<>(entry.getKey()),
DynamicDataBuilders.dynamicDataValueFromProto(entry.getValue()));
}
return Collections.unmodifiableMap(map);
@@ -102,10 +102,8 @@
public Fingerprint getFingerprint() {
return mFingerprint;
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static State fromProto(
@@ -116,7 +114,6 @@
/**
* Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
* created using this method can't be added to any other wrapper.
- *
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@@ -124,10 +121,7 @@
return fromProto(proto, null);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public StateProto.State toProto() {
@@ -140,8 +134,8 @@
return "State{"
+ "lastClickableId="
+ getLastClickableId()
- + ", idToValueMapping="
- + getIdToValueMapping()
+ + ", keyToValueMapping="
+ + getKeyToValueMapping()
+ "}";
}
@@ -155,6 +149,8 @@
/**
* Adds an entry into any shared state between the provider and renderer.
*
+ * @throws IllegalStateException if adding the new key/value will make the state larger
+ * than the allowed limit ({@link #getMaxStateEntryCount()}).
* @since 1.2
*/
@SuppressLint("MissingGetterMatchingBuilder")
@@ -162,6 +158,12 @@
public Builder addKeyToValueMapping(
@NonNull AppDataKey<?> sourceKey,
@NonNull DynamicDataValue value) {
+ if (mImpl.getIdToValueMap().size() >= getMaxStateEntryCount()) {
+ throw new IllegalStateException(
+ String.format(
+ "Can't add more entries to the state. It is already at its "
+ + "maximum allowed size of %d.", getMaxStateEntryCount()));
+ }
mImpl.putIdToValue(sourceKey.getKey(), value.toDynamicDataValueProto());
mFingerprint.recordPropertyUpdate(
sourceKey.getKey().hashCode(),
@@ -169,9 +171,11 @@
return this;
}
-
-
- /** Builds an instance from accumulated values. */
+ /** Builds an instance from accumulated values.
+ *
+ * @throws IllegalStateException if number of key/value pairs are greater than
+ * {@link #getMaxStateEntryCount()}.
+ */
@NonNull
public State build() {
if (mImpl.getIdToValueMap().size() > getMaxStateEntryCount()) {
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TimelineBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TimelineBuilders.java
index 88ed42a..18e51fb 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TimelineBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TimelineBuilders.java
@@ -62,26 +62,32 @@
public long getEndMillis() {
return mImpl.getEndMillis();
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static TimeInterval fromProto(@NonNull TimelineProto.TimeInterval proto) {
return new TimeInterval(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public TimelineProto.TimeInterval toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "TimeInterval{"
+ + "startMillis="
+ + getStartMillis()
+ + ", endMillis="
+ + getEndMillis()
+ + "}";
+ }
+
/** Builder for {@link TimeInterval} */
public static final class Builder {
private final TimelineProto.TimeInterval.Builder mImpl =
@@ -159,33 +165,37 @@
}
}
- /** Returns the {@link TimelineEntry} object containing the given layout element. */
+ /**
+ * Returns the {@link TimelineEntry} object containing the given layout element.
+ *
+ * @since 1.0
+ */
@NonNull
public static TimelineEntry fromLayoutElement(
@NonNull LayoutElementBuilders.LayoutElement layoutElement) {
return new Builder().setLayout(Layout.fromLayoutElement(layoutElement)).build();
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static TimelineEntry fromProto(@NonNull TimelineProto.TimelineEntry proto) {
return new TimelineEntry(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public TimelineProto.TimelineEntry toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "TimelineEntry{" + "validity=" + getValidity() + ", layout=" + getLayout() + "}";
+ }
+
/** Builder for {@link TimelineEntry} */
public static final class Builder {
private final TimelineProto.TimelineEntry.Builder mImpl =
@@ -259,27 +269,25 @@
return Collections.unmodifiableList(list);
}
- /** Returns the {@link Timeline} object containing the given layout element. */
+ /**
+ * Returns the {@link Timeline} object containing the given layout element.
+ *
+ * @since 1.0
+ */
@NonNull
public static Timeline fromLayoutElement(
@NonNull LayoutElementBuilders.LayoutElement layoutElement) {
return new Builder().addTimelineEntry(TimelineEntry.fromLayoutElement(layoutElement)).build();
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static Timeline fromProto(@NonNull TimelineProto.Timeline proto) {
return new Timeline(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public TimelineProto.Timeline toProto() {
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TriggerBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TriggerBuilders.java
index f5cb3c8..f1c3067 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TriggerBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TriggerBuilders.java
@@ -68,12 +68,22 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static OnLoadTrigger fromProto(@NonNull TriggerProto.OnLoadTrigger proto) {
- return new OnLoadTrigger(proto, null);
+ public static OnLoadTrigger fromProto(
+ @NonNull TriggerProto.OnLoadTrigger proto, @Nullable Fingerprint fingerprint) {
+ return new OnLoadTrigger(proto, fingerprint);
}
@NonNull
+ static OnLoadTrigger fromProto(@NonNull TriggerProto.OnLoadTrigger proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
TriggerProto.OnLoadTrigger toProto() {
return mImpl;
}
@@ -85,6 +95,12 @@
return TriggerProto.Trigger.newBuilder().setOnLoadTrigger(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "OnLoadTrigger";
+ }
+
/** Builder for {@link OnLoadTrigger}. */
public static final class Builder implements Trigger.Builder {
private final TriggerProto.OnLoadTrigger.Builder mImpl =
@@ -117,7 +133,7 @@
}
/**
- * Gets dynamic boolean used as trigger. Intended for testing purposes only.
+ * Gets dynamic boolean used as trigger.
*
* @since 1.2
*/
@@ -137,12 +153,23 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static OnConditionMetTrigger fromProto(@NonNull TriggerProto.OnConditionMetTrigger proto) {
- return new OnConditionMetTrigger(proto, null);
+ public static OnConditionMetTrigger fromProto(
+ @NonNull TriggerProto.OnConditionMetTrigger proto,
+ @Nullable Fingerprint fingerprint) {
+ return new OnConditionMetTrigger(proto, fingerprint);
}
@NonNull
+ static OnConditionMetTrigger fromProto(@NonNull TriggerProto.OnConditionMetTrigger proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
TriggerProto.OnConditionMetTrigger toProto() {
return mImpl;
}
@@ -154,11 +181,17 @@
return TriggerProto.Trigger.newBuilder().setOnConditionMetTrigger(mImpl).build();
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "OnConditionMetTrigger{" + "condition=" + getCondition() + "}";
+ }
+
/** Builder for {@link OnConditionMetTrigger}. */
public static final class Builder implements Trigger.Builder {
private final TriggerProto.OnConditionMetTrigger.Builder mImpl =
TriggerProto.OnConditionMetTrigger.newBuilder();
- private final Fingerprint mFingerprint = new Fingerprint(1952746052);
+ private final Fingerprint mFingerprint = new Fingerprint(756642641);
public Builder() {}
@@ -190,25 +223,17 @@
* @since 1.2
*/
public interface Trigger {
- /**
- * Get the protocol buffer representation of this object.
- *
- */
+ /** Get the protocol buffer representation of this object. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
TriggerProto.Trigger toTriggerProto();
- /**
- * Get the fingerprint for this object or null if unknown.
- *
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
Fingerprint getFingerprint();
- /** Builder to create {@link Trigger} objects.
- *
- */
+ /** Builder to create {@link Trigger} objects. */
@RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
@@ -218,14 +243,22 @@
}
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Trigger triggerFromProto(@NonNull TriggerProto.Trigger proto) {
+ public static Trigger triggerFromProto(
+ @NonNull TriggerProto.Trigger proto, @Nullable Fingerprint fingerprint) {
if (proto.hasOnLoadTrigger()) {
- return OnLoadTrigger.fromProto(proto.getOnLoadTrigger());
+ return OnLoadTrigger.fromProto(proto.getOnLoadTrigger(), fingerprint);
}
if (proto.hasOnConditionMetTrigger()) {
- return OnConditionMetTrigger.fromProto(proto.getOnConditionMetTrigger());
+ return OnConditionMetTrigger.fromProto(proto.getOnConditionMetTrigger(), fingerprint);
}
throw new IllegalStateException("Proto was not a recognised instance of Trigger");
}
+
+ @NonNull
+ static Trigger triggerFromProto(@NonNull TriggerProto.Trigger proto) {
+ return triggerFromProto(proto, null);
+ }
}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java
index 15cf3aa..9acc6574 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java
@@ -64,16 +64,35 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static Int32Prop fromProto(@NonNull TypesProto.Int32Prop proto) {
- return new Int32Prop(proto, null);
+ public static Int32Prop fromProto(
+ @NonNull TypesProto.Int32Prop proto, @Nullable Fingerprint fingerprint) {
+ return new Int32Prop(proto, fingerprint);
}
@NonNull
- TypesProto.Int32Prop toProto() {
+ static Int32Prop fromProto(@NonNull TypesProto.Int32Prop proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public TypesProto.Int32Prop toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "Int32Prop{"
+ + "value="
+ + getValue()
+ + "}";
+ }
+
/** Builder for {@link Int32Prop} */
public static final class Builder {
private final TypesProto.Int32Prop.Builder mImpl = TypesProto.Int32Prop.newBuilder();
@@ -146,9 +165,17 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public static StringProp fromProto(
+ @NonNull TypesProto.StringProp proto, @Nullable Fingerprint fingerprint) {
+ return new StringProp(proto, fingerprint);
+ }
+
@NonNull
static StringProp fromProto(@NonNull TypesProto.StringProp proto) {
- return new StringProp(proto, null);
+ return fromProto(proto, null);
}
/** Returns the internal proto instance. */
@@ -158,6 +185,17 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "StringProp{"
+ + "value="
+ + getValue()
+ + ", dynamicValue="
+ + getDynamicValue()
+ + "}";
+ }
+
/** Builder for {@link StringProp} */
public static final class Builder {
private final TypesProto.StringProp.Builder mImpl = TypesProto.StringProp.newBuilder();
@@ -182,7 +220,8 @@
/**
* Sets the static value. If a dynamic value is also set and the renderer supports
- * dynamic values for the corresponding field, this static value will be ignored.
+ * dynamic values for the corresponding field, this static value will be ignored. If the
+ * static value is not specified, {@code null} will be used instead.
*
* @since 1.0
*/
@@ -195,7 +234,9 @@
/**
* Sets the dynamic value. Note that when setting this value, the static value is still
- * required to be set to support older renderers that only read the static value.
+ * required to be set to support older renderers that only read the static value. If
+ * {@code dynamicValue} has an invalid result, the provided static value will be used
+ * instead.
*
* @since 1.2
*/
@@ -207,7 +248,14 @@
return this;
}
- /** Builds an instance from accumulated values. */
+ /**
+ * Builds an instance from accumulated values.
+ *
+ * @throws IllegalStateException if a dynamic value is set using {@link
+ * #setDynamicValue(DynamicBuilders.DynamicString)} but neither {@link
+ * #Builder(String)} nor {@link #setValue(String)} is used to provide a static
+ * value.
+ */
@NonNull
public StringProp build() {
if (mImpl.hasDynamicValue() && !mImpl.hasValue()) {
@@ -366,16 +414,37 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static FloatProp fromProto(@NonNull TypesProto.FloatProp proto) {
- return new FloatProp(proto, null);
+ public static FloatProp fromProto(
+ @NonNull TypesProto.FloatProp proto, @Nullable Fingerprint fingerprint) {
+ return new FloatProp(proto, fingerprint);
}
@NonNull
- TypesProto.FloatProp toProto() {
+ static FloatProp fromProto(@NonNull TypesProto.FloatProp proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public TypesProto.FloatProp toProto() {
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "FloatProp{"
+ + "value="
+ + getValue()
+ + ", dynamicValue="
+ + getDynamicValue()
+ + "}";
+ }
+
/** Builder for {@link FloatProp} */
public static final class Builder {
private final TypesProto.FloatProp.Builder mImpl = TypesProto.FloatProp.newBuilder();
@@ -400,8 +469,8 @@
/**
* Sets the static value. If a dynamic value is also set and the renderer supports
- * dynamic values for the corresponding field, this static value will be ignored.
- * If the static value is not specified, Zero will be used instead.
+ * dynamic values for the corresponding field, this static value will be ignored. If the
+ * static value is not specified, zero will be used instead.
*
* @since 1.0
*/
@@ -415,9 +484,8 @@
/**
* Sets the dynamic value. Note that when setting this value, the static value is still
* required to be set (with either {@link #Builder(float)} or {@link #setValue(float)})
- * to support older renderers that only read the static value. If {@code dynamicValue
- * } has an invalid result, the provided static value will be used
- * instead.
+ * to support older renderers that only read the static value. If {@code dynamicValue }
+ * has an invalid result, the provided static value will be used instead.
*
* @since 1.2
*/
@@ -432,15 +500,13 @@
/**
* Builds an instance from accumulated values.
*
- * @throws IllegalStateException if a dynamic value is set using
- * {@link #setDynamicValue(DynamicFloat)} but neither
- * {@link #Builder(float)} nor
- * {@link #setValue(float)} is used to provide a static
- * value.
+ * @throws IllegalStateException if a dynamic value is set using {@link
+ * #setDynamicValue(DynamicFloat)} but neither {@link #Builder(float)} nor {@link
+ * #setValue(float)} is used to provide a static value.
*/
@NonNull
public FloatProp build() {
- if(mImpl.hasDynamicValue() && !mImpl.hasValue()){
+ if (mImpl.hasDynamicValue() && !mImpl.hasValue()) {
throw new IllegalStateException("Static value is missing.");
}
return new FloatProp(mImpl.build(), mFingerprint);
@@ -478,20 +544,33 @@
return mFingerprint;
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- static BoolProp fromProto(@NonNull TypesProto.BoolProp proto) {
- return new BoolProp(proto, null);
+ public static BoolProp fromProto(
+ @NonNull TypesProto.BoolProp proto, @Nullable Fingerprint fingerprint) {
+ return new BoolProp(proto, fingerprint);
}
@NonNull
- TypesProto.BoolProp toProto() {
+ static BoolProp fromProto(@NonNull TypesProto.BoolProp proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public TypesProto.BoolProp toProto() {
return mImpl;
}
@Override
@NonNull
public String toString() {
- return "BoolProp{" + "value=" + getValue() + "}";
+ return "BoolProp{"
+ + "value="
+ + getValue()
+ + "}";
}
/** Builder for {@link BoolProp} */
diff --git a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/DimensionBuildersTest.java b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/DimensionBuildersTest.java
index 6264fe2..a4dcfdf 100644
--- a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/DimensionBuildersTest.java
+++ b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/DimensionBuildersTest.java
@@ -75,6 +75,7 @@
assertThrows(IllegalStateException.class, DP_PROP_WITHOUT_STATIC_VALUE::build);
}
+ @Test
public void degreesPropSupportsDynamicValue() {
DimensionProto.DegreesProp degreesPropProto = DEGREES_PROP.toProto();
diff --git a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/StateBuildersTest.java b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/StateBuildersTest.java
index 86d9ddb..57bcb1e 100644
--- a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/StateBuildersTest.java
+++ b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/StateBuildersTest.java
@@ -18,22 +18,25 @@
import static com.google.common.truth.Truth.assertThat;
+import androidx.wear.protolayout.expression.AppDataKey;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool;
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString;
import androidx.wear.protolayout.expression.DynamicDataBuilders;
-import androidx.wear.protolayout.expression.AppDataKey;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import java.util.Map;
+import java.util.Set;
+
@RunWith(RobolectricTestRunner.class)
public class StateBuildersTest {
@Test
public void emptyState() {
StateBuilders.State state = new StateBuilders.State.Builder().build();
- assertThat(state.getIdToValueMapping()).isEmpty();
+ assertThat(state.getKeyToValueMapping()).isEmpty();
}
@Test
@@ -42,17 +45,18 @@
DynamicDataBuilders.DynamicDataValue.fromBool(true);
DynamicDataBuilders.DynamicDataValue stringValue =
DynamicDataBuilders.DynamicDataValue.fromString("string");
- StateBuilders.State state = new StateBuilders.State.Builder()
- .addKeyToValueMapping(
- new AppDataKey<DynamicBool>("boolValue"), boolValue)
- .addKeyToValueMapping(
- new AppDataKey<DynamicString>("stringValue"), stringValue)
- .build();
-
- assertThat(state.getIdToValueMapping()).hasSize(2);
- assertThat(state.getIdToValueMapping().get("boolValue").toDynamicDataValueProto())
+ StateBuilders.State state =
+ new StateBuilders.State.Builder()
+ .addKeyToValueMapping(new AppDataKey<DynamicBool>("boolValue"), boolValue)
+ .addKeyToValueMapping(
+ new AppDataKey<DynamicString>("stringValue"), stringValue)
+ .build();
+ assertThat(state.getKeyToValueMapping()).hasSize(2);
+ assertThat(state.getKeyToValueMapping().get(
+ new AppDataKey<>("boolValue")).toDynamicDataValueProto())
.isEqualTo(boolValue.toDynamicDataValueProto());
- assertThat(state.getIdToValueMapping().get("stringValue").toDynamicDataValueProto())
+ assertThat(state.getKeyToValueMapping().get(
+ new AppDataKey<>("stringValue")).toDynamicDataValueProto())
.isEqualTo(stringValue.toDynamicDataValueProto());
}
}
diff --git a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/testapp/GoldenTestActivity.java b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/testapp/GoldenTestActivity.java
index 4f8ca09..fa91df8 100644
--- a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/testapp/GoldenTestActivity.java
+++ b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/testapp/GoldenTestActivity.java
@@ -63,7 +63,7 @@
}
LayoutElementBuilders.LayoutElement rootLayoutElement =
- LayoutElementBuilders.layoutElementFromProto(layoutElementProto);
+ LayoutElementBuilders.layoutElementFromProto(layoutElementProto, null);
Context appContext = getApplicationContext();
FrameLayout root = new FrameLayout(appContext);
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Button.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Button.java
index 02f7bb7..5c1a970 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Button.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Button.java
@@ -35,6 +35,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.LayoutElementProto;
import androidx.wear.tiles.material.Typography.TypographyName;
@@ -570,4 +571,11 @@
public LayoutElementProto.LayoutElement toLayoutElementProto() {
return checkNotNull(mElement.toLayoutElementProto());
}
+
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public Fingerprint getFingerprint() {
+ return mElement.getFingerprint();
+ }
}
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Chip.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Chip.java
index 2278d07..97d61f9 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Chip.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Chip.java
@@ -37,6 +37,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.LayoutElementProto;
import androidx.wear.tiles.material.Typography.TypographyName;
@@ -708,4 +709,11 @@
public LayoutElementProto.LayoutElement toLayoutElementProto() {
return mElement.toLayoutElementProto();
}
+
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public Fingerprint getFingerprint() {
+ return mElement.getFingerprint();
+ }
}
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CircularProgressIndicator.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CircularProgressIndicator.java
index a90f752..1614755 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CircularProgressIndicator.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CircularProgressIndicator.java
@@ -33,6 +33,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.LayoutElementProto;
/**
@@ -364,4 +365,11 @@
public LayoutElementProto.LayoutElement toLayoutElementProto() {
return mElement.toLayoutElementProto();
}
+
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public Fingerprint getFingerprint() {
+ return mElement.getFingerprint();
+ }
}
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CompactChip.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CompactChip.java
index 5c1a8f6..093bd13 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CompactChip.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CompactChip.java
@@ -30,6 +30,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.LayoutElementProto;
/**
@@ -243,4 +244,11 @@
public LayoutElementProto.LayoutElement toLayoutElementProto() {
return mImpl.toLayoutElementProto();
}
+
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public Fingerprint getFingerprint() {
+ return mImpl.getFingerprint();
+ }
}
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Text.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Text.java
index 8b00f0e..6500734 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Text.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Text.java
@@ -31,6 +31,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.LayoutElementProto;
import androidx.wear.protolayout.proto.ModifiersProto;
import androidx.wear.tiles.material.Typography.TypographyName;
@@ -250,7 +251,8 @@
.setTagData(getTagBytes(METADATA_TAG))
.build()
.toProto())
- .build());
+ .build(),
+ modifiers.getFingerprint());
}
}
@@ -352,4 +354,11 @@
public LayoutElementProto.LayoutElement toLayoutElementProto() {
return mText.toLayoutElementProto();
}
+
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public Fingerprint getFingerprint() {
+ return mText.getFingerprint();
+ }
}
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/TitleChip.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/TitleChip.java
index e2092ed5..f45da44 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/TitleChip.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/TitleChip.java
@@ -30,6 +30,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.LayoutElementProto;
/**
@@ -258,4 +259,11 @@
public LayoutElementProto.LayoutElement toLayoutElementProto() {
return mElement.toLayoutElementProto();
}
+
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public Fingerprint getFingerprint() {
+ return mElement.getFingerprint();
+ }
}
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/EdgeContentLayout.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/EdgeContentLayout.java
index 1dab500..7ef7d33 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/EdgeContentLayout.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/EdgeContentLayout.java
@@ -32,6 +32,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.LayoutElementProto;
import androidx.wear.tiles.material.CircularProgressIndicator;
@@ -419,4 +420,11 @@
public LayoutElementProto.LayoutElement toLayoutElementProto() {
return mImpl.toLayoutElementProto();
}
+
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public Fingerprint getFingerprint() {
+ return mImpl.getFingerprint();
+ }
}
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiButtonLayout.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiButtonLayout.java
index 6233ce7..2f3f43b 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiButtonLayout.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiButtonLayout.java
@@ -32,6 +32,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.LayoutElementProto;
import androidx.wear.tiles.material.Button;
@@ -433,4 +434,11 @@
public LayoutElementProto.LayoutElement toLayoutElementProto() {
return mElement.toLayoutElementProto();
}
+
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public Fingerprint getFingerprint() {
+ return mElement.getFingerprint();
+ }
}
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiSlotLayout.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiSlotLayout.java
index ed5fb72..b184a85 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiSlotLayout.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiSlotLayout.java
@@ -30,6 +30,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.LayoutElementProto;
import java.util.ArrayList;
@@ -243,4 +244,11 @@
public LayoutElementProto.LayoutElement toLayoutElementProto() {
return mElement.toLayoutElementProto();
}
+
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public Fingerprint getFingerprint() {
+ return mElement.getFingerprint();
+ }
}
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/PrimaryLayout.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/PrimaryLayout.java
index 2eb3881..3091cdb 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/PrimaryLayout.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/PrimaryLayout.java
@@ -43,6 +43,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.LayoutElementProto;
import androidx.wear.tiles.material.CompactChip;
@@ -607,4 +608,11 @@
public LayoutElementProto.LayoutElement toLayoutElementProto() {
return mImpl.toLayoutElementProto();
}
+
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public Fingerprint getFingerprint() {
+ return mImpl.getFingerprint();
+ }
}
diff --git a/wear/tiles/tiles-renderer/api/current.txt b/wear/tiles/tiles-renderer/api/current.txt
index ea08664..3bd3943 100644
--- a/wear/tiles/tiles-renderer/api/current.txt
+++ b/wear/tiles/tiles-renderer/api/current.txt
@@ -3,8 +3,9 @@
public interface TileClient {
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> requestApiVersion();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources!> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest);
+ method @Deprecated public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources!> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest);
method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.TileBuilders.Tile!> requestTile(androidx.wear.tiles.RequestBuilders.TileRequest);
+ method public default com.google.common.util.concurrent.ListenableFuture<androidx.wear.protolayout.ResourceBuilders.Resources!> requestTileResourcesAsync(androidx.wear.tiles.RequestBuilders.ResourcesRequest);
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> sendOnTileAddedEvent();
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> sendOnTileEnterEvent();
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> sendOnTileLeaveEvent();
@@ -19,7 +20,7 @@
ctor public DefaultTileClient(android.content.Context context, android.content.ComponentName componentName, java.util.concurrent.Executor executor);
ctor public DefaultTileClient(android.content.Context context, android.content.ComponentName componentName, kotlinx.coroutines.CoroutineScope coroutineScope, kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer> requestApiVersion();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest requestParams);
+ method @Deprecated public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest requestParams);
method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.TileBuilders.Tile> requestTile(androidx.wear.tiles.RequestBuilders.TileRequest requestParams);
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> sendOnTileAddedEvent();
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> sendOnTileEnterEvent();
@@ -47,6 +48,7 @@
ctor public TileRenderer(android.content.Context, java.util.concurrent.Executor, java.util.function.Consumer<androidx.wear.protolayout.StateBuilders.State!>);
method @Deprecated public android.view.View? inflate(android.view.ViewGroup);
method public com.google.common.util.concurrent.ListenableFuture<android.view.View!> inflateAsync(androidx.wear.protolayout.LayoutElementBuilders.Layout, androidx.wear.protolayout.ResourceBuilders.Resources, android.view.ViewGroup);
+ method public void setState(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
}
@Deprecated public static interface TileRenderer.LoadActionListener {
@@ -58,14 +60,19 @@
package androidx.wear.tiles.timeline {
public final class TilesTimelineCache {
- ctor public TilesTimelineCache(androidx.wear.tiles.TimelineBuilders.Timeline);
- method @MainThread public androidx.wear.tiles.TimelineBuilders.TimelineEntry? findClosestTimelineEntry(long);
- method @MainThread public long findCurrentTimelineEntryExpiry(androidx.wear.tiles.TimelineBuilders.TimelineEntry, long);
- method @MainThread public androidx.wear.tiles.TimelineBuilders.TimelineEntry? findTimelineEntryForTime(long);
+ ctor public TilesTimelineCache(androidx.wear.protolayout.TimelineBuilders.Timeline);
+ ctor @Deprecated public TilesTimelineCache(androidx.wear.tiles.TimelineBuilders.Timeline);
+ method @MainThread public androidx.wear.protolayout.TimelineBuilders.TimelineEntry? findClosestTileTimelineEntry(long);
+ method @Deprecated @MainThread public androidx.wear.tiles.TimelineBuilders.TimelineEntry? findClosestTimelineEntry(long);
+ method @MainThread public long findCurrentTimelineEntryExpiry(androidx.wear.protolayout.TimelineBuilders.TimelineEntry, long);
+ method @Deprecated @MainThread public long findCurrentTimelineEntryExpiry(androidx.wear.tiles.TimelineBuilders.TimelineEntry, long);
+ method @MainThread public androidx.wear.protolayout.TimelineBuilders.TimelineEntry? findTileTimelineEntryForTime(long);
+ method @Deprecated @MainThread public androidx.wear.tiles.TimelineBuilders.TimelineEntry? findTimelineEntryForTime(long);
}
public class TilesTimelineManager implements java.lang.AutoCloseable {
- ctor public TilesTimelineManager(android.app.AlarmManager, androidx.wear.tiles.timeline.TilesTimelineManager.Clock, androidx.wear.tiles.TimelineBuilders.Timeline, int, java.util.concurrent.Executor, androidx.wear.tiles.timeline.TilesTimelineManager.Listener);
+ ctor public TilesTimelineManager(android.app.AlarmManager, androidx.wear.tiles.timeline.TilesTimelineManager.Clock, androidx.wear.protolayout.TimelineBuilders.Timeline, int, java.util.concurrent.Executor, androidx.wear.tiles.timeline.TilesTimelineManager.LayoutUpdateListener);
+ ctor @Deprecated public TilesTimelineManager(android.app.AlarmManager, androidx.wear.tiles.timeline.TilesTimelineManager.Clock, androidx.wear.tiles.TimelineBuilders.Timeline, int, java.util.concurrent.Executor, androidx.wear.tiles.timeline.TilesTimelineManager.Listener);
method public void close();
method public void init();
}
@@ -74,8 +81,12 @@
method public long getCurrentTimeMillis();
}
- public static interface TilesTimelineManager.Listener {
- method public void onLayoutUpdate(int, androidx.wear.tiles.LayoutElementBuilders.Layout);
+ public static interface TilesTimelineManager.LayoutUpdateListener {
+ method public void onLayoutUpdate(int, androidx.wear.protolayout.LayoutElementBuilders.Layout);
+ }
+
+ @Deprecated public static interface TilesTimelineManager.Listener {
+ method @Deprecated public void onLayoutUpdate(int, androidx.wear.tiles.LayoutElementBuilders.Layout);
}
}
diff --git a/wear/tiles/tiles-renderer/api/restricted_current.txt b/wear/tiles/tiles-renderer/api/restricted_current.txt
index ea08664..3bd3943 100644
--- a/wear/tiles/tiles-renderer/api/restricted_current.txt
+++ b/wear/tiles/tiles-renderer/api/restricted_current.txt
@@ -3,8 +3,9 @@
public interface TileClient {
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> requestApiVersion();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources!> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest);
+ method @Deprecated public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources!> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest);
method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.TileBuilders.Tile!> requestTile(androidx.wear.tiles.RequestBuilders.TileRequest);
+ method public default com.google.common.util.concurrent.ListenableFuture<androidx.wear.protolayout.ResourceBuilders.Resources!> requestTileResourcesAsync(androidx.wear.tiles.RequestBuilders.ResourcesRequest);
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> sendOnTileAddedEvent();
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> sendOnTileEnterEvent();
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> sendOnTileLeaveEvent();
@@ -19,7 +20,7 @@
ctor public DefaultTileClient(android.content.Context context, android.content.ComponentName componentName, java.util.concurrent.Executor executor);
ctor public DefaultTileClient(android.content.Context context, android.content.ComponentName componentName, kotlinx.coroutines.CoroutineScope coroutineScope, kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer> requestApiVersion();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest requestParams);
+ method @Deprecated public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest requestParams);
method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.TileBuilders.Tile> requestTile(androidx.wear.tiles.RequestBuilders.TileRequest requestParams);
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> sendOnTileAddedEvent();
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> sendOnTileEnterEvent();
@@ -47,6 +48,7 @@
ctor public TileRenderer(android.content.Context, java.util.concurrent.Executor, java.util.function.Consumer<androidx.wear.protolayout.StateBuilders.State!>);
method @Deprecated public android.view.View? inflate(android.view.ViewGroup);
method public com.google.common.util.concurrent.ListenableFuture<android.view.View!> inflateAsync(androidx.wear.protolayout.LayoutElementBuilders.Layout, androidx.wear.protolayout.ResourceBuilders.Resources, android.view.ViewGroup);
+ method public void setState(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
}
@Deprecated public static interface TileRenderer.LoadActionListener {
@@ -58,14 +60,19 @@
package androidx.wear.tiles.timeline {
public final class TilesTimelineCache {
- ctor public TilesTimelineCache(androidx.wear.tiles.TimelineBuilders.Timeline);
- method @MainThread public androidx.wear.tiles.TimelineBuilders.TimelineEntry? findClosestTimelineEntry(long);
- method @MainThread public long findCurrentTimelineEntryExpiry(androidx.wear.tiles.TimelineBuilders.TimelineEntry, long);
- method @MainThread public androidx.wear.tiles.TimelineBuilders.TimelineEntry? findTimelineEntryForTime(long);
+ ctor public TilesTimelineCache(androidx.wear.protolayout.TimelineBuilders.Timeline);
+ ctor @Deprecated public TilesTimelineCache(androidx.wear.tiles.TimelineBuilders.Timeline);
+ method @MainThread public androidx.wear.protolayout.TimelineBuilders.TimelineEntry? findClosestTileTimelineEntry(long);
+ method @Deprecated @MainThread public androidx.wear.tiles.TimelineBuilders.TimelineEntry? findClosestTimelineEntry(long);
+ method @MainThread public long findCurrentTimelineEntryExpiry(androidx.wear.protolayout.TimelineBuilders.TimelineEntry, long);
+ method @Deprecated @MainThread public long findCurrentTimelineEntryExpiry(androidx.wear.tiles.TimelineBuilders.TimelineEntry, long);
+ method @MainThread public androidx.wear.protolayout.TimelineBuilders.TimelineEntry? findTileTimelineEntryForTime(long);
+ method @Deprecated @MainThread public androidx.wear.tiles.TimelineBuilders.TimelineEntry? findTimelineEntryForTime(long);
}
public class TilesTimelineManager implements java.lang.AutoCloseable {
- ctor public TilesTimelineManager(android.app.AlarmManager, androidx.wear.tiles.timeline.TilesTimelineManager.Clock, androidx.wear.tiles.TimelineBuilders.Timeline, int, java.util.concurrent.Executor, androidx.wear.tiles.timeline.TilesTimelineManager.Listener);
+ ctor public TilesTimelineManager(android.app.AlarmManager, androidx.wear.tiles.timeline.TilesTimelineManager.Clock, androidx.wear.protolayout.TimelineBuilders.Timeline, int, java.util.concurrent.Executor, androidx.wear.tiles.timeline.TilesTimelineManager.LayoutUpdateListener);
+ ctor @Deprecated public TilesTimelineManager(android.app.AlarmManager, androidx.wear.tiles.timeline.TilesTimelineManager.Clock, androidx.wear.tiles.TimelineBuilders.Timeline, int, java.util.concurrent.Executor, androidx.wear.tiles.timeline.TilesTimelineManager.Listener);
method public void close();
method public void init();
}
@@ -74,8 +81,12 @@
method public long getCurrentTimeMillis();
}
- public static interface TilesTimelineManager.Listener {
- method public void onLayoutUpdate(int, androidx.wear.tiles.LayoutElementBuilders.Layout);
+ public static interface TilesTimelineManager.LayoutUpdateListener {
+ method public void onLayoutUpdate(int, androidx.wear.protolayout.LayoutElementBuilders.Layout);
+ }
+
+ @Deprecated public static interface TilesTimelineManager.Listener {
+ method @Deprecated public void onLayoutUpdate(int, androidx.wear.tiles.LayoutElementBuilders.Layout);
}
}
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/checkers/CheckAccessibilityAvailable.kt b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/checkers/CheckAccessibilityAvailable.kt
index af1e39a..75db840 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/checkers/CheckAccessibilityAvailable.kt
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/checkers/CheckAccessibilityAvailable.kt
@@ -16,6 +16,8 @@
package androidx.wear.tiles.checkers
+import androidx.wear.protolayout.LayoutElementBuilders
+import androidx.wear.protolayout.TimelineBuilders
import kotlin.jvm.Throws
/**
@@ -30,8 +32,7 @@
get() = "CheckAccessibilityAvailable"
@Throws(CheckerException::class)
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types.
- override fun check(entry: androidx.wear.tiles.TimelineBuilders.TimelineEntry) {
+ override fun check(entry: TimelineBuilders.TimelineEntry) {
// Do a descent through the tile, checking that at least one element has an a11y tag.
if (entry.layout?.root?.let(this::checkElement) == false) {
throw CheckerException(
@@ -42,20 +43,19 @@
}
}
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types.
private fun checkElement(
- element: androidx.wear.tiles.LayoutElementBuilders.LayoutElement
+ element: LayoutElementBuilders.LayoutElement
): Boolean {
val modifiers =
when (element) {
- is androidx.wear.tiles.LayoutElementBuilders.Row -> element.modifiers
- is androidx.wear.tiles.LayoutElementBuilders.Column -> element.modifiers
- is androidx.wear.tiles.LayoutElementBuilders.Box -> element.modifiers
- is androidx.wear.tiles.LayoutElementBuilders.Arc -> element.modifiers
- is androidx.wear.tiles.LayoutElementBuilders.Spacer -> element.modifiers
- is androidx.wear.tiles.LayoutElementBuilders.Image -> element.modifiers
- is androidx.wear.tiles.LayoutElementBuilders.Text -> element.modifiers
- is androidx.wear.tiles.LayoutElementBuilders.Spannable -> element.modifiers
+ is LayoutElementBuilders.Row -> element.modifiers
+ is LayoutElementBuilders.Column -> element.modifiers
+ is LayoutElementBuilders.Box -> element.modifiers
+ is LayoutElementBuilders.Arc -> element.modifiers
+ is LayoutElementBuilders.Spacer -> element.modifiers
+ is LayoutElementBuilders.Image -> element.modifiers
+ is LayoutElementBuilders.Text -> element.modifiers
+ is LayoutElementBuilders.Spannable -> element.modifiers
else -> null
}
@@ -67,29 +67,28 @@
// Note that individual Spannable elements cannot have semantics; the parent should have
// these.
return when (element) {
- is androidx.wear.tiles.LayoutElementBuilders.Row ->
+ is LayoutElementBuilders.Row ->
element.contents.any(this::checkElement)
- is androidx.wear.tiles.LayoutElementBuilders.Column ->
+ is LayoutElementBuilders.Column ->
element.contents.any(this::checkElement)
- is androidx.wear.tiles.LayoutElementBuilders.Box ->
+ is LayoutElementBuilders.Box ->
element.contents.any(this::checkElement)
- is androidx.wear.tiles.LayoutElementBuilders.Arc ->
+ is LayoutElementBuilders.Arc ->
element.contents.any(this::checkArcLayoutElement)
else -> false
}
}
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types.
private fun checkArcLayoutElement(
- element: androidx.wear.tiles.LayoutElementBuilders.ArcLayoutElement
+ element: LayoutElementBuilders.ArcLayoutElement
): Boolean {
val modifiers =
when (element) {
// Note that ArcAdapter should be handled by taking the modifiers from the inner
// element instead.
- is androidx.wear.tiles.LayoutElementBuilders.ArcText -> element.modifiers
- is androidx.wear.tiles.LayoutElementBuilders.ArcLine -> element.modifiers
- is androidx.wear.tiles.LayoutElementBuilders.ArcSpacer -> element.modifiers
+ is LayoutElementBuilders.ArcText -> element.modifiers
+ is LayoutElementBuilders.ArcLine -> element.modifiers
+ is LayoutElementBuilders.ArcSpacer -> element.modifiers
else -> null
}
@@ -97,7 +96,7 @@
return true
}
- return if (element is androidx.wear.tiles.LayoutElementBuilders.ArcAdapter) {
+ return if (element is LayoutElementBuilders.ArcAdapter) {
element.content?.let(this::checkElement) ?: false
} else {
false
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/checkers/TimelineChecker.kt b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/checkers/TimelineChecker.kt
index 0e96e9a..17aadaf 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/checkers/TimelineChecker.kt
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/checkers/TimelineChecker.kt
@@ -17,6 +17,7 @@
package androidx.wear.tiles.checkers
import android.util.Log
+import androidx.wear.protolayout.TimelineBuilders
import kotlin.jvm.Throws
/**
@@ -39,8 +40,7 @@
* @throws CheckerException if there was an issue while checking the [TimelineEntry]
*/
@Throws(CheckerException::class)
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
- fun check(entry: androidx.wear.tiles.TimelineBuilders.TimelineEntry)
+ fun check(entry: TimelineBuilders.TimelineEntry)
}
/**
@@ -57,8 +57,7 @@
}
/** Check a given [Timeline] against all registered [TimelineEntryChecker]s. */
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
- public fun doCheck(timeline: androidx.wear.tiles.TimelineBuilders.Timeline) {
+ fun doCheck(timeline: TimelineBuilders.Timeline) {
timeline.timelineEntries.forEach { entry ->
entryCheckers.forEach {
try {
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/client/TileClient.java b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/client/TileClient.java
index 0c58a7b..bb730a1 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/client/TileClient.java
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/client/TileClient.java
@@ -16,15 +16,17 @@
package androidx.wear.tiles.client;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+
import androidx.annotation.NonNull;
+import androidx.wear.protolayout.ResourceBuilders;
import androidx.wear.tiles.RequestBuilders;
import androidx.wear.tiles.TileBuilders;
+import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.ListenableFuture;
-/**
- * Client to connect and interact with a TileService.
- */
+/** Client to connect and interact with a TileService. */
public interface TileClient {
/** Gets the API version supported by the connected TileService. */
@NonNull
@@ -37,7 +39,22 @@
/** Request a resource bundle from the connected TileService. */
@NonNull
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
+ @SuppressWarnings("deprecation") // For backward compatibility
+ default ListenableFuture<ResourceBuilders.Resources> requestTileResourcesAsync(
+ @NonNull RequestBuilders.ResourcesRequest requestParams) {
+ return FluentFuture.from(requestResources(requestParams))
+ .transform(
+ res -> ResourceBuilders.Resources.fromProto(res.toProto()),
+ directExecutor());
+ }
+
+ /**
+ * Request a resource bundle from the connected TileService.
+ *
+ * @deprecated Use {@link #requestTileResourcesAsync(RequestBuilders.ResourcesRequest)} instead.
+ */
+ @NonNull
+ @Deprecated
ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> requestResources(
@NonNull RequestBuilders.ResourcesRequest requestParams);
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/connection/DefaultTileClient.kt b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/connection/DefaultTileClient.kt
index 324056c..6fad649 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/connection/DefaultTileClient.kt
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/connection/DefaultTileClient.kt
@@ -20,6 +20,7 @@
import android.content.Context
import androidx.annotation.VisibleForTesting
import androidx.concurrent.futures.ResolvableFuture
+import androidx.wear.protolayout.ResourceBuilders
import androidx.wear.protolayout.proto.ResourceProto
import androidx.wear.protolayout.protobuf.InvalidProtocolBufferException
import androidx.wear.tiles.EventBuilders
@@ -39,8 +40,9 @@
import androidx.wear.tiles.TileService
import androidx.wear.tiles.client.TileClient
import androidx.wear.tiles.proto.TileProto
+import com.google.common.util.concurrent.FluentFuture
import com.google.common.util.concurrent.ListenableFuture
-import java.lang.IllegalArgumentException
+import com.google.common.util.concurrent.MoreExecutors
import java.util.concurrent.Executor
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
@@ -149,10 +151,9 @@
}
}
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
- public override fun requestResources(
+ public override fun requestTileResourcesAsync(
requestParams: RequestBuilders.ResourcesRequest
- ): ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> {
+ ): ListenableFuture<ResourceBuilders.Resources> {
return runForFuture {
val params = ResourcesRequestData(
requestParams.toProto().toByteArray(),
@@ -168,6 +169,22 @@
}
}
+ @Deprecated(
+ "Use requestTileResourcesAsync instead.",
+ replaceWith = ReplaceWith("requestTileResourcesAsync"))
+ @Suppress("deprecation")
+ public override fun requestResources(
+ requestParams: RequestBuilders.ResourcesRequest
+ ): ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> {
+ return FluentFuture.from(requestTileResourcesAsync(requestParams)).transform(
+ { res: ResourceBuilders.Resources ->
+ androidx.wear.tiles.ResourceBuilders.Resources.fromProto(
+ res.toProto()
+ )
+ }, MoreExecutors.directExecutor()
+ )
+ }
+
public override fun sendOnTileAddedEvent(): ListenableFuture<Void?> {
return runForFuture {
it.onTileAddEvent(TILE_ADD_EVENT)
@@ -226,9 +243,8 @@
}
}
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
private class ResourcesResultCallback(
- private val continuation: Continuation<androidx.wear.tiles.ResourceBuilders.Resources>
+ private val continuation: Continuation<ResourceBuilders.Resources>
) : ResourcesCallback.Stub() {
override fun updateResources(resourcesData: ResourcesData?) {
when {
@@ -249,7 +265,7 @@
try {
val resources = ResourceProto.Resources.parseFrom(resourcesData.contents)
continuation.resume(
- androidx.wear.tiles.ResourceBuilders.Resources.fromProto(resources))
+ ResourceBuilders.Resources.fromProto(resources))
} catch (ex: InvalidProtocolBufferException) {
continuation.resumeWithException(ex)
}
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/manager/TileUiClient.kt b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/manager/TileUiClient.kt
index c25eb30..5eff066 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/manager/TileUiClient.kt
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/manager/TileUiClient.kt
@@ -34,12 +34,14 @@
import androidx.wear.protolayout.LayoutElementBuilders
import androidx.wear.protolayout.ResourceBuilders
import androidx.wear.protolayout.StateBuilders
+import androidx.wear.protolayout.TimelineBuilders
import androidx.wear.tiles.RequestBuilders
import androidx.wear.tiles.checkers.TimelineChecker
import androidx.wear.tiles.connection.DefaultTileClient
import androidx.wear.tiles.renderer.TileRenderer
import androidx.wear.tiles.timeline.TilesTimelineManager
import java.util.concurrent.Executors
+import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -50,13 +52,13 @@
import kotlinx.coroutines.withContext
/**
- * UI client for a single tile. This handles binding to a Tile Service, and inflating the given
- * tile contents into the provided parentView. This also handles requested updates, re-fetching the
- * tile on-demand.
+ * UI client for a single tile. This handles binding to a Tile Service, and inflating the given tile
+ * contents into the provided parentView. This also handles requested updates, re-fetching the tile
+ * on-demand.
*
* After creation, you should call {@link #connect} to connect and start the initial fetch.
- * Likewise, when the owning activity is destroyed, you should call {@link #close} to disconnect
- * and release resources.
+ * Likewise, when the owning activity is destroyed, you should call {@link #close} to disconnect and
+ * release resources.
*/
public class TileUiClient(
private val context: Context,
@@ -72,27 +74,25 @@
private val coroutineScope = CoroutineScope(Dispatchers.Main + job)
private val timelineChecker = TimelineChecker()
- private val tilesConnection = DefaultTileClient(
- context = context,
- componentName = component,
- coroutineScope = coroutineScope,
- coroutineDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
- )
+ private val tilesConnection =
+ DefaultTileClient(
+ context = context,
+ componentName = component,
+ coroutineScope = coroutineScope,
+ coroutineDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher())
private var timelineManager: TilesTimelineManager? = null
-
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
private var tileResources: ResourceBuilders.Resources? = null
- private val updateScheduler = UpdateScheduler(
- context.getSystemService(AlarmManager::class.java),
- SystemClock::elapsedRealtime
- )
+ private val updateScheduler =
+ UpdateScheduler(
+ context.getSystemService(AlarmManager::class.java), SystemClock::elapsedRealtime)
- private val updateReceiver = object : BroadcastReceiver() {
- override fun onReceive(context: Context?, intent: Intent?) {
- updateScheduler.updateNow(false)
+ private val updateReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ updateScheduler.updateNow(false)
+ }
}
- }
private var isRunning = false
@@ -108,9 +108,7 @@
coroutineScope.launch { requestTile() }
updateScheduler.enableUpdates()
- updateScheduler.setUpdateReceiver {
- coroutineScope.launch { requestTile() }
- }
+ updateScheduler.setUpdateReceiver { coroutineScope.launch { requestTile() } }
registerBroadcastReceiver()
isRunning = true
@@ -135,50 +133,46 @@
isRunning = false
}
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
private suspend fun requestTile(
state: StateBuilders.State = StateBuilders.State.Builder().build()
) = coroutineScope {
withContext(Dispatchers.Main) {
- val tileRequest = RequestBuilders.TileRequest
- .Builder()
- .setCurrentState(state)
- .setDeviceConfiguration(buildDeviceParameters())
- .build()
+ val tileRequest =
+ RequestBuilders.TileRequest.Builder()
+ .setCurrentState(state)
+ .setDeviceConfiguration(buildDeviceParameters())
+ .build()
val tile = tilesConnection.requestTile(tileRequest).await()
if (tile.resourcesVersion.isEmpty()) {
tileResources = ResourceBuilders.Resources.Builder().build()
} else if (tile.resourcesVersion != tileResources?.version) {
- val resourcesRequest = RequestBuilders.ResourcesRequest
- .Builder()
- .setVersion(tile.resourcesVersion)
- .setDeviceConfiguration(buildDeviceParameters())
- .build()
+ val resourcesRequest =
+ RequestBuilders.ResourcesRequest.Builder()
+ .setVersion(tile.resourcesVersion)
+ .setDeviceConfiguration(buildDeviceParameters())
+ .build()
- tileResources = ResourceBuilders.Resources.fromProto(
- tilesConnection.requestResources(resourcesRequest).await().toProto()
- )
+ tileResources = tilesConnection.requestTileResourcesAsync(resourcesRequest).await()
}
- timelineManager?.apply {
- close()
- }
+ timelineManager?.apply { close() }
// Check the tile and raise any validation errors.
- if (tile.timeline != null) {
- timelineChecker.doCheck(tile.timeline!!)
+ if (tile.tileTimeline != null) {
+ timelineChecker.doCheck(tile.tileTimeline!!)
}
- val localTimelineManager = TilesTimelineManager(
- context.getSystemService(AlarmManager::class.java),
- System::currentTimeMillis,
- tile.timeline ?: androidx.wear.tiles.TimelineBuilders.Timeline.Builder().build(),
- 0,
- ContextCompat.getMainExecutor(context),
- { _, layout -> updateContents(layout) }
- )
+ val localTimelineManager =
+ TilesTimelineManager(
+ context.getSystemService(AlarmManager::class.java),
+ System::currentTimeMillis,
+ tile.tileTimeline ?: TimelineBuilders.Timeline.Builder().build(),
+ 0,
+ ContextCompat.getMainExecutor(context)) { _, layout ->
+ coroutineScope.launch { updateContents(layout) }
+ }
timelineManager = localTimelineManager
val freshnessInterval = tile.freshnessIntervalMillis
@@ -193,24 +187,17 @@
}
}
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
- private fun updateContents(layout: androidx.wear.tiles.LayoutElementBuilders.Layout) {
+ private suspend fun updateContents(layout: LayoutElementBuilders.Layout) {
parentView.removeAllViews()
- val renderer = TileRenderer(
- context,
- ContextCompat.getMainExecutor(context),
- { state -> coroutineScope.launch { requestTile(state) } }
- )
- val result = renderer.inflateAsync(
- LayoutElementBuilders.Layout.fromProto(layout.toProto()),
- tileResources!!,
- parentView
- )
- result.addListener(
- { (result.get().layoutParams as FrameLayout.LayoutParams).gravity = Gravity.CENTER },
- ContextCompat.getMainExecutor(context)
- )
+ val renderer =
+ TileRenderer(context, ContextCompat.getMainExecutor(context)) { state ->
+ coroutineScope.launch { requestTile(state) }
+ }
+
+ renderer.inflateAsync(layout, tileResources!!, parentView).await()?.apply {
+ (layoutParams as FrameLayout.LayoutParams).gravity = Gravity.CENTER
+ }
}
private fun registerBroadcastReceiver() {
@@ -222,13 +209,12 @@
val displayMetrics: DisplayMetrics = context.resources.displayMetrics
val isScreenRound: Boolean = context.resources.configuration.isScreenRound
return DeviceParametersBuilders.DeviceParameters.Builder()
- .setScreenWidthDp(Math.round(displayMetrics.widthPixels / displayMetrics.density))
- .setScreenHeightDp(Math.round(displayMetrics.heightPixels / displayMetrics.density))
+ .setScreenWidthDp((displayMetrics.widthPixels / displayMetrics.density).roundToInt())
+ .setScreenHeightDp((displayMetrics.heightPixels / displayMetrics.density).roundToInt())
.setScreenDensity(displayMetrics.density)
.setScreenShape(
if (isScreenRound) DeviceParametersBuilders.SCREEN_SHAPE_ROUND
- else DeviceParametersBuilders.SCREEN_SHAPE_RECT
- )
+ else DeviceParametersBuilders.SCREEN_SHAPE_RECT)
.setDevicePlatform(DeviceParametersBuilders.DEVICE_PLATFORM_WEAR_OS)
.build()
}
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java
index 3fb2267..df588c4 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java
@@ -28,10 +28,13 @@
import androidx.wear.protolayout.LayoutElementBuilders;
import androidx.wear.protolayout.ResourceBuilders;
import androidx.wear.protolayout.StateBuilders;
+import androidx.wear.protolayout.expression.AppDataKey;
+import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
import androidx.wear.protolayout.expression.pipeline.StateStore;
import androidx.wear.protolayout.proto.LayoutElementProto;
import androidx.wear.protolayout.proto.ResourceProto;
import androidx.wear.protolayout.renderer.impl.ProtoLayoutViewInstance;
+import androidx.wear.protolayout.renderer.inflater.ProtoLayoutThemeImpl;
import androidx.wear.tiles.TileService;
import com.google.common.collect.ImmutableMap;
@@ -40,6 +43,7 @@
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
+import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -75,6 +79,7 @@
@Nullable private final LayoutElementProto.Layout mLayout;
@Nullable private final ResourceProto.Resources mResources;
@NonNull private final ListeningExecutorService mUiExecutor;
+ @NonNull private final StateStore mStateStore = new StateStore(ImmutableMap.of());
/**
* Default constructor.
@@ -97,6 +102,7 @@
@NonNull LoadActionListener loadActionListener) {
this(
uiContext,
+ /* tilesTheme= */ 0,
loadActionExecutor,
toStateConsumer(loadActionListener),
layout.toProto(),
@@ -125,9 +131,9 @@
@NonNull androidx.wear.tiles.ResourceBuilders.Resources resources,
@NonNull Executor loadActionExecutor,
@NonNull LoadActionListener loadActionListener) {
- // TODO(b/272527869): Enable setting theme.
this(
uiContext,
+ tilesTheme,
loadActionExecutor,
toStateConsumer(loadActionListener),
layout.toProto(),
@@ -145,6 +151,7 @@
@NonNull Consumer<StateBuilders.State> loadActionListener) {
this(
uiContext,
+ /* tilesTheme= */ 0,
loadActionExecutor,
loadActionListener,
/* layout= */ null,
@@ -153,10 +160,12 @@
private TileRenderer(
@NonNull Context uiContext,
+ @StyleRes int tilesTheme,
@NonNull Executor loadActionExecutor,
@NonNull Consumer<StateBuilders.State> loadActionListener,
@Nullable LayoutElementProto.Layout layout,
@Nullable ResourceProto.Resources resources) {
+
this.mLayout = layout;
this.mResources = resources;
this.mUiExecutor = MoreExecutors.newDirectExecutorService();
@@ -172,13 +181,16 @@
uiContext, mUiExecutor, mUiExecutor, TileService.EXTRA_CLICKABLE_ID)
.setAnimationEnabled(true)
.setIsViewFullyVisible(true)
- .setStateStore(new StateStore(ImmutableMap.of()))
+ .setStateStore(mStateStore)
.setLoadActionListener(instanceListener);
+ if (tilesTheme != 0) {
+ config.setProtoLayoutTheme(new ProtoLayoutThemeImpl(uiContext, tilesTheme));
+ }
this.mInstance = new ProtoLayoutViewInstance(config.build());
}
@NonNull
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
+ @SuppressWarnings("deprecation") // For backward compatibility
private static Consumer<StateBuilders.State> toStateConsumer(
@NonNull LoadActionListener loadActionListener) {
return nextState ->
@@ -220,6 +232,20 @@
}
/**
+ * Sets the state for the current (and future) layouts. This is equivalent to setting the tile
+ * state via {@link StateBuilders.State.Builder#addKeyToValueMapping(AppDataKey,
+ * DynamicDataValue)}
+ *
+ * @param newState the state to use for the current layout (and any future layouts). This value
+ * will replace any previously set state.
+ * @throws IllegalStateException if number of {@code newState} entries is greater than {@link
+ * StateStore#getMaxStateEntryCount()}.
+ */
+ public void setState(@NonNull Map<AppDataKey<?>, DynamicDataValue> newState) {
+ mStateStore.setAppStateEntryValues(newState);
+ }
+
+ /**
* Inflates a Tile into {@code parent}.
*
* @param layout The portion of the Tile to render.
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/timeline/TilesTimelineCache.java b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/timeline/TilesTimelineCache.java
index af5fcb2..edfd08b 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/timeline/TilesTimelineCache.java
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/timeline/TilesTimelineCache.java
@@ -19,6 +19,7 @@
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.wear.protolayout.TimelineBuilders;
import androidx.wear.protolayout.proto.TimelineProto.TimelineEntry;
import androidx.wear.tiles.timeline.internal.TilesTimelineCacheInternal;
@@ -29,11 +30,46 @@
public final class TilesTimelineCache {
private final TilesTimelineCacheInternal mCache;
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
+ /**
+ * Default constructor.
+ *
+ * @deprecated Use {@link #TilesTimelineCache(TimelineBuilders.Timeline)} instead.
+ */
+ @Deprecated
public TilesTimelineCache(@NonNull androidx.wear.tiles.TimelineBuilders.Timeline timeline) {
mCache = new TilesTimelineCacheInternal(timeline.toProto());
}
+ /** Default constructor. */
+ public TilesTimelineCache(@NonNull TimelineBuilders.Timeline timeline) {
+ mCache = new TilesTimelineCacheInternal(timeline.toProto());
+ }
+
+ /**
+ * Finds the entry which should be active at the given time. This will return the entry which
+ * has the _shortest_ validity period at the current time, if validity periods overlap. Note
+ * that an entry which has no validity period set will be considered a "default" and will be
+ * used if no other entries are suitable.
+ *
+ * @param timeMillis The time to base the search on, in milliseconds.
+ * @return The timeline entry which should be active at the given time. Returns {@code null} if
+ * none are valid.
+ * @deprecated Use {@link #findTileTimelineEntryForTime(long)} instead.
+ */
+ @Deprecated
+ @MainThread
+ @Nullable
+ public androidx.wear.tiles.TimelineBuilders.TimelineEntry findTimelineEntryForTime(
+ long timeMillis) {
+ TimelineEntry entry = mCache.findTimelineEntryForTime(timeMillis);
+
+ if (entry == null) {
+ return null;
+ }
+
+ return androidx.wear.tiles.TimelineBuilders.TimelineEntry.fromProto(entry);
+ }
+
/**
* Finds the entry which should be active at the given time. This will return the entry which
* has the _shortest_ validity period at the current time, if validity periods overlap. Note
@@ -46,15 +82,41 @@
*/
@MainThread
@Nullable
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
- public androidx.wear.tiles.TimelineBuilders.TimelineEntry findTimelineEntryForTime(
- long timeMillis) {
+ public TimelineBuilders.TimelineEntry findTileTimelineEntryForTime(long timeMillis) {
TimelineEntry entry = mCache.findTimelineEntryForTime(timeMillis);
if (entry == null) {
return null;
}
+ return TimelineBuilders.TimelineEntry.fromProto(entry);
+ }
+
+ /**
+ * A (very) inexact version of {@link TilesTimelineCache#findTimelineEntryForTime(long)} which
+ * finds the closest timeline entry to the current time, regardless of validity. This should
+ * only used as a fallback if {@code findTimelineEntryForTime} fails, so it can attempt to at
+ * least show something.
+ *
+ * <p>By this point, we're technically in an error state, so just show _something_. Note that
+ * calling this if {@code findTimelineEntryForTime} returns a valid entry is invalid, and may
+ * lead to incorrect results.
+ *
+ * @param timeMillis The time to search from, in milliseconds.
+ * @return The timeline entry with validity period closest to {@code timeMillis}.
+ * @deprecated Use {@link #findClosestTileTimelineEntry(long)} instead.
+ */
+ @MainThread
+ @Nullable
+ @Deprecated
+ public androidx.wear.tiles.TimelineBuilders.TimelineEntry findClosestTimelineEntry(
+ long timeMillis) {
+ TimelineEntry entry = mCache.findClosestTimelineEntry(timeMillis);
+
+ if (entry == null) {
+ return null;
+ }
+
return androidx.wear.tiles.TimelineBuilders.TimelineEntry.fromProto(entry);
}
@@ -73,16 +135,35 @@
*/
@MainThread
@Nullable
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
- public androidx.wear.tiles.TimelineBuilders.TimelineEntry findClosestTimelineEntry(
- long timeMillis) {
+ public TimelineBuilders.TimelineEntry findClosestTileTimelineEntry(long timeMillis) {
TimelineEntry entry = mCache.findClosestTimelineEntry(timeMillis);
if (entry == null) {
return null;
}
- return androidx.wear.tiles.TimelineBuilders.TimelineEntry.fromProto(entry);
+ return TimelineBuilders.TimelineEntry.fromProto(entry);
+ }
+
+ /**
+ * Finds when the timeline entry {@code entry} should be considered "expired". This is either
+ * when it is no longer valid (i.e. end_millis), or when another entry should be presented
+ * instead.
+ *
+ * @param entry The entry to find the expiry time of.
+ * @param fromTimeMillis The time to start searching from. The returned time will never be lower
+ * than the value passed here.
+ * @return The time in millis that {@code entry} should be considered to be expired. This value
+ * will be {@link Long#MAX_VALUE} if {@code entry} does not expire.
+ * @deprecated Use {@link #findCurrentTimelineEntryExpiry(TimelineBuilders.TimelineEntry, long)}
+ * instead.
+ */
+ @Deprecated
+ @MainThread
+ public long findCurrentTimelineEntryExpiry(
+ @NonNull androidx.wear.tiles.TimelineBuilders.TimelineEntry entry,
+ long fromTimeMillis) {
+ return mCache.findCurrentTimelineEntryExpiry(entry.toProto(), fromTimeMillis);
}
/**
@@ -97,10 +178,8 @@
* will be {@link Long#MAX_VALUE} if {@code entry} does not expire.
*/
@MainThread
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public long findCurrentTimelineEntryExpiry(
- @NonNull androidx.wear.tiles.TimelineBuilders.TimelineEntry entry,
- long fromTimeMillis) {
+ @NonNull TimelineBuilders.TimelineEntry entry, long fromTimeMillis) {
return mCache.findCurrentTimelineEntryExpiry(entry.toProto(), fromTimeMillis);
}
}
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/timeline/TilesTimelineManager.java b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/timeline/TilesTimelineManager.java
index a9a4c6d..d3ad277 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/timeline/TilesTimelineManager.java
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/timeline/TilesTimelineManager.java
@@ -20,6 +20,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import androidx.wear.protolayout.LayoutElementBuilders;
+import androidx.wear.protolayout.TimelineBuilders;
import androidx.wear.tiles.timeline.internal.TilesTimelineManagerInternal;
import java.util.concurrent.Executor;
@@ -41,7 +43,12 @@
long getCurrentTimeMillis();
}
- /** Type to listen for layout updates from a given timeline. */
+ /**
+ * Type to listen for layout updates from a given timeline.
+ *
+ * @deprecated Use {@link LayoutUpdateListener} instead.
+ */
+ @Deprecated
public interface Listener {
/**
@@ -49,12 +56,26 @@
*
* @param token The token originally passed to {@link TilesTimelineManager}.
* @param layout The new layout to use.
+ * @deprecated Use {@link LayoutUpdateListener#onLayoutUpdate(int,
+ * LayoutElementBuilders.Layout)} instead.
*/
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
+ @Deprecated
void onLayoutUpdate(
int token, @NonNull androidx.wear.tiles.LayoutElementBuilders.Layout layout);
}
+ /** Type to listen for layout updates from a given timeline. */
+ public interface LayoutUpdateListener {
+
+ /**
+ * Called when a timeline has a new layout to be displayed.
+ *
+ * @param token The token originally passed to {@link TilesTimelineManager}.
+ * @param layout The new layout to use.
+ */
+ void onLayoutUpdate(int token, @NonNull LayoutElementBuilders.Layout layout);
+ }
+
private final TilesTimelineManagerInternal mManager;
/**
@@ -65,9 +86,13 @@
* This should be synchronized to the same clock as used by {@code alarmManager}
* @param timeline The Tiles timeline to use.
* @param token A token, which will be passed to {@code listener}'s callback.
+ * @param listenerExecutor the executor for {@code listener}
* @param listener A listener instance, called when a new timeline entry is available.
+ * @deprecated Use {@link
+ * #TilesTimelineManager(AlarmManager,Clock,TimelineBuilders.Timeline,int,Executor,LayoutUpdateListener)}
+ * instead.
*/
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
+ @Deprecated
public TilesTimelineManager(
@NonNull AlarmManager alarmManager,
@NonNull Clock clock,
@@ -78,7 +103,7 @@
mManager =
new TilesTimelineManagerInternal(
alarmManager,
- () -> clock.getCurrentTimeMillis(),
+ clock::getCurrentTimeMillis,
timeline.toProto(),
token,
listenerExecutor,
@@ -90,6 +115,37 @@
}
/**
+ * Default constructor.
+ *
+ * @param alarmManager An AlarmManager instance suitable for setting RTC alarms on.
+ * @param clock A Clock to use to ascertain the current time (and hence which tile to show).
+ * This should be synchronized to the same clock as used by {@code alarmManager}
+ * @param timeline The Tiles timeline to use.
+ * @param token A token, which will be passed to {@code listener}'s callback.
+ * @param listenerExecutor the executor for {@code listener}
+ * @param listener A listener instance, called when a new timeline entry is available.
+ */
+ public TilesTimelineManager(
+ @NonNull AlarmManager alarmManager,
+ @NonNull Clock clock,
+ @NonNull TimelineBuilders.Timeline timeline,
+ int token,
+ @NonNull Executor listenerExecutor,
+ @NonNull LayoutUpdateListener listener) {
+ mManager =
+ new TilesTimelineManagerInternal(
+ alarmManager,
+ clock::getCurrentTimeMillis,
+ timeline.toProto(),
+ token,
+ listenerExecutor,
+ (t, entry) ->
+ listener.onLayoutUpdate(
+ t,
+ LayoutElementBuilders.Layout.fromProto(entry.getLayout())));
+ }
+
+ /**
* Sets up this Timeline Manager. This will cause the timeline manager to dispatch the first
* layout, and set its first alarm.
*/
diff --git a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/checkers/CheckAccessibilityAvailableTest.kt b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/checkers/CheckAccessibilityAvailableTest.kt
index 525529e..10c8080 100644
--- a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/checkers/CheckAccessibilityAvailableTest.kt
+++ b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/checkers/CheckAccessibilityAvailableTest.kt
@@ -16,6 +16,9 @@
package androidx.wear.tiles.checkers
+import androidx.wear.protolayout.LayoutElementBuilders
+import androidx.wear.protolayout.ModifiersBuilders
+import androidx.wear.protolayout.TimelineBuilders
import androidx.wear.tiles.TilesTestRunner
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -24,10 +27,9 @@
@RunWith(TilesTestRunner::class)
class CheckAccessibilityAvailableTest {
@Test
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
fun check_throwsWithNoSemantics() {
val entry = buildTimelineEntry(
- androidx.wear.tiles.LayoutElementBuilders.Box.Builder().build())
+ LayoutElementBuilders.Box.Builder().build())
var exception: CheckerException? = null
@@ -41,15 +43,14 @@
}
@Test
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
fun check_doesntThrowIfSemanticsPresent() {
val entry =
buildTimelineEntry(
- androidx.wear.tiles.LayoutElementBuilders.Box.Builder()
+ LayoutElementBuilders.Box.Builder()
.setModifiers(
- androidx.wear.tiles.ModifiersBuilders.Modifiers.Builder()
+ ModifiersBuilders.Modifiers.Builder()
.setSemantics(
- androidx.wear.tiles.ModifiersBuilders.Semantics.Builder()
+ ModifiersBuilders.Semantics.Builder()
.setContentDescription("Hello World")
.build()
)
@@ -70,17 +71,16 @@
}
@Test
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
fun check_doesntThrowIfSemanticsPresentOnNestedElement() {
val entry =
buildTimelineEntry(
- androidx.wear.tiles.LayoutElementBuilders.Box.Builder()
+ LayoutElementBuilders.Box.Builder()
.addContent(
- androidx.wear.tiles.LayoutElementBuilders.Box.Builder()
+ LayoutElementBuilders.Box.Builder()
.setModifiers(
- androidx.wear.tiles.ModifiersBuilders.Modifiers.Builder()
+ ModifiersBuilders.Modifiers.Builder()
.setSemantics(
- androidx.wear.tiles.ModifiersBuilders.Semantics.Builder()
+ ModifiersBuilders.Semantics.Builder()
.setContentDescription("Hello World")
.build()
)
@@ -102,13 +102,12 @@
assertThat(exception).isNull()
}
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
private fun buildTimelineEntry(
- layout: androidx.wear.tiles.LayoutElementBuilders.LayoutElement
+ layout: LayoutElementBuilders.LayoutElement
) =
- androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry.Builder()
.setLayout(
- androidx.wear.tiles.LayoutElementBuilders.Layout.Builder().setRoot(layout).build()
+ LayoutElementBuilders.Layout.Builder().setRoot(layout).build()
)
.build()
}
diff --git a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/checkers/TimelineCheckerTest.kt b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/checkers/TimelineCheckerTest.kt
index 4222ae5..b91d8275 100644
--- a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/checkers/TimelineCheckerTest.kt
+++ b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/checkers/TimelineCheckerTest.kt
@@ -16,6 +16,8 @@
package androidx.wear.tiles.checkers
+import androidx.wear.protolayout.LayoutElementBuilders
+import androidx.wear.protolayout.TimelineBuilders
import androidx.wear.tiles.TilesTestRunner
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -30,7 +32,6 @@
@RunWith(TilesTestRunner::class)
class TimelineCheckerTest {
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
@Test
fun doCheck_callsAllCheckersOnSuccess() {
val mockChecker1 = mock<TimelineEntryChecker> {
@@ -45,14 +46,14 @@
val timeline = buildTimeline()
checker.doCheck(timeline)
- argumentCaptor<androidx.wear.tiles.TimelineBuilders.TimelineEntry>().apply {
+ argumentCaptor<TimelineBuilders.TimelineEntry>().apply {
verify(mockChecker1, times(2)).check(capture())
assertThat(firstValue.toProto()).isEqualTo(timeline.timelineEntries[0].toProto())
assertThat(secondValue.toProto()).isEqualTo(timeline.timelineEntries[1].toProto())
}
- argumentCaptor<androidx.wear.tiles.TimelineBuilders.TimelineEntry>().apply {
+ argumentCaptor<TimelineBuilders.TimelineEntry>().apply {
verify(mockChecker2, times(2)).check(capture())
assertThat(firstValue.toProto()).isEqualTo(timeline.timelineEntries[0].toProto())
@@ -60,7 +61,6 @@
}
}
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
@Test
fun doCheck_callsAllCheckersOnFailure() {
val mockChecker1 = mock<TimelineEntryChecker> {
@@ -78,14 +78,14 @@
checker.doCheck(timeline)
// Even on failure, it should still work through everything...
- argumentCaptor<androidx.wear.tiles.TimelineBuilders.TimelineEntry>().apply {
+ argumentCaptor<TimelineBuilders.TimelineEntry>().apply {
verify(mockChecker1, times(2)).check(capture())
assertThat(firstValue.toProto()).isEqualTo(timeline.timelineEntries[0].toProto())
assertThat(secondValue.toProto()).isEqualTo(timeline.timelineEntries[1].toProto())
}
- argumentCaptor<androidx.wear.tiles.TimelineBuilders.TimelineEntry>().apply {
+ argumentCaptor<TimelineBuilders.TimelineEntry>().apply {
verify(mockChecker2, times(2)).check(capture())
assertThat(firstValue.toProto()).isEqualTo(timeline.timelineEntries[0].toProto())
@@ -93,20 +93,19 @@
}
}
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
private fun buildTimeline() =
- androidx.wear.tiles.TimelineBuilders.Timeline.Builder().addTimelineEntry(
- androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder().setLayout(
- androidx.wear.tiles.LayoutElementBuilders.Layout.Builder().setRoot(
- androidx.wear.tiles.LayoutElementBuilders.Text.Builder()
+ TimelineBuilders.Timeline.Builder().addTimelineEntry(
+ TimelineBuilders.TimelineEntry.Builder().setLayout(
+ LayoutElementBuilders.Layout.Builder().setRoot(
+ LayoutElementBuilders.Text.Builder()
.setText("Hello")
.build()
).build()
).build()
).addTimelineEntry(
- androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder().setLayout(
- androidx.wear.tiles.LayoutElementBuilders.Layout.Builder().setRoot(
- androidx.wear.tiles.LayoutElementBuilders.Text.Builder()
+ TimelineBuilders.TimelineEntry.Builder().setLayout(
+ LayoutElementBuilders.Layout.Builder().setRoot(
+ LayoutElementBuilders.Text.Builder()
.setText("World")
.build()
).build()
diff --git a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/connection/DefaultTileClientTest.kt b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/connection/DefaultTileClientTest.kt
index 7e800c9..67aa9ea 100644
--- a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/connection/DefaultTileClientTest.kt
+++ b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/connection/DefaultTileClientTest.kt
@@ -22,6 +22,7 @@
import android.os.Looper
import androidx.concurrent.futures.await
import androidx.test.core.app.ApplicationProvider
+import androidx.wear.protolayout.ResourceBuilders
import androidx.wear.protolayout.protobuf.InvalidProtocolBufferException
import androidx.wear.tiles.RequestBuilders
import androidx.wear.tiles.ResourcesCallback
@@ -175,15 +176,14 @@
}
@Test
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
public fun getResources_canGetResources(): Unit = fakeCoroutineScope.runTest {
- val expectedResources = androidx.wear.tiles.ResourceBuilders.Resources.Builder()
+ val expectedResources = ResourceBuilders.Resources.Builder()
.setVersion("5")
.build()
fakeTileService.returnResources = expectedResources.toProto().toByteArray()
val result = async {
- clientUnderTest.requestResources(
+ clientUnderTest.requestTileResourcesAsync(
RequestBuilders.ResourcesRequest.Builder().build()
).await()
}
@@ -197,7 +197,7 @@
fakeTileService.returnResources = byteArrayOf(127)
val result = async(Job()) {
- clientUnderTest.requestResources(
+ clientUnderTest.requestTileResourcesAsync(
RequestBuilders.ResourcesRequest.Builder().build()
).await()
}
@@ -210,16 +210,15 @@
}
@Test
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
public fun getResources_failsIfVersionMismatch(): Unit = fakeCoroutineScope.runTest {
- val expectedResources = androidx.wear.tiles.ResourceBuilders.Resources.Builder()
+ val expectedResources = ResourceBuilders.Resources.Builder()
.setVersion("5")
.build()
fakeTileService.returnResources = expectedResources.toProto().toByteArray()
fakeTileService.returnResourcesVersion = -2
val result = async(Job()) {
- clientUnderTest.requestResources(
+ clientUnderTest.requestTileResourcesAsync(
RequestBuilders.ResourcesRequest.Builder().build()
).await()
}
@@ -231,9 +230,8 @@
}
@Test
- @Suppress("deprecation") // TODO(b/276343540): Use protolayout types
public fun getResources_failsOnTimeout(): Unit = runTest {
- val expectedResources = androidx.wear.tiles.ResourceBuilders.Resources.Builder()
+ val expectedResources = ResourceBuilders.Resources.Builder()
.setVersion("5")
.build()
fakeTileService.returnResources = expectedResources.toProto().toByteArray()
@@ -247,7 +245,7 @@
// This has to be dispatched on the correct dispatcher, so we can fully control its timing.
val result = async(stdDispatcher + Job()) {
- clientUnderTest.requestResources(
+ clientUnderTest.requestTileResourcesAsync(
RequestBuilders.ResourcesRequest.Builder().build()
).await()
}
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/TilesTimelineCacheTest.java b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/timeline/TilesTimelineCacheTest.java
index 25d6f1f..e7a1782 100644
--- a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/timeline/TilesTimelineCacheTest.java
+++ b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/timeline/TilesTimelineCacheTest.java
@@ -19,6 +19,8 @@
import static com.google.common.truth.Truth.assertThat;
import androidx.annotation.Nullable;
+import androidx.wear.protolayout.LayoutElementBuilders;
+import androidx.wear.protolayout.TimelineBuilders;
import androidx.wear.tiles.TilesTestRunner;
import com.google.common.truth.Expect;
@@ -36,25 +38,21 @@
@Rule public Expect expect = Expect.create();
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineCache_noValidityMakesDefaultTile() {
// Purposefully not setting a validity period.
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Hello World"))
.build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
- .addTimelineEntry(entry)
- .build();
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder().addTimelineEntry(entry).build();
TilesTimelineCache timelineCache = new TilesTimelineCache(timeline);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(0L), entry);
+ expectTimelineEntryEqual(timelineCache.findTileTimelineEntryForTime(0L), entry);
}
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineCache_nonOverlappingTilesShownAtCorrectTime() {
// Check for non-overlapping time slots (i.e. pure sequential), for example:
// +-------------------+------------------+
@@ -67,58 +65,57 @@
// +-------------------+------------------+
final long cutoverMillis = Duration.ofMinutes(10).toMillis();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry1 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry1 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Tile1"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(0)
.setEndMillis(cutoverMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry2 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry2 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Tile2"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(cutoverMillis)
.setEndMillis(Long.MAX_VALUE)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder()
.addTimelineEntry(entry1)
.addTimelineEntry(entry2)
.build();
TilesTimelineCache timelineCache = new TilesTimelineCache(timeline);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(0L), entry1);
+ expectTimelineEntryEqual(timelineCache.findTileTimelineEntryForTime(0L), entry1);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry1, 0L))
.isEqualTo(cutoverMillis);
// 1m before cutover
expectTimelineEntryEqual(
- timelineCache.findTimelineEntryForTime(
+ timelineCache.findTileTimelineEntryForTime(
cutoverMillis - Duration.ofMinutes(1).toMillis()),
entry1);
// Cutover
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(cutoverMillis), entry2);
+ expectTimelineEntryEqual(timelineCache.findTileTimelineEntryForTime(cutoverMillis), entry2);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry2, cutoverMillis))
.isEqualTo(Long.MAX_VALUE);
// 1m after
expectTimelineEntryEqual(
- timelineCache.findTimelineEntryForTime(
+ timelineCache.findTileTimelineEntryForTime(
cutoverMillis + Duration.ofMinutes(1).toMillis()),
entry2);
}
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineCache_overlappingEntryWithDefault() {
// Test that with a default, and an entry "on top", the entry is shown for its validity
// period, and the default for all other times. As an example
@@ -135,45 +132,45 @@
final long entry1StartMillis = Duration.ofMinutes(10).toMillis();
final long entry1EndMillis = entry1StartMillis + Duration.ofMinutes(10).toMillis();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry defaultEntry =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry defaultEntry =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("DefaultTile"))
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry1 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry1 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry1"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry1StartMillis)
.setEndMillis(entry1EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder()
.addTimelineEntry(entry1)
.addTimelineEntry(defaultEntry)
.build();
TilesTimelineCache timelineCache = new TilesTimelineCache(timeline);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(0L), defaultEntry);
+ expectTimelineEntryEqual(timelineCache.findTileTimelineEntryForTime(0L), defaultEntry);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(defaultEntry, 0L))
.isEqualTo(entry1StartMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry1StartMillis), entry1);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry1StartMillis), entry1);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry1, entry1StartMillis))
.isEqualTo(entry1EndMillis);
expectTimelineEntryEqual(
- timelineCache.findTimelineEntryForTime(entry1EndMillis), defaultEntry);
+ timelineCache.findTileTimelineEntryForTime(entry1EndMillis), defaultEntry);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(defaultEntry, entry1EndMillis))
.isEqualTo(Long.MAX_VALUE);
}
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineCache_testStackedEntries() {
// Do a test with "perfectly stacked" entries, for example
// +-------+
@@ -200,43 +197,43 @@
final long entry3EndMillis =
entry3StartMillis + Duration.ofMinutes(2).toMillis(); // Valid for 2 minutes
- androidx.wear.tiles.TimelineBuilders.TimelineEntry defaultEntry =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry defaultEntry =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("DefaultTile"))
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry1 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry1 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry1"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry1StartMillis)
.setEndMillis(entry1EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry2 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry2 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry2"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry2StartMillis)
.setEndMillis(entry2EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry3 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry3 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry3"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry3StartMillis)
.setEndMillis(entry3EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder()
.addTimelineEntry(defaultEntry)
.addTimelineEntry(entry1)
.addTimelineEntry(entry2)
@@ -245,38 +242,42 @@
TilesTimelineCache timelineCache = new TilesTimelineCache(timeline);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(0L), defaultEntry);
+ expectTimelineEntryEqual(timelineCache.findTileTimelineEntryForTime(0L), defaultEntry);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(defaultEntry, 0L))
.isEqualTo(entry1StartMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry1StartMillis), entry1);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry1StartMillis), entry1);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry1, entry1StartMillis))
.isEqualTo(entry2StartMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry2StartMillis), entry2);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry2StartMillis), entry2);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry2, entry2StartMillis))
.isEqualTo(entry3StartMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry3StartMillis), entry3);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry3StartMillis), entry3);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry3, entry3StartMillis))
.isEqualTo(entry3EndMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry3EndMillis), entry2);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry3EndMillis), entry2);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry2, entry3EndMillis))
.isEqualTo(entry2EndMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry2EndMillis), entry1);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry2EndMillis), entry1);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry1, entry2EndMillis))
.isEqualTo(entry1EndMillis);
expectTimelineEntryEqual(
- timelineCache.findTimelineEntryForTime(entry1EndMillis), defaultEntry);
+ timelineCache.findTileTimelineEntryForTime(entry1EndMillis), defaultEntry);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(defaultEntry, entry1EndMillis))
.isEqualTo(Long.MAX_VALUE);
}
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineCache_testStackedHangingEntries() {
// Test with "hanging" entries, for example
// +--------------+
@@ -303,43 +304,43 @@
final long entry3EndMillis =
entry3StartMillis + Duration.ofMinutes(4).toMillis(); // Valid for 4 minutes
- androidx.wear.tiles.TimelineBuilders.TimelineEntry defaultEntry =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry defaultEntry =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("DefaultTile"))
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry1 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry1 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry1"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry1StartMillis)
.setEndMillis(entry1EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry2 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry2 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry2"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry2StartMillis)
.setEndMillis(entry2EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry3 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry3 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry3"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry3StartMillis)
.setEndMillis(entry3EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder()
.addTimelineEntry(defaultEntry)
.addTimelineEntry(entry1)
.addTimelineEntry(entry2)
@@ -348,34 +349,37 @@
TilesTimelineCache timelineCache = new TilesTimelineCache(timeline);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(0L), defaultEntry);
+ expectTimelineEntryEqual(timelineCache.findTileTimelineEntryForTime(0L), defaultEntry);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(defaultEntry, 0L))
.isEqualTo(entry1StartMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry1StartMillis), entry1);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry1StartMillis), entry1);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry1, entry1StartMillis))
.isEqualTo(entry2StartMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry2StartMillis), entry2);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry2StartMillis), entry2);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry2, entry2StartMillis))
.isEqualTo(entry3StartMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry3StartMillis), entry3);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry3StartMillis), entry3);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry3, entry3StartMillis))
.isEqualTo(entry3EndMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry3EndMillis), entry1);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry3EndMillis), entry1);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry1, entry3EndMillis))
.isEqualTo(entry1EndMillis);
expectTimelineEntryEqual(
- timelineCache.findTimelineEntryForTime(entry1EndMillis), defaultEntry);
+ timelineCache.findTileTimelineEntryForTime(entry1EndMillis), defaultEntry);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(defaultEntry, entry1EndMillis))
.isEqualTo(Long.MAX_VALUE);
}
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineCache_stackedEntriesShortestAlwaysWins() {
// Test that if entries are stacked, the shortest entry always wins, not the "top". For
// example:
@@ -404,43 +408,43 @@
final long entry3EndMillis =
entry3StartMillis + Duration.ofMinutes(6).toMillis(); // Valid for 6 minutes
- androidx.wear.tiles.TimelineBuilders.TimelineEntry defaultEntry =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry defaultEntry =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("DefaultTile"))
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry1 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry1 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry1"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry1StartMillis)
.setEndMillis(entry1EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry2 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry2 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry2"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry2StartMillis)
.setEndMillis(entry2EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry3 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry3 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry3"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry3StartMillis)
.setEndMillis(entry3EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder()
.addTimelineEntry(defaultEntry)
.addTimelineEntry(entry1)
.addTimelineEntry(entry2)
@@ -449,41 +453,45 @@
TilesTimelineCache timelineCache = new TilesTimelineCache(timeline);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(0L), defaultEntry);
+ expectTimelineEntryEqual(timelineCache.findTileTimelineEntryForTime(0L), defaultEntry);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(defaultEntry, 0L))
.isEqualTo(entry1StartMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry1StartMillis), entry1);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry1StartMillis), entry1);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry1, entry1StartMillis))
.isEqualTo(entry2StartMillis);
// Ending time of entry2 should be entry2End, as it's always the shortest
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry2StartMillis), entry2);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry2StartMillis), entry2);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry2, entry2StartMillis))
.isEqualTo(entry2EndMillis);
// At entry3start, entry2 is still the shortest valid one.
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry3StartMillis), entry2);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry3StartMillis), entry2);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry2, entry3StartMillis))
.isEqualTo(entry2EndMillis);
// Should now switch to entry3
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry2EndMillis), entry3);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry2EndMillis), entry3);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry3, entry2EndMillis))
.isEqualTo(entry3EndMillis);
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(entry3EndMillis), entry1);
+ expectTimelineEntryEqual(
+ timelineCache.findTileTimelineEntryForTime(entry3EndMillis), entry1);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry1, entry3EndMillis))
.isEqualTo(entry1EndMillis);
expectTimelineEntryEqual(
- timelineCache.findTimelineEntryForTime(entry1EndMillis), defaultEntry);
+ timelineCache.findTileTimelineEntryForTime(entry1EndMillis), defaultEntry);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(defaultEntry, entry1EndMillis))
.isEqualTo(Long.MAX_VALUE);
}
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineCache_noValidTilePicksClosest() {
final long entry1StartMillis = Duration.ofMinutes(10).toMillis();
final long entry1EndMillis =
@@ -492,28 +500,28 @@
final long entry2EndMillis =
entry2StartMillis + Duration.ofMinutes(10).toMillis(); // 10 minutes
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry1 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry1 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry1"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry1StartMillis)
.setEndMillis(entry1EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry2 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry2 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Entry2"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(entry2StartMillis)
.setEndMillis(entry2EndMillis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder()
.addTimelineEntry(entry1)
.addTimelineEntry(entry2)
.build();
@@ -522,18 +530,18 @@
// This is really undefined behaviour at the moment, but, well, let's keep this as the
// assumed behaviour for now. Should just pick entry1 in this case.
- expectTimelineEntryEqual(timelineCache.findTimelineEntryForTime(0L), null);
- expectTimelineEntryEqual(timelineCache.findClosestTimelineEntry(0L), entry1);
+ expectTimelineEntryEqual(timelineCache.findTileTimelineEntryForTime(0L), null);
+ expectTimelineEntryEqual(timelineCache.findClosestTileTimelineEntry(0L), entry1);
expect.that(timelineCache.findCurrentTimelineEntryExpiry(entry1, 0L))
.isEqualTo(entry1EndMillis);
// And after the end, should pick entry2
expectTimelineEntryEqual(
- timelineCache.findTimelineEntryForTime(
+ timelineCache.findTileTimelineEntryForTime(
entry2EndMillis + Duration.ofMinutes(1).toMillis()),
null);
expectTimelineEntryEqual(
- timelineCache.findClosestTimelineEntry(
+ timelineCache.findClosestTileTimelineEntry(
entry2EndMillis + Duration.ofMinutes(1).toMillis()),
entry2);
@@ -543,10 +551,9 @@
.isEqualTo(Long.MAX_VALUE);
}
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
private void expectTimelineEntryEqual(
- @Nullable androidx.wear.tiles.TimelineBuilders.TimelineEntry actual,
- @Nullable androidx.wear.tiles.TimelineBuilders.TimelineEntry expected) {
+ @Nullable TimelineBuilders.TimelineEntry actual,
+ @Nullable TimelineBuilders.TimelineEntry expected) {
if (expected == null) {
expect.that(actual).isNull();
} else {
@@ -555,13 +562,9 @@
}
}
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
- private static androidx.wear.tiles.LayoutElementBuilders.Layout buildTextLayout(String text) {
- return new androidx.wear.tiles.LayoutElementBuilders.Layout.Builder()
- .setRoot(
- new androidx.wear.tiles.LayoutElementBuilders.Text.Builder()
- .setText(text)
- .build())
+ private static LayoutElementBuilders.Layout buildTextLayout(String text) {
+ return new LayoutElementBuilders.Layout.Builder()
+ .setRoot(new LayoutElementBuilders.Text.Builder().setText(text).build())
.build();
}
}
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 1d54d75..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
@@ -28,6 +28,8 @@
import android.content.Context;
import androidx.core.content.ContextCompat;
+import androidx.wear.protolayout.LayoutElementBuilders;
+import androidx.wear.protolayout.TimelineBuilders;
import androidx.wear.tiles.TilesTestRunner;
import com.google.common.truth.Expect;
@@ -81,18 +83,13 @@
}
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineManager_singleTileImmediatelySet() {
- List<androidx.wear.tiles.LayoutElementBuilders.Layout> returnedLayouts = new ArrayList<>();
- androidx.wear.tiles.LayoutElementBuilders.Layout layout = buildTextLayout("Hello World");
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
- .setLayout(layout)
- .build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
- .addTimelineEntry(entry)
- .build();
+ List<LayoutElementBuilders.Layout> returnedLayouts = new ArrayList<>();
+ LayoutElementBuilders.Layout layout = buildTextLayout("Hello World");
+ TimelineBuilders.TimelineEntry entry =
+ new TimelineBuilders.TimelineEntry.Builder().setLayout(layout).build();
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder().addTimelineEntry(entry).build();
mTimelineManager =
new TilesTimelineManager(
@@ -111,47 +108,46 @@
}
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineManager_tileWithRollover() {
- List<androidx.wear.tiles.LayoutElementBuilders.Layout> returnedLayouts = new ArrayList<>();
+ List<LayoutElementBuilders.Layout> returnedLayouts = new ArrayList<>();
final long cutover1Millis = mCurrentTime + Duration.ofMinutes(10).toMillis();
final long cutover2Millis = mCurrentTime + Duration.ofMinutes(20).toMillis();
- androidx.wear.tiles.LayoutElementBuilders.Layout layout1 = buildTextLayout("Tile1");
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry1 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ LayoutElementBuilders.Layout layout1 = buildTextLayout("Tile1");
+ TimelineBuilders.TimelineEntry entry1 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(layout1)
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(0)
.setEndMillis(cutover1Millis)
.build())
.build();
- androidx.wear.tiles.LayoutElementBuilders.Layout layout2 = buildTextLayout("Tile2");
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry2 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ LayoutElementBuilders.Layout layout2 = buildTextLayout("Tile2");
+ TimelineBuilders.TimelineEntry entry2 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(layout2)
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(cutover1Millis)
.setEndMillis(cutover2Millis)
.build())
.build();
- androidx.wear.tiles.LayoutElementBuilders.Layout layout3 = buildTextLayout("Tile3");
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry3 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ LayoutElementBuilders.Layout layout3 = buildTextLayout("Tile3");
+ TimelineBuilders.TimelineEntry entry3 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(layout3)
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(cutover2Millis)
.setEndMillis(Long.MAX_VALUE)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder()
.addTimelineEntry(entry1)
.addTimelineEntry(entry2)
.addTimelineEntry(entry3)
@@ -187,33 +183,32 @@
}
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineManager_alarmsCanceledOnDeInit() {
- List<androidx.wear.tiles.LayoutElementBuilders.Layout> returnedLayouts = new ArrayList<>();
+ List<LayoutElementBuilders.Layout> returnedLayouts = new ArrayList<>();
final long cutover1Millis = mCurrentTime + Duration.ofMinutes(10).toMillis();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry1 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry1 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Tile1"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(0)
.setEndMillis(cutover1Millis)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry2 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ TimelineBuilders.TimelineEntry entry2 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(buildTextLayout("Tile2"))
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(cutover1Millis)
.setEndMillis(Long.MAX_VALUE)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder()
.addTimelineEntry(entry1)
.addTimelineEntry(entry2)
.build();
@@ -236,37 +231,36 @@
}
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineManager_minDelayEnforced() {
- List<androidx.wear.tiles.LayoutElementBuilders.Layout> returnedLayouts = new ArrayList<>();
+ List<LayoutElementBuilders.Layout> returnedLayouts = new ArrayList<>();
final long cutover1Millis =
mCurrentTime + TilesTimelineManager.MIN_TILE_UPDATE_DELAY_MILLIS / 2;
- androidx.wear.tiles.LayoutElementBuilders.Layout layout1 = buildTextLayout("Tile1");
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry1 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ LayoutElementBuilders.Layout layout1 = buildTextLayout("Tile1");
+ TimelineBuilders.TimelineEntry entry1 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(layout1)
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(0)
.setEndMillis(cutover1Millis)
.build())
.build();
- androidx.wear.tiles.LayoutElementBuilders.Layout layout2 = buildTextLayout("Tile2");
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry2 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ LayoutElementBuilders.Layout layout2 = buildTextLayout("Tile2");
+ TimelineBuilders.TimelineEntry entry2 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(layout2)
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(cutover1Millis)
.setEndMillis(Long.MAX_VALUE)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder()
.addTimelineEntry(entry1)
.addTimelineEntry(entry2)
.build();
@@ -295,53 +289,52 @@
}
@Test
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
public void timelineManager_minDelayUsesCorrectEntry() {
// This has three entries, one initial one, one that happens after MIN_DELAY/2, and one that
// happens after MIN_DELAY. This should totally skip the middle entry, and only show the
// first and last entries.
- List<androidx.wear.tiles.LayoutElementBuilders.Layout> returnedLayouts = new ArrayList<>();
+ List<LayoutElementBuilders.Layout> returnedLayouts = new ArrayList<>();
final long cutover1Millis =
mCurrentTime + TilesTimelineManager.MIN_TILE_UPDATE_DELAY_MILLIS / 2;
final long cutover2Millis =
cutover1Millis + TilesTimelineManager.MIN_TILE_UPDATE_DELAY_MILLIS / 2;
- androidx.wear.tiles.LayoutElementBuilders.Layout layout1 = buildTextLayout("Tile1");
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry1 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ LayoutElementBuilders.Layout layout1 = buildTextLayout("Tile1");
+ TimelineBuilders.TimelineEntry entry1 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(layout1)
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(0)
.setEndMillis(cutover1Millis)
.build())
.build();
- androidx.wear.tiles.LayoutElementBuilders.Layout layout2 = buildTextLayout("Tile2");
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry2 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ LayoutElementBuilders.Layout layout2 = buildTextLayout("Tile2");
+ TimelineBuilders.TimelineEntry entry2 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(layout2)
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(cutover1Millis)
.setEndMillis(cutover2Millis)
.build())
.build();
- androidx.wear.tiles.LayoutElementBuilders.Layout layout3 = buildTextLayout("Tile3");
- androidx.wear.tiles.TimelineBuilders.TimelineEntry entry3 =
- new androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder()
+ LayoutElementBuilders.Layout layout3 = buildTextLayout("Tile3");
+ TimelineBuilders.TimelineEntry entry3 =
+ new TimelineBuilders.TimelineEntry.Builder()
.setLayout(layout3)
.setValidity(
- new androidx.wear.tiles.TimelineBuilders.TimeInterval.Builder()
+ new TimelineBuilders.TimeInterval.Builder()
.setStartMillis(cutover2Millis)
.setEndMillis(Long.MAX_VALUE)
.build())
.build();
- androidx.wear.tiles.TimelineBuilders.Timeline timeline =
- new androidx.wear.tiles.TimelineBuilders.Timeline.Builder()
+ TimelineBuilders.Timeline timeline =
+ new TimelineBuilders.Timeline.Builder()
.addTimelineEntry(entry1)
.addTimelineEntry(entry2)
.addTimelineEntry(entry3)
@@ -366,16 +359,13 @@
expectLayoutsEqual(returnedLayouts.get(1), layout3);
}
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
- private static androidx.wear.tiles.LayoutElementBuilders.Layout buildTextLayout(String text) {
- return new androidx.wear.tiles.LayoutElementBuilders.Layout.Builder()
- .setRoot(
- new androidx.wear.tiles.LayoutElementBuilders.Text.Builder()
- .setText(text)
- .build())
+ private static LayoutElementBuilders.Layout buildTextLayout(String text) {
+ return new LayoutElementBuilders.Layout.Builder()
+ .setRoot(new LayoutElementBuilders.Text.Builder().setText(text).build())
.build();
}
+ @SuppressWarnings("deprecation") // ScheduledAlarm usage, see b/284981234
private void seekToTime(long timeMillis) {
ShadowAlarmManager shadowAlarmManager = shadowOf(mAlarmManager);
@@ -399,10 +389,8 @@
expect.that(shadowAlarmManager.getScheduledAlarms()).isEmpty();
}
- @SuppressWarnings("deprecation") // TODO(b/276343540): Use protolayout types
private void expectLayoutsEqual(
- androidx.wear.tiles.LayoutElementBuilders.Layout actual,
- androidx.wear.tiles.LayoutElementBuilders.Layout expected) {
+ LayoutElementBuilders.Layout actual, LayoutElementBuilders.Layout expected) {
expect.that(actual.toProto()).isEqualTo(expected.toProto());
}
}
diff --git a/wear/tiles/tiles-testing/api/current.txt b/wear/tiles/tiles-testing/api/current.txt
index 07ee6fd..17cae9a 100644
--- a/wear/tiles/tiles-testing/api/current.txt
+++ b/wear/tiles/tiles-testing/api/current.txt
@@ -5,7 +5,7 @@
ctor public TestTileClient(T service, java.util.concurrent.Executor executor);
ctor public TestTileClient(T service, kotlinx.coroutines.CoroutineScope coroutineScope, kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer> requestApiVersion();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest requestParams);
+ method @Deprecated public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest requestParams);
method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.TileBuilders.Tile> requestTile(androidx.wear.tiles.RequestBuilders.TileRequest requestParams);
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> sendOnTileAddedEvent();
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> sendOnTileEnterEvent();
diff --git a/wear/tiles/tiles-testing/api/restricted_current.txt b/wear/tiles/tiles-testing/api/restricted_current.txt
index 07ee6fd..17cae9a 100644
--- a/wear/tiles/tiles-testing/api/restricted_current.txt
+++ b/wear/tiles/tiles-testing/api/restricted_current.txt
@@ -5,7 +5,7 @@
ctor public TestTileClient(T service, java.util.concurrent.Executor executor);
ctor public TestTileClient(T service, kotlinx.coroutines.CoroutineScope coroutineScope, kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer> requestApiVersion();
- method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest requestParams);
+ method @Deprecated public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> requestResources(androidx.wear.tiles.RequestBuilders.ResourcesRequest requestParams);
method public com.google.common.util.concurrent.ListenableFuture<androidx.wear.tiles.TileBuilders.Tile> requestTile(androidx.wear.tiles.RequestBuilders.TileRequest requestParams);
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> sendOnTileAddedEvent();
method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> sendOnTileEnterEvent();
diff --git a/wear/tiles/tiles-testing/src/main/java/androidx/wear/tiles/testing/TestTileClient.kt b/wear/tiles/tiles-testing/src/main/java/androidx/wear/tiles/testing/TestTileClient.kt
index 9b36360..bb0168e 100644
--- a/wear/tiles/tiles-testing/src/main/java/androidx/wear/tiles/testing/TestTileClient.kt
+++ b/wear/tiles/tiles-testing/src/main/java/androidx/wear/tiles/testing/TestTileClient.kt
@@ -21,6 +21,7 @@
import android.content.ComponentName
import android.content.Intent
import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.wear.protolayout.ResourceBuilders
import androidx.wear.tiles.RequestBuilders
import androidx.wear.tiles.TileBuilders
import androidx.wear.tiles.TileService
@@ -45,8 +46,7 @@
* unbind, but not destroy the service. If you wish to test service destruction, you can instead
* call [Service.onDestroy] on the passed in `service` instance.
*/
-public class TestTileClient<T : TileService> :
- TileClient {
+public class TestTileClient<T : TileService> : TileClient {
private val controller: ServiceController<T>
private val componentName: ComponentName
private val innerTileService: DefaultTileClient
@@ -113,7 +113,17 @@
return innerTileService.requestTile(requestParams)
}
- @Suppress("deprecation") // For backwards compatibility.
+ override fun requestTileResourcesAsync(
+ requestParams: RequestBuilders.ResourcesRequest
+ ): ListenableFuture<ResourceBuilders.Resources> {
+ maybeBind()
+ return innerTileService.requestTileResourcesAsync(requestParams)
+ }
+
+ @Deprecated(
+ "Use requestTileResourcesAsync instead.",
+ replaceWith = ReplaceWith("requestTileResourcesAsync"))
+ @Suppress("deprecation")
override fun requestResources(
requestParams: RequestBuilders.ResourcesRequest
): ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> {
@@ -153,4 +163,4 @@
)
}
}
-}
\ No newline at end of file
+}
diff --git a/wear/tiles/tiles-testing/src/test/java/androidx/wear/tiles/testing/TestTileClientTest.kt b/wear/tiles/tiles-testing/src/test/java/androidx/wear/tiles/testing/TestTileClientTest.kt
index ed539b0..f1c6f06d1 100644
--- a/wear/tiles/tiles-testing/src/test/java/androidx/wear/tiles/testing/TestTileClientTest.kt
+++ b/wear/tiles/tiles-testing/src/test/java/androidx/wear/tiles/testing/TestTileClientTest.kt
@@ -68,7 +68,7 @@
@Test
public fun canCallOnResourcesRequest() {
- val future = clientUnderTest.requestResources(
+ val future = clientUnderTest.requestTileResourcesAsync(
RequestBuilders.ResourcesRequest.Builder().build()
)
shadowOf(Looper.getMainLooper()).idle()
diff --git a/wear/tiles/tiles-tooling/build.gradle b/wear/tiles/tiles-tooling/build.gradle
index 85252f5..59362e7 100644
--- a/wear/tiles/tiles-tooling/build.gradle
+++ b/wear/tiles/tiles-tooling/build.gradle
@@ -1,5 +1,5 @@
-import androidx.build.LibraryType
import androidx.build.Publish
+import androidx.build.RunApiTasks
plugins {
id("AndroidXPlugin")
@@ -44,8 +44,8 @@
androidx {
name = "Android Wear Tiles Tooling"
- type = LibraryType.PUBLISHED_LIBRARY
- publish = Publish.SNAPSHOT_AND_RELEASE
+ publish = Publish.SNAPSHOT_ONLY // Library is not ready to be released yet.
+ runApiTasks = new RunApiTasks.Yes()
inceptionYear = "2023"
description = "A set of tools that are used to preview TilesService in Android Studio"
}
\ No newline at end of file
diff --git a/wear/tiles/tiles-tooling/src/main/java/androidx/wear/tiles/tooling/TileServiceViewAdapter.kt b/wear/tiles/tiles-tooling/src/main/java/androidx/wear/tiles/tooling/TileServiceViewAdapter.kt
index fd4b6fd..d0968e0 100644
--- a/wear/tiles/tiles-tooling/src/main/java/androidx/wear/tiles/tooling/TileServiceViewAdapter.kt
+++ b/wear/tiles/tiles-tooling/src/main/java/androidx/wear/tiles/tooling/TileServiceViewAdapter.kt
@@ -26,6 +26,7 @@
import androidx.wear.protolayout.LayoutElementBuilders
import androidx.wear.protolayout.ResourceBuilders
import androidx.wear.protolayout.StateBuilders
+import androidx.wear.protolayout.TimelineBuilders
import androidx.wear.tiles.RequestBuilders
import androidx.wear.tiles.TileBuilders
import androidx.wear.tiles.TileService
@@ -35,6 +36,8 @@
import java.lang.reflect.Method
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
+import kotlinx.coroutines.guava.await
+import kotlinx.coroutines.runBlocking
private const val TOOLS_NS_URI = "http://schemas.android.com/tools"
@@ -50,13 +53,12 @@
while (currentClass != null) {
try {
return currentClass.getDeclaredMethod(name, *parameterTypes)
- } catch (_: NoSuchMethodException) {}
+ } catch (_: NoSuchMethodException) { }
currentClass = currentClass.superclass
}
val methodSignature = "$name(${parameterTypes.joinToString { ", " }})"
throw NoSuchMethodException(
- "Could not find method $methodSignature neither in $this nor in its superclasses."
- )
+ "Could not find method $methodSignature neither in $this nor in its superclasses.")
}
/**
@@ -76,7 +78,7 @@
}
@SuppressLint("BanUncheckedReflection")
- @Suppress("UNCHECKED_CAST", "deprecation") // TODO(b/276343540): Use protolayout types
+ @Suppress("UNCHECKED_CAST")
internal fun init(tileServiceName: String) {
val tileServiceClass = Class.forName(tileServiceName)
@@ -85,9 +87,9 @@
// tileService.attachBaseContext(context)
val attachBaseContextMethod =
- tileServiceClass.findMethod("attachBaseContext", Context::class.java).apply {
- isAccessible = true
- }
+ tileServiceClass
+ .findMethod("attachBaseContext", Context::class.java)
+ .apply { isAccessible = true }
attachBaseContextMethod.invoke(tileService, context)
val deviceParams = context.buildDeviceParameters()
@@ -103,9 +105,8 @@
.findMethod("onTileRequest", RequestBuilders.TileRequest::class.java)
.apply { isAccessible = true }
val tile =
- (onTileRequestMethod.invoke(tileService, tileRequest)
- as ListenableFuture<TileBuilders.Tile>)
- .get(1, TimeUnit.SECONDS)
+ (onTileRequestMethod.invoke(tileService, tileRequest) as
+ ListenableFuture<TileBuilders.Tile>).get(1, TimeUnit.SECONDS)
val resourceRequest = RequestBuilders.ResourcesRequest
.Builder()
@@ -113,51 +114,51 @@
.setDeviceConfiguration(deviceParams)
.build()
- // val resources = tileService.onTileResourcesRequest(resourceRequest).get(1, TimeUnit.SECONDS)
+ // val resources = tileService.onTileResourcesRequest(resourceRequest).get(1,
+ // TimeUnit.SECONDS)
val onTileResourcesRequestMethod =
tileServiceClass
.findMethod("onTileResourcesRequest", RequestBuilders.ResourcesRequest::class.java)
.apply { isAccessible = true }
val resources =
ResourceBuilders.Resources.fromProto(
- (onTileResourcesRequestMethod.invoke(tileService, resourceRequest) as
- ListenableFuture<ResourceBuilders.Resources>)
- .get(1, TimeUnit.SECONDS).toProto()
- )
+ (onTileResourcesRequestMethod.invoke(tileService, resourceRequest)
+ as ListenableFuture<ResourceBuilders.Resources>)
+ .get(1, TimeUnit.SECONDS)
+ .toProto())
- val layout = tile.timeline?.getCurrentLayout()
+ val layout = tile.tileTimeline?.getCurrentLayout()
if (layout != null) {
val renderer = TileRenderer(context, ContextCompat.getMainExecutor(context)) {}
- val result = renderer.inflateAsync(layout, resources, this)
- result.addListener(
- {
- (result.get().layoutParams as FrameLayout.LayoutParams).gravity = Gravity.CENTER
- },
- ContextCompat.getMainExecutor(context)
- )
+ runBlocking {
+ renderer
+ .inflateAsync(layout, resources, this@TileServiceViewAdapter)
+ .await()
+ ?.apply { (layoutParams as FrameLayout.LayoutParams).gravity = Gravity.CENTER }
+ }
}
}
}
-@Suppress("deprecation") // For backwards compatibility.
-internal fun androidx.wear.tiles.TimelineBuilders.Timeline?.getCurrentLayout():
- LayoutElementBuilders.Layout? {
+internal fun TimelineBuilders.Timeline?.getCurrentLayout(): LayoutElementBuilders.Layout? {
val now = System.currentTimeMillis()
return this?.let {
- val cache = TilesTimelineCache(it)
- cache.findTimelineEntryForTime(now) ?: cache.findClosestTimelineEntry(now)
- }
- ?.layout
- ?.let { LayoutElementBuilders.Layout.fromProto(it.toProto()) }
+ val cache = TilesTimelineCache(it)
+ cache.findTileTimelineEntryForTime(now) ?: cache.findClosestTileTimelineEntry(now)
+ }?.layout
}
-/** Creates an instance of [DeviceParametersBuilders.DeviceParameters] from the [Context]. */
+/**
+ * Creates an instance of [DeviceParametersBuilders.DeviceParameters] from the [Context].
+ */
internal fun Context.buildDeviceParameters(): DeviceParametersBuilders.DeviceParameters {
val displayMetrics = resources.displayMetrics
val isScreenRound = resources.configuration.isScreenRound
return DeviceParametersBuilders.DeviceParameters.Builder()
- .setScreenWidthDp((displayMetrics.widthPixels / displayMetrics.density).roundToInt())
- .setScreenHeightDp((displayMetrics.heightPixels / displayMetrics.density).roundToInt())
+ .setScreenWidthDp(
+ (displayMetrics.widthPixels / displayMetrics.density).roundToInt())
+ .setScreenHeightDp(
+ (displayMetrics.heightPixels / displayMetrics.density).roundToInt())
.setScreenDensity(displayMetrics.density)
.setScreenShape(
if (isScreenRound) DeviceParametersBuilders.SCREEN_SHAPE_ROUND
diff --git a/wear/tiles/tiles/lint-baseline.xml b/wear/tiles/tiles/lint-baseline.xml
new file mode 100644
index 0000000..2fdb31d
--- /dev/null
+++ b/wear/tiles/tiles/lint-baseline.xml
@@ -0,0 +1,121 @@
+<?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">
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface ResourcesCallback {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/ResourcesCallback.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable ResourcesData;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/ResourcesData.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable ResourcesRequestData;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/ResourcesRequestData.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable TileAddEventData;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/TileAddEventData.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface TileCallback {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/TileCallback.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable TileData;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/TileData.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable TileEnterEventData;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/TileEnterEventData.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable TileLeaveEventData;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/TileLeaveEventData.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface TileProvider {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/TileProvider.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable TileRemoveEventData;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/TileRemoveEventData.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable TileRequestData;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/TileRequestData.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable TileUpdateRequestData;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/TileUpdateRequestData.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface TileUpdateRequesterService {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/tiles/TileUpdateRequesterService.aidl"/>
+ </issue>
+
+</issues>
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ActionBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ActionBuilders.java
index 0146892..a169593 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ActionBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ActionBuilders.java
@@ -10,12 +10,14 @@
* 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.tiles;
+import static androidx.wear.protolayout.expression.Preconditions.checkNotNull;
import static java.util.stream.Collectors.toMap;
import android.annotation.SuppressLint;
@@ -24,6 +26,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.ActionProto;
import java.util.Collections;
@@ -71,9 +74,12 @@
/** A string value that can be added to an Android intent's extras. */
public static final class AndroidStringExtra implements AndroidExtra {
private final ActionProto.AndroidStringExtra mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private AndroidStringExtra(ActionProto.AndroidStringExtra impl) {
+ AndroidStringExtra(
+ ActionProto.AndroidStringExtra impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -82,13 +88,18 @@
return mImpl.getValue();
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static AndroidStringExtra fromProto(@NonNull ActionProto.AndroidStringExtra proto) {
- return new AndroidStringExtra(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static AndroidStringExtra fromProto(@NonNull ActionProto.AndroidStringExtra proto) {
+ return new AndroidStringExtra(proto, null);
+ }
+
@NonNull
ActionProto.AndroidStringExtra toProto() {
return mImpl;
@@ -105,6 +116,7 @@
public static final class Builder implements AndroidExtra.Builder {
private final ActionProto.AndroidStringExtra.Builder mImpl =
ActionProto.AndroidStringExtra.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1281351679);
public Builder() {}
@@ -112,13 +124,14 @@
@NonNull
public Builder setValue(@NonNull String value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, value.hashCode());
return this;
}
@Override
@NonNull
public AndroidStringExtra build() {
- return AndroidStringExtra.fromProto(mImpl.build());
+ return new AndroidStringExtra(mImpl.build(), mFingerprint);
}
}
}
@@ -126,9 +139,12 @@
/** An integer value that can be added to an Android intent's extras. */
public static final class AndroidIntExtra implements AndroidExtra {
private final ActionProto.AndroidIntExtra mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private AndroidIntExtra(ActionProto.AndroidIntExtra impl) {
+ AndroidIntExtra(
+ ActionProto.AndroidIntExtra impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -136,13 +152,18 @@
return mImpl.getValue();
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static AndroidIntExtra fromProto(@NonNull ActionProto.AndroidIntExtra proto) {
- return new AndroidIntExtra(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static AndroidIntExtra fromProto(@NonNull ActionProto.AndroidIntExtra proto) {
+ return new AndroidIntExtra(proto, null);
+ }
+
@NonNull
ActionProto.AndroidIntExtra toProto() {
return mImpl;
@@ -159,6 +180,7 @@
public static final class Builder implements AndroidExtra.Builder {
private final ActionProto.AndroidIntExtra.Builder mImpl =
ActionProto.AndroidIntExtra.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1929293734);
public Builder() {}
@@ -166,13 +188,14 @@
@NonNull
public Builder setValue(int value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, value);
return this;
}
@Override
@NonNull
public AndroidIntExtra build() {
- return AndroidIntExtra.fromProto(mImpl.build());
+ return new AndroidIntExtra(mImpl.build(), mFingerprint);
}
}
}
@@ -180,9 +203,12 @@
/** A long value that can be added to an Android intent's extras. */
public static final class AndroidLongExtra implements AndroidExtra {
private final ActionProto.AndroidLongExtra mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private AndroidLongExtra(ActionProto.AndroidLongExtra impl) {
+ AndroidLongExtra(
+ ActionProto.AndroidLongExtra impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -190,13 +216,18 @@
return mImpl.getValue();
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static AndroidLongExtra fromProto(@NonNull ActionProto.AndroidLongExtra proto) {
- return new AndroidLongExtra(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static AndroidLongExtra fromProto(@NonNull ActionProto.AndroidLongExtra proto) {
+ return new AndroidLongExtra(proto, null);
+ }
+
@NonNull
ActionProto.AndroidLongExtra toProto() {
return mImpl;
@@ -213,6 +244,7 @@
public static final class Builder implements AndroidExtra.Builder {
private final ActionProto.AndroidLongExtra.Builder mImpl =
ActionProto.AndroidLongExtra.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-874743180);
public Builder() {}
@@ -220,13 +252,14 @@
@NonNull
public Builder setValue(long value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Long.hashCode(value));
return this;
}
@Override
@NonNull
public AndroidLongExtra build() {
- return AndroidLongExtra.fromProto(mImpl.build());
+ return new AndroidLongExtra(mImpl.build(), mFingerprint);
}
}
}
@@ -234,9 +267,12 @@
/** A double value that can be added to an Android intent's extras. */
public static final class AndroidDoubleExtra implements AndroidExtra {
private final ActionProto.AndroidDoubleExtra mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private AndroidDoubleExtra(ActionProto.AndroidDoubleExtra impl) {
+ AndroidDoubleExtra(
+ ActionProto.AndroidDoubleExtra impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -244,13 +280,18 @@
return mImpl.getValue();
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static AndroidDoubleExtra fromProto(@NonNull ActionProto.AndroidDoubleExtra proto) {
- return new AndroidDoubleExtra(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static AndroidDoubleExtra fromProto(@NonNull ActionProto.AndroidDoubleExtra proto) {
+ return new AndroidDoubleExtra(proto, null);
+ }
+
@NonNull
ActionProto.AndroidDoubleExtra toProto() {
return mImpl;
@@ -267,6 +308,7 @@
public static final class Builder implements AndroidExtra.Builder {
private final ActionProto.AndroidDoubleExtra.Builder mImpl =
ActionProto.AndroidDoubleExtra.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-278689892);
public Builder() {}
@@ -274,13 +316,14 @@
@NonNull
public Builder setValue(double value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Double.hashCode(value));
return this;
}
@Override
@NonNull
public AndroidDoubleExtra build() {
- return AndroidDoubleExtra.fromProto(mImpl.build());
+ return new AndroidDoubleExtra(mImpl.build(), mFingerprint);
}
}
}
@@ -288,9 +331,12 @@
/** A boolean value that can be added to an Android intent's extras. */
public static final class AndroidBooleanExtra implements AndroidExtra {
private final ActionProto.AndroidBooleanExtra mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private AndroidBooleanExtra(ActionProto.AndroidBooleanExtra impl) {
+ AndroidBooleanExtra(
+ ActionProto.AndroidBooleanExtra impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -298,14 +344,18 @@
return mImpl.getValue();
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static AndroidBooleanExtra fromProto(
- @NonNull ActionProto.AndroidBooleanExtra proto) {
- return new AndroidBooleanExtra(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static AndroidBooleanExtra fromProto(@NonNull ActionProto.AndroidBooleanExtra proto) {
+ return new AndroidBooleanExtra(proto, null);
+ }
+
@NonNull
ActionProto.AndroidBooleanExtra toProto() {
return mImpl;
@@ -322,6 +372,7 @@
public static final class Builder implements AndroidExtra.Builder {
private final ActionProto.AndroidBooleanExtra.Builder mImpl =
ActionProto.AndroidBooleanExtra.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1238672683);
public Builder() {}
@@ -330,13 +381,14 @@
@NonNull
public Builder setValue(boolean value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Boolean.hashCode(value));
return this;
}
@Override
@NonNull
public AndroidBooleanExtra build() {
- return AndroidBooleanExtra.fromProto(mImpl.build());
+ return new AndroidBooleanExtra(mImpl.build(), mFingerprint);
}
}
}
@@ -351,30 +403,10 @@
@NonNull
ActionProto.AndroidExtra toAndroidExtraProto();
- /**
- * Return an instance of one of this object's subtypes, from the protocol buffer
- * representation.
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- static AndroidExtra fromAndroidExtraProto(@NonNull ActionProto.AndroidExtra proto) {
- if (proto.hasStringVal()) {
- return AndroidStringExtra.fromProto(proto.getStringVal());
- }
- if (proto.hasIntVal()) {
- return AndroidIntExtra.fromProto(proto.getIntVal());
- }
- if (proto.hasLongVal()) {
- return AndroidLongExtra.fromProto(proto.getLongVal());
- }
- if (proto.hasDoubleVal()) {
- return AndroidDoubleExtra.fromProto(proto.getDoubleVal());
- }
- if (proto.hasBooleanVal()) {
- return AndroidBooleanExtra.fromProto(proto.getBooleanVal());
- }
- throw new IllegalStateException("Proto was not a recognised instance of AndroidExtra");
- }
+ @Nullable
+ Fingerprint getFingerprint();
/** Builder to create {@link AndroidExtra} objects. */
@SuppressLint("StaticFinalBuilder")
@@ -386,12 +418,39 @@
}
}
+ /**
+ * Return an instance of one of this object's subtypes, from the protocol buffer
+ * representation.
+ */
+ @NonNull
+ static AndroidExtra androidExtraFromProto(@NonNull ActionProto.AndroidExtra proto) {
+ if (proto.hasStringVal()) {
+ return AndroidStringExtra.fromProto(proto.getStringVal());
+ }
+ if (proto.hasIntVal()) {
+ return AndroidIntExtra.fromProto(proto.getIntVal());
+ }
+ if (proto.hasLongVal()) {
+ return AndroidLongExtra.fromProto(proto.getLongVal());
+ }
+ if (proto.hasDoubleVal()) {
+ return AndroidDoubleExtra.fromProto(proto.getDoubleVal());
+ }
+ if (proto.hasBooleanVal()) {
+ return AndroidBooleanExtra.fromProto(proto.getBooleanVal());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of AndroidExtra");
+ }
+
/** A launch action to send an intent to an Android activity. */
public static final class AndroidActivity {
private final ActionProto.AndroidActivity mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private AndroidActivity(ActionProto.AndroidActivity impl) {
+ AndroidActivity(
+ ActionProto.AndroidActivity impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -421,20 +480,23 @@
.collect(
toMap(
Map.Entry::getKey,
- f ->
- AndroidExtra.fromAndroidExtraProto(
- f.getValue()))));
+ f -> androidExtraFromProto(f.getValue()))));
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static AndroidActivity fromProto(@NonNull ActionProto.AndroidActivity proto) {
- return new AndroidActivity(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public ActionProto.AndroidActivity toProto() {
+ static AndroidActivity fromProto(@NonNull ActionProto.AndroidActivity proto) {
+ return new AndroidActivity(proto, null);
+ }
+
+ @NonNull
+ ActionProto.AndroidActivity toProto() {
return mImpl;
}
@@ -442,6 +504,7 @@
public static final class Builder {
private final ActionProto.AndroidActivity.Builder mImpl =
ActionProto.AndroidActivity.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1939606345);
public Builder() {}
@@ -449,6 +512,7 @@
@NonNull
public Builder setPackageName(@NonNull String packageName) {
mImpl.setPackageName(packageName);
+ mFingerprint.recordPropertyUpdate(1, packageName.hashCode());
return this;
}
@@ -459,6 +523,7 @@
@NonNull
public Builder setClassName(@NonNull String className) {
mImpl.setClassName(className);
+ mFingerprint.recordPropertyUpdate(2, className.hashCode());
return this;
}
@@ -467,13 +532,15 @@
@NonNull
public Builder addKeyToExtraMapping(@NonNull String key, @NonNull AndroidExtra extra) {
mImpl.putKeyToExtra(key, extra.toAndroidExtraProto());
+ mFingerprint.recordPropertyUpdate(
+ key.hashCode(), checkNotNull(extra.getFingerprint()).aggregateValueAsInt());
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public AndroidActivity build() {
- return AndroidActivity.fromProto(mImpl.build());
+ return new AndroidActivity(mImpl.build(), mFingerprint);
}
}
}
@@ -485,9 +552,11 @@
*/
public static final class LaunchAction implements Action {
private final ActionProto.LaunchAction mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private LaunchAction(ActionProto.LaunchAction impl) {
+ LaunchAction(ActionProto.LaunchAction impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets an action to launch an Android activity. Intended for testing purposes only. */
@@ -500,13 +569,18 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static LaunchAction fromProto(@NonNull ActionProto.LaunchAction proto) {
- return new LaunchAction(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static LaunchAction fromProto(@NonNull ActionProto.LaunchAction proto) {
+ return new LaunchAction(proto, null);
+ }
+
@NonNull
ActionProto.LaunchAction toProto() {
return mImpl;
@@ -523,6 +597,7 @@
public static final class Builder implements Action.Builder {
private final ActionProto.LaunchAction.Builder mImpl =
ActionProto.LaunchAction.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(175064445);
public Builder() {}
@@ -530,13 +605,15 @@
@NonNull
public Builder setAndroidActivity(@NonNull AndroidActivity androidActivity) {
mImpl.setAndroidActivity(androidActivity.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(androidActivity.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public LaunchAction build() {
- return LaunchAction.fromProto(mImpl.build());
+ return new LaunchAction(mImpl.build(), mFingerprint);
}
}
}
@@ -544,9 +621,11 @@
/** An action used to load (or reload) the tile contents. */
public static final class LoadAction implements Action {
private final ActionProto.LoadAction mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private LoadAction(ActionProto.LoadAction impl) {
+ LoadAction(ActionProto.LoadAction impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -564,13 +643,18 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static LoadAction fromProto(@NonNull ActionProto.LoadAction proto) {
- return new LoadAction(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static LoadAction fromProto(@NonNull ActionProto.LoadAction proto) {
+ return new LoadAction(proto, null);
+ }
+
@NonNull
ActionProto.LoadAction toProto() {
return mImpl;
@@ -587,6 +671,7 @@
public static final class Builder implements Action.Builder {
private final ActionProto.LoadAction.Builder mImpl =
ActionProto.LoadAction.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1728161517);
public Builder() {}
@@ -598,13 +683,15 @@
@NonNull
public Builder setRequestState(@NonNull StateBuilders.State requestState) {
mImpl.setRequestState(requestState.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(requestState.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public LoadAction build() {
- return LoadAction.fromProto(mImpl.build());
+ return new LoadAction(mImpl.build(), mFingerprint);
}
}
}
@@ -616,21 +703,10 @@
@NonNull
ActionProto.Action toActionProto();
- /**
- * Return an instance of one of this object's subtypes, from the protocol buffer
- * representation.
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- static Action fromActionProto(@NonNull ActionProto.Action proto) {
- if (proto.hasLaunchAction()) {
- return LaunchAction.fromProto(proto.getLaunchAction());
- }
- if (proto.hasLoadAction()) {
- return LoadAction.fromProto(proto.getLoadAction());
- }
- throw new IllegalStateException("Proto was not a recognised instance of Action");
- }
+ @Nullable
+ Fingerprint getFingerprint();
/** Builder to create {@link Action} objects. */
@SuppressLint("StaticFinalBuilder")
@@ -641,4 +717,19 @@
Action build();
}
}
+
+ /**
+ * Return an instance of one of this object's subtypes, from the protocol buffer
+ * representation.
+ */
+ @NonNull
+ static Action actionFromProto(@NonNull ActionProto.Action proto) {
+ if (proto.hasLaunchAction()) {
+ return LaunchAction.fromProto(proto.getLaunchAction());
+ }
+ if (proto.hasLoadAction()) {
+ return LoadAction.fromProto(proto.getLoadAction());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of Action");
+ }
}
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ColorBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ColorBuilders.java
index aadb4fa..dd34db9 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ColorBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ColorBuilders.java
@@ -18,8 +18,10 @@
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.ColorProto;
/**
@@ -27,6 +29,7 @@
*
* @deprecated Use {@link androidx.wear.protolayout.ColorBuilders} instead.
*/
+@Deprecated
public final class ColorBuilders {
private ColorBuilders() {}
@@ -39,9 +42,11 @@
/** A property defining a color. */
public static final class ColorProp {
private final ColorProto.ColorProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ColorProp(ColorProto.ColorProp impl) {
+ ColorProp(ColorProto.ColorProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the color value, in ARGB format. Intended for testing purposes only. */
@@ -50,21 +55,27 @@
return mImpl.getArgb();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static ColorProp fromProto(@NonNull ColorProto.ColorProp proto) {
- return new ColorProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public ColorProto.ColorProp toProto() {
+ static ColorProp fromProto(@NonNull ColorProto.ColorProp proto) {
+ return new ColorProp(proto, null);
+ }
+
+ @NonNull
+ ColorProto.ColorProp toProto() {
return mImpl;
}
/** Builder for {@link ColorProp} */
public static final class Builder {
private final ColorProto.ColorProp.Builder mImpl = ColorProto.ColorProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1332287496);
public Builder() {}
@@ -72,13 +83,14 @@
@NonNull
public Builder setArgb(@ColorInt int argb) {
mImpl.setArgb(argb);
+ mFingerprint.recordPropertyUpdate(1, argb);
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public ColorProp build() {
- return ColorProp.fromProto(mImpl.build());
+ return new ColorProp(mImpl.build(), mFingerprint);
}
}
}
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/DeviceParametersBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/DeviceParametersBuilders.java
index bcd694f..662d045 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/DeviceParametersBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/DeviceParametersBuilders.java
@@ -23,7 +23,6 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
-import androidx.annotation.RestrictTo.Scope;
import androidx.wear.protolayout.proto.DeviceParametersProto;
import java.lang.annotation.Retention;
@@ -109,16 +108,13 @@
return mImpl.getScreenShape().getNumber();
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public static DeviceParameters fromProto(
- @NonNull DeviceParametersProto.DeviceParameters proto) {
+ static DeviceParameters fromProto(@NonNull DeviceParametersProto.DeviceParameters proto) {
return new DeviceParameters(proto);
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public DeviceParametersProto.DeviceParameters toProto() {
+ DeviceParametersProto.DeviceParameters toProto() {
return mImpl;
}
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/DimensionBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/DimensionBuilders.java
index cb98f89..1452498f 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/DimensionBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/DimensionBuilders.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2021-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.
@@ -24,8 +24,10 @@
import androidx.annotation.Dimension;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.DimensionProto;
/**
@@ -92,9 +94,11 @@
public static final class DpProp
implements ContainerDimension, ImageDimension, SpacerDimension {
private final DimensionProto.DpProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private DpProp(DimensionProto.DpProp impl) {
+ DpProp(DimensionProto.DpProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value, in dp. Intended for testing purposes only. */
@@ -103,13 +107,18 @@
return mImpl.getValue();
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static DpProp fromProto(@NonNull DimensionProto.DpProp proto) {
- return new DpProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static DpProp fromProto(@NonNull DimensionProto.DpProp proto) {
+ return new DpProp(proto, null);
+ }
+
@NonNull
DimensionProto.DpProp toProto() {
return mImpl;
@@ -142,6 +151,7 @@
ImageDimension.Builder,
SpacerDimension.Builder {
private final DimensionProto.DpProp.Builder mImpl = DimensionProto.DpProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(752970309);
public Builder() {}
@@ -149,13 +159,14 @@
@NonNull
public Builder setValue(@Dimension(unit = DP) float value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Float.floatToIntBits(value));
return this;
}
@Override
@NonNull
public DpProp build() {
- return DpProp.fromProto(mImpl.build());
+ return new DpProp(mImpl.build(), mFingerprint);
}
}
}
@@ -163,9 +174,11 @@
/** A type for font sizes, measured in sp. */
public static final class SpProp {
private final DimensionProto.SpProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private SpProp(DimensionProto.SpProp impl) {
+ SpProp(DimensionProto.SpProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value, in sp. Intended for testing purposes only. */
@@ -174,21 +187,27 @@
return mImpl.getValue();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static SpProp fromProto(@NonNull DimensionProto.SpProp proto) {
- return new SpProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public DimensionProto.SpProp toProto() {
+ static SpProp fromProto(@NonNull DimensionProto.SpProp proto) {
+ return new SpProp(proto, null);
+ }
+
+ @NonNull
+ DimensionProto.SpProp toProto() {
return mImpl;
}
/** Builder for {@link SpProp} */
public static final class Builder {
private final DimensionProto.SpProp.Builder mImpl = DimensionProto.SpProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-2144685857);
public Builder() {}
@@ -196,13 +215,14 @@
@NonNull
public Builder setValue(@Dimension(unit = SP) float value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(2, Float.floatToIntBits(value));
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public SpProp build() {
- return SpProp.fromProto(mImpl.build());
+ return new SpProp(mImpl.build(), mFingerprint);
}
}
}
@@ -210,9 +230,11 @@
/** A type for font spacing, measured in em. */
public static final class EmProp {
private final DimensionProto.EmProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private EmProp(DimensionProto.EmProp impl) {
+ EmProp(DimensionProto.EmProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value, in em. Intended for testing purposes only. */
@@ -220,21 +242,27 @@
return mImpl.getValue();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static EmProp fromProto(@NonNull DimensionProto.EmProp proto) {
- return new EmProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public DimensionProto.EmProp toProto() {
+ static EmProp fromProto(@NonNull DimensionProto.EmProp proto) {
+ return new EmProp(proto, null);
+ }
+
+ @NonNull
+ DimensionProto.EmProp toProto() {
return mImpl;
}
/** Builder for {@link EmProp} */
public static final class Builder {
private final DimensionProto.EmProp.Builder mImpl = DimensionProto.EmProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1628313311);
public Builder() {}
@@ -242,13 +270,14 @@
@NonNull
public Builder setValue(float value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Float.floatToIntBits(value));
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public EmProp build() {
- return EmProp.fromProto(mImpl.build());
+ return new EmProp(mImpl.build(), mFingerprint);
}
}
}
@@ -256,9 +285,11 @@
/** A type for angular dimensions, measured in degrees. */
public static final class DegreesProp {
private final DimensionProto.DegreesProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private DegreesProp(DimensionProto.DegreesProp impl) {
+ DegreesProp(DimensionProto.DegreesProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value, in degrees. Intended for testing purposes only. */
@@ -266,15 +297,20 @@
return mImpl.getValue();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static DegreesProp fromProto(@NonNull DimensionProto.DegreesProp proto) {
- return new DegreesProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public DimensionProto.DegreesProp toProto() {
+ static DegreesProp fromProto(@NonNull DimensionProto.DegreesProp proto) {
+ return new DegreesProp(proto, null);
+ }
+
+ @NonNull
+ DimensionProto.DegreesProp toProto() {
return mImpl;
}
@@ -282,6 +318,7 @@
public static final class Builder {
private final DimensionProto.DegreesProp.Builder mImpl =
DimensionProto.DegreesProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(405060347);
public Builder() {}
@@ -289,13 +326,14 @@
@NonNull
public Builder setValue(float value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Float.floatToIntBits(value));
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public DegreesProp build() {
- return DegreesProp.fromProto(mImpl.build());
+ return new DegreesProp(mImpl.build(), mFingerprint);
}
}
}
@@ -306,19 +344,27 @@
*/
public static final class ExpandedDimensionProp implements ContainerDimension, ImageDimension {
private final DimensionProto.ExpandedDimensionProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ExpandedDimensionProp(DimensionProto.ExpandedDimensionProp impl) {
+ ExpandedDimensionProp(
+ DimensionProto.ExpandedDimensionProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
@NonNull
- public static ExpandedDimensionProp fromProto(
+ static ExpandedDimensionProp fromProto(
@NonNull DimensionProto.ExpandedDimensionProp proto) {
- return new ExpandedDimensionProp(proto);
+ return new ExpandedDimensionProp(proto, null);
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DimensionProto.ExpandedDimensionProp toProto() {
return mImpl;
@@ -345,13 +391,14 @@
implements ContainerDimension.Builder, ImageDimension.Builder {
private final DimensionProto.ExpandedDimensionProp.Builder mImpl =
DimensionProto.ExpandedDimensionProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1053378170);
public Builder() {}
@Override
@NonNull
public ExpandedDimensionProp build() {
- return ExpandedDimensionProp.fromProto(mImpl.build());
+ return new ExpandedDimensionProp(mImpl.build(), mFingerprint);
}
}
}
@@ -362,19 +409,26 @@
*/
public static final class WrappedDimensionProp implements ContainerDimension {
private final DimensionProto.WrappedDimensionProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private WrappedDimensionProp(DimensionProto.WrappedDimensionProp impl) {
+ WrappedDimensionProp(
+ DimensionProto.WrappedDimensionProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
@NonNull
- public static WrappedDimensionProp fromProto(
- @NonNull DimensionProto.WrappedDimensionProp proto) {
- return new WrappedDimensionProp(proto);
+ static WrappedDimensionProp fromProto(@NonNull DimensionProto.WrappedDimensionProp proto) {
+ return new WrappedDimensionProp(proto, null);
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DimensionProto.WrappedDimensionProp toProto() {
return mImpl;
@@ -393,13 +447,14 @@
public static final class Builder implements ContainerDimension.Builder {
private final DimensionProto.WrappedDimensionProp.Builder mImpl =
DimensionProto.WrappedDimensionProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-113456542);
public Builder() {}
@Override
@NonNull
public WrappedDimensionProp build() {
- return WrappedDimensionProp.fromProto(mImpl.build());
+ return new WrappedDimensionProp(mImpl.build(), mFingerprint);
}
}
}
@@ -415,9 +470,12 @@
*/
public static final class ProportionalDimensionProp implements ImageDimension {
private final DimensionProto.ProportionalDimensionProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ProportionalDimensionProp(DimensionProto.ProportionalDimensionProp impl) {
+ ProportionalDimensionProp(
+ DimensionProto.ProportionalDimensionProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -438,14 +496,19 @@
return mImpl.getAspectRatioHeight();
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static ProportionalDimensionProp fromProto(
- @NonNull DimensionProto.ProportionalDimensionProp proto) {
- return new ProportionalDimensionProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static ProportionalDimensionProp fromProto(
+ @NonNull DimensionProto.ProportionalDimensionProp proto) {
+ return new ProportionalDimensionProp(proto, null);
+ }
+
@NonNull
DimensionProto.ProportionalDimensionProp toProto() {
return mImpl;
@@ -464,6 +527,7 @@
public static final class Builder implements ImageDimension.Builder {
private final DimensionProto.ProportionalDimensionProp.Builder mImpl =
DimensionProto.ProportionalDimensionProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-2079046835);
public Builder() {}
@@ -471,6 +535,7 @@
@NonNull
public Builder setAspectRatioWidth(@IntRange(from = 0) int aspectRatioWidth) {
mImpl.setAspectRatioWidth(aspectRatioWidth);
+ mFingerprint.recordPropertyUpdate(1, aspectRatioWidth);
return this;
}
@@ -478,13 +543,14 @@
@NonNull
public Builder setAspectRatioHeight(@IntRange(from = 0) int aspectRatioHeight) {
mImpl.setAspectRatioHeight(aspectRatioHeight);
+ mFingerprint.recordPropertyUpdate(2, aspectRatioHeight);
return this;
}
@Override
@NonNull
public ProportionalDimensionProp build() {
- return ProportionalDimensionProp.fromProto(mImpl.build());
+ return new ProportionalDimensionProp(mImpl.build(), mFingerprint);
}
}
}
@@ -496,26 +562,10 @@
@NonNull
DimensionProto.ContainerDimension toContainerDimensionProto();
- /**
- * Return an instance of one of this object's subtypes, from the protocol buffer
- * representation.
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- static ContainerDimension fromContainerDimensionProto(
- @NonNull DimensionProto.ContainerDimension proto) {
- if (proto.hasLinearDimension()) {
- return DpProp.fromProto(proto.getLinearDimension());
- }
- if (proto.hasExpandedDimension()) {
- return ExpandedDimensionProp.fromProto(proto.getExpandedDimension());
- }
- if (proto.hasWrappedDimension()) {
- return WrappedDimensionProp.fromProto(proto.getWrappedDimension());
- }
- throw new IllegalStateException(
- "Proto was not a recognised instance of ContainerDimension");
- }
+ @Nullable
+ Fingerprint getFingerprint();
/** Builder to create {@link ContainerDimension} objects. */
@SuppressLint("StaticFinalBuilder")
@@ -527,6 +577,26 @@
}
}
+ /**
+ * Return an instance of one of this object's subtypes, from the protocol buffer
+ * representation.
+ */
+ @NonNull
+ static ContainerDimension containerDimensionFromProto(
+ @NonNull DimensionProto.ContainerDimension proto) {
+ if (proto.hasLinearDimension()) {
+ return DpProp.fromProto(proto.getLinearDimension());
+ }
+ if (proto.hasExpandedDimension()) {
+ return ExpandedDimensionProp.fromProto(proto.getExpandedDimension());
+ }
+ if (proto.hasWrappedDimension()) {
+ return WrappedDimensionProp.fromProto(proto.getWrappedDimension());
+ }
+ throw new IllegalStateException(
+ "Proto was not a recognised instance of ContainerDimension");
+ }
+
/** Interface defining a dimension that can be applied to an image. */
public interface ImageDimension {
/** Get the protocol buffer representation of this object. */
@@ -534,26 +604,10 @@
@NonNull
DimensionProto.ImageDimension toImageDimensionProto();
- /**
- * Return an instance of one of this object's subtypes, from the protocol buffer
- * representation.
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- static ImageDimension fromImageDimensionProto(
- @NonNull DimensionProto.ImageDimension proto) {
- if (proto.hasLinearDimension()) {
- return DpProp.fromProto(proto.getLinearDimension());
- }
- if (proto.hasExpandedDimension()) {
- return ExpandedDimensionProp.fromProto(proto.getExpandedDimension());
- }
- if (proto.hasProportionalDimension()) {
- return ProportionalDimensionProp.fromProto(proto.getProportionalDimension());
- }
- throw new IllegalStateException(
- "Proto was not a recognised instance of ImageDimension");
- }
+ @Nullable
+ Fingerprint getFingerprint();
/** Builder to create {@link ImageDimension} objects. */
@SuppressLint("StaticFinalBuilder")
@@ -565,6 +619,24 @@
}
}
+ /**
+ * Return an instance of one of this object's subtypes, from the protocol buffer
+ * representation.
+ */
+ @NonNull
+ static ImageDimension imageDimensionFromProto(@NonNull DimensionProto.ImageDimension proto) {
+ if (proto.hasLinearDimension()) {
+ return DpProp.fromProto(proto.getLinearDimension());
+ }
+ if (proto.hasExpandedDimension()) {
+ return ExpandedDimensionProp.fromProto(proto.getExpandedDimension());
+ }
+ if (proto.hasProportionalDimension()) {
+ return ProportionalDimensionProp.fromProto(proto.getProportionalDimension());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of ImageDimension");
+ }
+
/** Interface defining a dimension that can be applied to a spacer. */
public interface SpacerDimension {
/** Get the protocol buffer representation of this object. */
@@ -572,20 +644,10 @@
@NonNull
DimensionProto.SpacerDimension toSpacerDimensionProto();
- /**
- * Return an instance of one of this object's subtypes, from the protocol buffer
- * representation.
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- static SpacerDimension fromSpacerDimensionProto(
- @NonNull DimensionProto.SpacerDimension proto) {
- if (proto.hasLinearDimension()) {
- return DpProp.fromProto(proto.getLinearDimension());
- }
- throw new IllegalStateException(
- "Proto was not a recognised instance of SpacerDimension");
- }
+ @Nullable
+ Fingerprint getFingerprint();
/** Builder to create {@link SpacerDimension} objects. */
@SuppressLint("StaticFinalBuilder")
@@ -596,4 +658,12 @@
SpacerDimension build();
}
}
+
+ @NonNull
+ static SpacerDimension spacerDimensionFromProto(@NonNull DimensionProto.SpacerDimension proto) {
+ if (proto.hasLinearDimension()) {
+ return DpProp.fromProto(proto.getLinearDimension());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of SpacerDimension");
+ }
}
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/EventBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/EventBuilders.java
index 0d962f5..4563882 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/EventBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/EventBuilders.java
@@ -49,31 +49,25 @@
return mImpl.getTileId();
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static TileAddEvent fromProto(@NonNull EventProto.TileAddEvent proto) {
return new TileAddEvent(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public EventProto.TileAddEvent toProto() {
return mImpl;
}
- @Override
- @NonNull
- public String toString() {
- return "TileAddEvent{" + "tileId=" + getTileId() + "}";
- }
+ @Override
+ @NonNull
+ public String toString() {
+ return "TileAddEvent{" + "tileId=" + getTileId() + "}";
+ }
/** Builder for {@link TileAddEvent} */
public static final class Builder {
@@ -124,31 +118,25 @@
return mImpl.getTileId();
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static TileRemoveEvent fromProto(@NonNull EventProto.TileRemoveEvent proto) {
return new TileRemoveEvent(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public EventProto.TileRemoveEvent toProto() {
return mImpl;
}
- @Override
- @NonNull
- public String toString() {
- return "TileRemoveEvent{" + "tileId=" + getTileId() + "}";
- }
+ @Override
+ @NonNull
+ public String toString() {
+ return "TileRemoveEvent{" + "tileId=" + getTileId() + "}";
+ }
/** Builder for {@link TileRemoveEvent} */
public static final class Builder {
@@ -199,31 +187,25 @@
return mImpl.getTileId();
}
- /**
- * Creates a new wrapper instance from the proto.
- *
- */
+ /** Creates a new wrapper instance from the proto. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static TileEnterEvent fromProto(@NonNull EventProto.TileEnterEvent proto) {
return new TileEnterEvent(proto);
}
- /**
- * Returns the internal proto instance.
- *
- */
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public EventProto.TileEnterEvent toProto() {
return mImpl;
}
- @Override
- @NonNull
- public String toString() {
- return "TileEnterEvent{" + "tileId=" + getTileId() + "}";
- }
+ @Override
+ @NonNull
+ public String toString() {
+ return "TileEnterEvent{" + "tileId=" + getTileId() + "}";
+ }
/** Builder for {@link TileEnterEvent} */
public static final class Builder {
@@ -298,10 +280,7 @@
@Override
@NonNull
public String toString() {
- return "TileLeaveEvent{"
- + "tileId="
- + getTileId()
- + "}";
+ return "TileLeaveEvent{" + "tileId=" + getTileId() + "}";
}
/** Builder for {@link TileLeaveEvent} */
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/LayoutElementBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/LayoutElementBuilders.java
index afad3bd..05ff865 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/LayoutElementBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/LayoutElementBuilders.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2021-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.
@@ -16,6 +16,7 @@
package androidx.wear.tiles;
+import static androidx.wear.protolayout.expression.Preconditions.checkNotNull;
import static java.util.stream.Collectors.toList;
import android.annotation.SuppressLint;
@@ -27,7 +28,10 @@
import androidx.annotation.OptIn;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.AlignmentProto;
+import androidx.wear.protolayout.proto.FingerprintProto;
+import androidx.wear.protolayout.proto.FingerprintProto.TreeFingerprint;
import androidx.wear.protolayout.proto.LayoutElementProto;
import androidx.wear.protolayout.proto.TypesProto;
import androidx.wear.protolayout.protobuf.InvalidProtocolBufferException;
@@ -178,15 +182,19 @@
public static final int TEXT_ALIGN_UNDEFINED = 0;
/**
- * Align to the "start" of the {@link Text} element (left in LTR layouts, right in RTL layouts).
+ * Align to the "start" of the {@link androidx.wear.tiles.LayoutElementBuilders.Text} element
+ * (left in LTR layouts, right in RTL layouts).
*/
public static final int TEXT_ALIGN_START = 1;
- /** Align to the center of the {@link Text} element. */
+ /**
+ * Align to the center of the {@link androidx.wear.tiles.LayoutElementBuilders.Text} element.
+ */
public static final int TEXT_ALIGN_CENTER = 2;
/**
- * Align to the "end" of the {@link Text} element (right in LTR layouts, left in RTL layouts).
+ * Align to the "end" of the {@link androidx.wear.tiles.LayoutElementBuilders.Text} element
+ * (right in LTR layouts, left in RTL layouts).
*/
public static final int TEXT_ALIGN_END = 3;
@@ -212,12 +220,15 @@
public static final int TEXT_OVERFLOW_ELLIPSIZE_END = 2;
/**
- * The anchor position of an {@link Arc}'s elements. This is used to specify how elements added
- * to an {@link Arc} should be laid out with respect to anchor_angle.
+ * The anchor position of an {@link androidx.wear.tiles.LayoutElementBuilders.Arc}'s elements.
+ * This is used to specify how elements added to an {@link
+ * androidx.wear.tiles.LayoutElementBuilders.Arc} should be laid out with respect to
+ * anchor_angle.
*
* <p>As an example, assume that the following diagrams are wrapped to an arc, and each
- * represents an {@link Arc} element containing a single {@link Text} element. The {@link Text}
- * element's anchor_angle is "0" for all cases.
+ * represents an {@link androidx.wear.tiles.LayoutElementBuilders.Arc} element containing a
+ * single {@link androidx.wear.tiles.LayoutElementBuilders.Text} element. The {@link
+ * androidx.wear.tiles.LayoutElementBuilders.Text} element's anchor_angle is "0" for all cases.
*
* <pre>{@code
* ARC_ANCHOR_START:
@@ -303,9 +314,12 @@
/** An extensible {@code HorizontalAlignment} property. */
public static final class HorizontalAlignmentProp {
private final AlignmentProto.HorizontalAlignmentProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private HorizontalAlignmentProp(AlignmentProto.HorizontalAlignmentProp impl) {
+ private HorizontalAlignmentProp(
+ AlignmentProto.HorizontalAlignmentProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -314,16 +328,23 @@
return mImpl.getValue().getNumber();
}
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static HorizontalAlignmentProp fromProto(
- @NonNull AlignmentProto.HorizontalAlignmentProp proto) {
- return new HorizontalAlignmentProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public AlignmentProto.HorizontalAlignmentProp toProto() {
+ static HorizontalAlignmentProp fromProto(
+ @NonNull AlignmentProto.HorizontalAlignmentProp proto) {
+ return new HorizontalAlignmentProp(proto, null);
+ }
+
+ @NonNull
+ AlignmentProto.HorizontalAlignmentProp toProto() {
return mImpl;
}
@@ -331,6 +352,7 @@
public static final class Builder {
private final AlignmentProto.HorizontalAlignmentProp.Builder mImpl =
AlignmentProto.HorizontalAlignmentProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-384830516);
public Builder() {}
@@ -338,6 +360,7 @@
@NonNull
public Builder setValue(@HorizontalAlignment int value) {
mImpl.setValue(AlignmentProto.HorizontalAlignment.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
return this;
}
@@ -352,9 +375,12 @@
/** An extensible {@code VerticalAlignment} property. */
public static final class VerticalAlignmentProp {
private final AlignmentProto.VerticalAlignmentProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private VerticalAlignmentProp(AlignmentProto.VerticalAlignmentProp impl) {
+ VerticalAlignmentProp(
+ AlignmentProto.VerticalAlignmentProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -363,16 +389,21 @@
return mImpl.getValue().getNumber();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static VerticalAlignmentProp fromProto(
- @NonNull AlignmentProto.VerticalAlignmentProp proto) {
- return new VerticalAlignmentProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public AlignmentProto.VerticalAlignmentProp toProto() {
+ static VerticalAlignmentProp fromProto(
+ @NonNull AlignmentProto.VerticalAlignmentProp proto) {
+ return new VerticalAlignmentProp(proto, null);
+ }
+
+ @NonNull
+ AlignmentProto.VerticalAlignmentProp toProto() {
return mImpl;
}
@@ -380,6 +411,7 @@
public static final class Builder {
private final AlignmentProto.VerticalAlignmentProp.Builder mImpl =
AlignmentProto.VerticalAlignmentProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1443510393);
public Builder() {}
@@ -387,13 +419,14 @@
@NonNull
public Builder setValue(@VerticalAlignment int value) {
mImpl.setValue(AlignmentProto.VerticalAlignment.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public VerticalAlignmentProp build() {
- return VerticalAlignmentProp.fromProto(mImpl.build());
+ return new VerticalAlignmentProp(mImpl.build(), mFingerprint);
}
}
}
@@ -401,9 +434,12 @@
/** An extensible {@code FontWeight} property. */
public static final class FontWeightProp {
private final LayoutElementProto.FontWeightProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private FontWeightProp(LayoutElementProto.FontWeightProp impl) {
+ FontWeightProp(
+ LayoutElementProto.FontWeightProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -412,15 +448,20 @@
return mImpl.getValue().getNumber();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static FontWeightProp fromProto(@NonNull LayoutElementProto.FontWeightProp proto) {
- return new FontWeightProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public LayoutElementProto.FontWeightProp toProto() {
+ static FontWeightProp fromProto(@NonNull LayoutElementProto.FontWeightProp proto) {
+ return new FontWeightProp(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.FontWeightProp toProto() {
return mImpl;
}
@@ -428,6 +469,7 @@
public static final class Builder {
private final LayoutElementProto.FontWeightProp.Builder mImpl =
LayoutElementProto.FontWeightProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1793388920);
public Builder() {}
@@ -435,13 +477,14 @@
@NonNull
public Builder setValue(@FontWeight int value) {
mImpl.setValue(LayoutElementProto.FontWeight.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public FontWeightProp build() {
- return FontWeightProp.fromProto(mImpl.build());
+ return new FontWeightProp(mImpl.build(), mFingerprint);
}
}
}
@@ -450,9 +493,12 @@
@TilesExperimental
public static final class FontVariantProp {
private final LayoutElementProto.FontVariantProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private FontVariantProp(LayoutElementProto.FontVariantProp impl) {
+ FontVariantProp(
+ LayoutElementProto.FontVariantProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -461,15 +507,20 @@
return mImpl.getValue().getNumber();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static FontVariantProp fromProto(@NonNull LayoutElementProto.FontVariantProp proto) {
- return new FontVariantProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public LayoutElementProto.FontVariantProp toProto() {
+ static FontVariantProp fromProto(@NonNull LayoutElementProto.FontVariantProp proto) {
+ return new FontVariantProp(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.FontVariantProp toProto() {
return mImpl;
}
@@ -477,6 +528,7 @@
public static final class Builder {
private final LayoutElementProto.FontVariantProp.Builder mImpl =
LayoutElementProto.FontVariantProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-293831500);
public Builder() {}
@@ -484,13 +536,14 @@
@NonNull
public Builder setValue(@FontVariant int value) {
mImpl.setValue(LayoutElementProto.FontVariant.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public FontVariantProp build() {
- return FontVariantProp.fromProto(mImpl.build());
+ return new FontVariantProp(mImpl.build(), mFingerprint);
}
}
}
@@ -498,9 +551,13 @@
/** An extensible {@code SpanVerticalAlignment} property. */
public static final class SpanVerticalAlignmentProp {
private final LayoutElementProto.SpanVerticalAlignmentProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private SpanVerticalAlignmentProp(LayoutElementProto.SpanVerticalAlignmentProp impl) {
+ SpanVerticalAlignmentProp(
+ LayoutElementProto.SpanVerticalAlignmentProp impl,
+ @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -509,16 +566,21 @@
return mImpl.getValue().getNumber();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static SpanVerticalAlignmentProp fromProto(
- @NonNull LayoutElementProto.SpanVerticalAlignmentProp proto) {
- return new SpanVerticalAlignmentProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public LayoutElementProto.SpanVerticalAlignmentProp toProto() {
+ static SpanVerticalAlignmentProp fromProto(
+ @NonNull LayoutElementProto.SpanVerticalAlignmentProp proto) {
+ return new SpanVerticalAlignmentProp(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.SpanVerticalAlignmentProp toProto() {
return mImpl;
}
@@ -526,6 +588,7 @@
public static final class Builder {
private final LayoutElementProto.SpanVerticalAlignmentProp.Builder mImpl =
LayoutElementProto.SpanVerticalAlignmentProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1008812329);
public Builder() {}
@@ -533,13 +596,14 @@
@NonNull
public Builder setValue(@SpanVerticalAlignment int value) {
mImpl.setValue(LayoutElementProto.SpanVerticalAlignment.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public SpanVerticalAlignmentProp build() {
- return SpanVerticalAlignmentProp.fromProto(mImpl.build());
+ return new SpanVerticalAlignmentProp(mImpl.build(), mFingerprint);
}
}
}
@@ -547,9 +611,11 @@
/** The styling of a font (e.g. font size, and metrics). */
public static final class FontStyle {
private final LayoutElementProto.FontStyle mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private FontStyle(LayoutElementProto.FontStyle impl) {
+ FontStyle(LayoutElementProto.FontStyle impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -647,12 +713,19 @@
}
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static FontStyle fromProto(@NonNull LayoutElementProto.FontStyle proto) {
- return new FontStyle(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
+ @NonNull
+ static FontStyle fromProto(@NonNull LayoutElementProto.FontStyle proto) {
+ return new FontStyle(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public LayoutElementProto.FontStyle toProto() {
@@ -663,6 +736,7 @@
public static final class Builder {
private final LayoutElementProto.FontStyle.Builder mImpl =
LayoutElementProto.FontStyle.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(181264306);
public Builder() {}
@@ -673,6 +747,8 @@
@NonNull
public Builder setSize(@NonNull DimensionBuilders.SpProp size) {
mImpl.setSize(size.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(size.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -683,8 +759,11 @@
@NonNull
public Builder setItalic(@NonNull TypeBuilders.BoolProp italic) {
mImpl.setItalic(italic.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(italic.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets whether the text should be rendered in a italic typeface. If not specified,
* defaults to "false".
@@ -693,6 +772,7 @@
@NonNull
public Builder setItalic(boolean italic) {
mImpl.setItalic(TypesProto.BoolProp.newBuilder().setValue(italic));
+ mFingerprint.recordPropertyUpdate(2, Boolean.hashCode(italic));
return this;
}
@@ -703,8 +783,11 @@
@NonNull
public Builder setUnderline(@NonNull TypeBuilders.BoolProp underline) {
mImpl.setUnderline(underline.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(underline.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets whether the text should be rendered with an underline. If not specified,
* defaults to "false".
@@ -713,6 +796,7 @@
@NonNull
public Builder setUnderline(boolean underline) {
mImpl.setUnderline(TypesProto.BoolProp.newBuilder().setValue(underline));
+ mFingerprint.recordPropertyUpdate(3, Boolean.hashCode(underline));
return this;
}
@@ -720,6 +804,8 @@
@NonNull
public Builder setColor(@NonNull ColorBuilders.ColorProp color) {
mImpl.setColor(color.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(color.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -731,8 +817,11 @@
@NonNull
public Builder setWeight(@NonNull FontWeightProp weight) {
mImpl.setWeight(weight.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(weight.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the weight of the font. If the provided value is not supported on a platform,
* the nearest supported value will be used. If not defined, or when set to an invalid
@@ -743,6 +832,7 @@
mImpl.setWeight(
LayoutElementProto.FontWeightProp.newBuilder()
.setValue(LayoutElementProto.FontWeight.forNumber(weight)));
+ mFingerprint.recordPropertyUpdate(5, weight);
return this;
}
@@ -753,6 +843,8 @@
@NonNull
public Builder setLetterSpacing(@NonNull DimensionBuilders.EmProp letterSpacing) {
mImpl.setLetterSpacing(letterSpacing.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 6, checkNotNull(letterSpacing.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -764,8 +856,11 @@
@NonNull
public Builder setVariant(@NonNull FontVariantProp variant) {
mImpl.setVariant(variant.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 7, checkNotNull(variant.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the variant of a font. Some renderers may use different fonts for title and body
* text, which can be selected using this field. If not specified, defaults to "body".
@@ -776,13 +871,14 @@
mImpl.setVariant(
LayoutElementProto.FontVariantProp.newBuilder()
.setValue(LayoutElementProto.FontVariant.forNumber(variant)));
+ mFingerprint.recordPropertyUpdate(7, variant);
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public FontStyle build() {
- return FontStyle.fromProto(mImpl.build());
+ return new FontStyle(mImpl.build(), mFingerprint);
}
}
}
@@ -790,9 +886,12 @@
/** An extensible {@code TextAlignment} property. */
public static final class TextAlignmentProp {
private final AlignmentProto.TextAlignmentProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private TextAlignmentProp(AlignmentProto.TextAlignmentProp impl) {
+ TextAlignmentProp(
+ AlignmentProto.TextAlignmentProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -801,15 +900,20 @@
return mImpl.getValue().getNumber();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static TextAlignmentProp fromProto(@NonNull AlignmentProto.TextAlignmentProp proto) {
- return new TextAlignmentProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public AlignmentProto.TextAlignmentProp toProto() {
+ static TextAlignmentProp fromProto(@NonNull AlignmentProto.TextAlignmentProp proto) {
+ return new TextAlignmentProp(proto, null);
+ }
+
+ @NonNull
+ AlignmentProto.TextAlignmentProp toProto() {
return mImpl;
}
@@ -817,6 +921,7 @@
public static final class Builder {
private final AlignmentProto.TextAlignmentProp.Builder mImpl =
AlignmentProto.TextAlignmentProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(797507251);
public Builder() {}
@@ -824,13 +929,14 @@
@NonNull
public Builder setValue(@TextAlignment int value) {
mImpl.setValue(AlignmentProto.TextAlignment.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public TextAlignmentProp build() {
- return TextAlignmentProp.fromProto(mImpl.build());
+ return new TextAlignmentProp(mImpl.build(), mFingerprint);
}
}
}
@@ -838,9 +944,12 @@
/** An extensible {@code TextOverflow} property. */
public static final class TextOverflowProp {
private final LayoutElementProto.TextOverflowProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private TextOverflowProp(LayoutElementProto.TextOverflowProp impl) {
+ TextOverflowProp(
+ LayoutElementProto.TextOverflowProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -849,16 +958,20 @@
return mImpl.getValue().getNumber();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static TextOverflowProp fromProto(
- @NonNull LayoutElementProto.TextOverflowProp proto) {
- return new TextOverflowProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public LayoutElementProto.TextOverflowProp toProto() {
+ static TextOverflowProp fromProto(@NonNull LayoutElementProto.TextOverflowProp proto) {
+ return new TextOverflowProp(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.TextOverflowProp toProto() {
return mImpl;
}
@@ -866,6 +979,7 @@
public static final class Builder {
private final LayoutElementProto.TextOverflowProp.Builder mImpl =
LayoutElementProto.TextOverflowProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1183432233);
public Builder() {}
@@ -873,13 +987,14 @@
@NonNull
public Builder setValue(@TextOverflow int value) {
mImpl.setValue(LayoutElementProto.TextOverflow.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public TextOverflowProp build() {
- return TextOverflowProp.fromProto(mImpl.build());
+ return new TextOverflowProp(mImpl.build(), mFingerprint);
}
}
}
@@ -887,9 +1002,12 @@
/** An extensible {@code ArcAnchorType} property. */
public static final class ArcAnchorTypeProp {
private final AlignmentProto.ArcAnchorTypeProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ArcAnchorTypeProp(AlignmentProto.ArcAnchorTypeProp impl) {
+ ArcAnchorTypeProp(
+ AlignmentProto.ArcAnchorTypeProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -898,15 +1016,20 @@
return mImpl.getValue().getNumber();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static ArcAnchorTypeProp fromProto(@NonNull AlignmentProto.ArcAnchorTypeProp proto) {
- return new ArcAnchorTypeProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public AlignmentProto.ArcAnchorTypeProp toProto() {
+ static ArcAnchorTypeProp fromProto(@NonNull AlignmentProto.ArcAnchorTypeProp proto) {
+ return new ArcAnchorTypeProp(proto, null);
+ }
+
+ @NonNull
+ AlignmentProto.ArcAnchorTypeProp toProto() {
return mImpl;
}
@@ -914,6 +1037,7 @@
public static final class Builder {
private final AlignmentProto.ArcAnchorTypeProp.Builder mImpl =
AlignmentProto.ArcAnchorTypeProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1193249074);
public Builder() {}
@@ -921,13 +1045,14 @@
@NonNull
public Builder setValue(@ArcAnchorType int value) {
mImpl.setValue(AlignmentProto.ArcAnchorType.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public ArcAnchorTypeProp build() {
- return ArcAnchorTypeProp.fromProto(mImpl.build());
+ return new ArcAnchorTypeProp(mImpl.build(), mFingerprint);
}
}
}
@@ -935,9 +1060,11 @@
/** A text string. */
public static final class Text implements LayoutElement {
private final LayoutElementProto.Text mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Text(LayoutElementProto.Text impl) {
+ Text(LayoutElementProto.Text impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the text to render. Intended for testing purposes only. */
@@ -1036,13 +1163,19 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Text fromProto(@NonNull LayoutElementProto.Text proto) {
- return new Text(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static Text fromProto(
+ @NonNull LayoutElementProto.Text proto, @Nullable Fingerprint fingerprint) {
+ return new Text(proto, fingerprint);
+ }
+
@NonNull
LayoutElementProto.Text toProto() {
return mImpl;
@@ -1059,6 +1192,7 @@
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Text.Builder mImpl =
LayoutElementProto.Text.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1976530157);
public Builder() {}
@@ -1066,12 +1200,16 @@
@NonNull
public Builder setText(@NonNull TypeBuilders.StringProp text) {
mImpl.setText(text.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(text.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/** Sets the text to render. */
@NonNull
public Builder setText(@NonNull String text) {
- mImpl.setText(TypesProto.StringProp.newBuilder().setValue(text));
+ mImpl.mergeText(TypesProto.StringProp.newBuilder().setValue(text).build());
+ mFingerprint.recordPropertyUpdate(1, text.hashCode());
return this;
}
@@ -1082,6 +1220,8 @@
@NonNull
public Builder setFontStyle(@NonNull FontStyle fontStyle) {
mImpl.setFontStyle(fontStyle.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(fontStyle.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -1089,6 +1229,8 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.Modifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -1099,8 +1241,11 @@
@NonNull
public Builder setMaxLines(@NonNull TypeBuilders.Int32Prop maxLines) {
mImpl.setMaxLines(maxLines.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(maxLines.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the maximum number of lines that can be represented by the {@link Text} element.
* If not defined, the {@link Text} element will be treated as a single-line element.
@@ -1108,6 +1253,7 @@
@NonNull
public Builder setMaxLines(@IntRange(from = 1) int maxLines) {
mImpl.setMaxLines(TypesProto.Int32Prop.newBuilder().setValue(maxLines));
+ mFingerprint.recordPropertyUpdate(4, maxLines);
return this;
}
@@ -1121,8 +1267,11 @@
@NonNull
public Builder setMultilineAlignment(@NonNull TextAlignmentProp multilineAlignment) {
mImpl.setMultilineAlignment(multilineAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(multilineAlignment.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets alignment of the text within its bounds. Note that a {@link Text} element will
* size itself to wrap its contents, so this option is meaningless for single-line text
@@ -1137,6 +1286,7 @@
.setValue(
AlignmentProto.TextAlignment.forNumber(
multilineAlignment)));
+ mFingerprint.recordPropertyUpdate(5, multilineAlignment);
return this;
}
@@ -1150,8 +1300,11 @@
@NonNull
public Builder setOverflow(@NonNull TextOverflowProp overflow) {
mImpl.setOverflow(overflow.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 6, checkNotNull(overflow.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets how to handle text which overflows the bound of the {@link Text} element. A
* {@link Text} element will grow as large as possible inside its parent container
@@ -1164,6 +1317,7 @@
mImpl.setOverflow(
LayoutElementProto.TextOverflowProp.newBuilder()
.setValue(LayoutElementProto.TextOverflow.forNumber(overflow)));
+ mFingerprint.recordPropertyUpdate(6, overflow);
return this;
}
@@ -1175,13 +1329,15 @@
@NonNull
public Builder setLineHeight(@NonNull DimensionBuilders.SpProp lineHeight) {
mImpl.setLineHeight(lineHeight.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 7, checkNotNull(lineHeight.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public Text build() {
- return Text.fromProto(mImpl.build());
+ return new Text(mImpl.build(), mFingerprint);
}
}
}
@@ -1189,9 +1345,12 @@
/** An extensible {@code ContentScaleMode} property. */
public static final class ContentScaleModeProp {
private final LayoutElementProto.ContentScaleModeProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ContentScaleModeProp(LayoutElementProto.ContentScaleModeProp impl) {
+ ContentScaleModeProp(
+ LayoutElementProto.ContentScaleModeProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -1200,16 +1359,21 @@
return mImpl.getValue().getNumber();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static ContentScaleModeProp fromProto(
- @NonNull LayoutElementProto.ContentScaleModeProp proto) {
- return new ContentScaleModeProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public LayoutElementProto.ContentScaleModeProp toProto() {
+ static ContentScaleModeProp fromProto(
+ @NonNull LayoutElementProto.ContentScaleModeProp proto) {
+ return new ContentScaleModeProp(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.ContentScaleModeProp toProto() {
return mImpl;
}
@@ -1217,6 +1381,7 @@
public static final class Builder {
private final LayoutElementProto.ContentScaleModeProp.Builder mImpl =
LayoutElementProto.ContentScaleModeProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-893830536);
public Builder() {}
@@ -1224,13 +1389,14 @@
@NonNull
public Builder setValue(@ContentScaleMode int value) {
mImpl.setValue(LayoutElementProto.ContentScaleMode.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public ContentScaleModeProp build() {
- return ContentScaleModeProp.fromProto(mImpl.build());
+ return new ContentScaleModeProp(mImpl.build(), mFingerprint);
}
}
}
@@ -1238,9 +1404,12 @@
/** Filtering parameters used for images. This can be used to apply a color tint to images. */
public static final class ColorFilter {
private final LayoutElementProto.ColorFilter mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ColorFilter(LayoutElementProto.ColorFilter impl) {
+ ColorFilter(
+ LayoutElementProto.ColorFilter impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -1260,15 +1429,20 @@
}
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static ColorFilter fromProto(@NonNull LayoutElementProto.ColorFilter proto) {
- return new ColorFilter(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public LayoutElementProto.ColorFilter toProto() {
+ static ColorFilter fromProto(@NonNull LayoutElementProto.ColorFilter proto) {
+ return new ColorFilter(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.ColorFilter toProto() {
return mImpl;
}
@@ -1276,6 +1450,7 @@
public static final class Builder {
private final LayoutElementProto.ColorFilter.Builder mImpl =
LayoutElementProto.ColorFilter.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(181311326);
public Builder() {}
@@ -1291,13 +1466,15 @@
public LayoutElementBuilders.ColorFilter.Builder setTint(
@NonNull ColorBuilders.ColorProp tint) {
mImpl.setTint(tint.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(tint.getFingerprint()).aggregateValueAsInt());
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public ColorFilter build() {
- return ColorFilter.fromProto(mImpl.build());
+ return new ColorFilter(mImpl.build(), mFingerprint);
}
}
}
@@ -1311,9 +1488,11 @@
*/
public static final class Image implements LayoutElement {
private final LayoutElementProto.Image mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Image(LayoutElementProto.Image impl) {
+ Image(LayoutElementProto.Image impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -1336,7 +1515,7 @@
@Nullable
public DimensionBuilders.ImageDimension getWidth() {
if (mImpl.hasWidth()) {
- return DimensionBuilders.ImageDimension.fromImageDimensionProto(mImpl.getWidth());
+ return DimensionBuilders.imageDimensionFromProto(mImpl.getWidth());
} else {
return null;
}
@@ -1349,7 +1528,7 @@
@Nullable
public DimensionBuilders.ImageDimension getHeight() {
if (mImpl.hasHeight()) {
- return DimensionBuilders.ImageDimension.fromImageDimensionProto(mImpl.getHeight());
+ return DimensionBuilders.imageDimensionFromProto(mImpl.getHeight());
} else {
return null;
}
@@ -1392,13 +1571,19 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Image fromProto(@NonNull LayoutElementProto.Image proto) {
- return new Image(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static Image fromProto(
+ @NonNull LayoutElementProto.Image proto, @Nullable Fingerprint fingerprint) {
+ return new Image(proto, fingerprint);
+ }
+
@NonNull
LayoutElementProto.Image toProto() {
return mImpl;
@@ -1415,6 +1600,7 @@
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Image.Builder mImpl =
LayoutElementProto.Image.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-543078544);
public Builder() {}
@@ -1425,8 +1611,11 @@
@NonNull
public Builder setResourceId(@NonNull TypeBuilders.StringProp resourceId) {
mImpl.setResourceId(resourceId.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(resourceId.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the resource_id of the image to render. This must exist in the supplied resource
* bundle.
@@ -1434,6 +1623,7 @@
@NonNull
public Builder setResourceId(@NonNull String resourceId) {
mImpl.setResourceId(TypesProto.StringProp.newBuilder().setValue(resourceId));
+ mFingerprint.recordPropertyUpdate(1, resourceId.hashCode());
return this;
}
@@ -1441,6 +1631,8 @@
@NonNull
public Builder setWidth(@NonNull DimensionBuilders.ImageDimension width) {
mImpl.setWidth(width.toImageDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -1448,6 +1640,8 @@
@NonNull
public Builder setHeight(@NonNull DimensionBuilders.ImageDimension height) {
mImpl.setHeight(height.toImageDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -1458,8 +1652,11 @@
@NonNull
public Builder setContentScaleMode(@NonNull ContentScaleModeProp contentScaleMode) {
mImpl.setContentScaleMode(contentScaleMode.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(contentScaleMode.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets how to scale the image resource inside the bounds specified by width/height if
* its size does not match those bounds. Defaults to CONTENT_SCALE_MODE_FIT.
@@ -1471,6 +1668,7 @@
.setValue(
LayoutElementProto.ContentScaleMode.forNumber(
contentScaleMode)));
+ mFingerprint.recordPropertyUpdate(4, contentScaleMode);
return this;
}
@@ -1478,6 +1676,8 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.Modifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -1485,15 +1685,17 @@
* Sets filtering parameters for this image. If not specified, defaults to no filtering.
*/
@NonNull
- public Builder setColorFilter(@NonNull ColorFilter filter) {
- mImpl.setColorFilter(filter.toProto());
+ public Builder setColorFilter(@NonNull ColorFilter colorFilter) {
+ mImpl.setColorFilter(colorFilter.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 6, checkNotNull(colorFilter.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public Image build() {
- return Image.fromProto(mImpl.build());
+ return new Image(mImpl.build(), mFingerprint);
}
}
}
@@ -1501,9 +1703,11 @@
/** A simple spacer, typically used to provide padding between adjacent elements. */
public static final class Spacer implements LayoutElement {
private final LayoutElementProto.Spacer mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Spacer(LayoutElementProto.Spacer impl) {
+ Spacer(LayoutElementProto.Spacer impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -1514,7 +1718,7 @@
@Nullable
public DimensionBuilders.SpacerDimension getWidth() {
if (mImpl.hasWidth()) {
- return DimensionBuilders.SpacerDimension.fromSpacerDimensionProto(mImpl.getWidth());
+ return DimensionBuilders.spacerDimensionFromProto(mImpl.getWidth());
} else {
return null;
}
@@ -1527,7 +1731,7 @@
@Nullable
public DimensionBuilders.SpacerDimension getHeight() {
if (mImpl.hasHeight()) {
- return DimensionBuilders.SpacerDimension.fromSpacerDimensionProto(
+ return DimensionBuilders.spacerDimensionFromProto(
mImpl.getHeight());
} else {
return null;
@@ -1547,13 +1751,19 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Spacer fromProto(@NonNull LayoutElementProto.Spacer proto) {
- return new Spacer(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static Spacer fromProto(
+ @NonNull LayoutElementProto.Spacer proto, @Nullable Fingerprint fingerprint) {
+ return new Spacer(proto, fingerprint);
+ }
+
@NonNull
LayoutElementProto.Spacer toProto() {
return mImpl;
@@ -1570,6 +1780,7 @@
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Spacer.Builder mImpl =
LayoutElementProto.Spacer.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1748084575);
public Builder() {}
@@ -1581,6 +1792,8 @@
@NonNull
public Builder setWidth(@NonNull DimensionBuilders.SpacerDimension width) {
mImpl.setWidth(width.toSpacerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -1588,6 +1801,8 @@
@NonNull
public Builder setHeight(@NonNull DimensionBuilders.SpacerDimension height) {
mImpl.setHeight(height.toSpacerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -1595,13 +1810,15 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.Modifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public Spacer build() {
- return Spacer.fromProto(mImpl.build());
+ return new Spacer(mImpl.build(), mFingerprint);
}
}
}
@@ -1612,9 +1829,11 @@
*/
public static final class Box implements LayoutElement {
private final LayoutElementProto.Box mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Box(LayoutElementProto.Box impl) {
+ Box(LayoutElementProto.Box impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the child element(s) to wrap. Intended for testing purposes only. */
@@ -1622,7 +1841,7 @@
public List<LayoutElement> getContents() {
return Collections.unmodifiableList(
mImpl.getContentsList().stream()
- .map(LayoutElement::fromLayoutElementProto)
+ .map(LayoutElementBuilders::layoutElementFromProto)
.collect(toList()));
}
@@ -1633,7 +1852,7 @@
@Nullable
public DimensionBuilders.ContainerDimension getHeight() {
if (mImpl.hasHeight()) {
- return DimensionBuilders.ContainerDimension.fromContainerDimensionProto(
+ return DimensionBuilders.containerDimensionFromProto(
mImpl.getHeight());
} else {
return null;
@@ -1647,7 +1866,7 @@
@Nullable
public DimensionBuilders.ContainerDimension getWidth() {
if (mImpl.hasWidth()) {
- return DimensionBuilders.ContainerDimension.fromContainerDimensionProto(
+ return DimensionBuilders.containerDimensionFromProto(
mImpl.getWidth());
} else {
return null;
@@ -1693,13 +1912,19 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Box fromProto(@NonNull LayoutElementProto.Box proto) {
- return new Box(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static Box fromProto(
+ @NonNull LayoutElementProto.Box proto, @Nullable Fingerprint fingerprint) {
+ return new Box(proto, fingerprint);
+ }
+
@NonNull
LayoutElementProto.Box toProto() {
return mImpl;
@@ -1716,6 +1941,7 @@
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Box.Builder mImpl =
LayoutElementProto.Box.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1881256071);
public Builder() {}
@@ -1723,6 +1949,7 @@
@NonNull
public Builder addContent(@NonNull LayoutElement content) {
mImpl.addContents(content.toLayoutElementProto());
+ mFingerprint.addChildNode(checkNotNull(content.getFingerprint()));
return this;
}
@@ -1733,6 +1960,8 @@
@NonNull
public Builder setHeight(@NonNull DimensionBuilders.ContainerDimension height) {
mImpl.setHeight(height.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -1743,6 +1972,8 @@
@NonNull
public Builder setWidth(@NonNull DimensionBuilders.ContainerDimension width) {
mImpl.setWidth(width.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -1754,8 +1985,12 @@
public Builder setHorizontalAlignment(
@NonNull HorizontalAlignmentProp horizontalAlignment) {
mImpl.setHorizontalAlignment(horizontalAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4,
+ checkNotNull(horizontalAlignment.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the horizontal alignment of the element inside this {@link Box}. If not defined,
* defaults to HORIZONTAL_ALIGN_CENTER.
@@ -1767,6 +2002,7 @@
.setValue(
AlignmentProto.HorizontalAlignment.forNumber(
horizontalAlignment)));
+ mFingerprint.recordPropertyUpdate(4, horizontalAlignment);
return this;
}
@@ -1777,8 +2013,11 @@
@NonNull
public Builder setVerticalAlignment(@NonNull VerticalAlignmentProp verticalAlignment) {
mImpl.setVerticalAlignment(verticalAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(verticalAlignment.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the vertical alignment of the element inside this {@link Box}. If not defined,
* defaults to VERTICAL_ALIGN_CENTER.
@@ -1790,6 +2029,7 @@
.setValue(
AlignmentProto.VerticalAlignment.forNumber(
verticalAlignment)));
+ mFingerprint.recordPropertyUpdate(5, verticalAlignment);
return this;
}
@@ -1797,13 +2037,15 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.Modifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 6, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public Box build() {
- return Box.fromProto(mImpl.build());
+ return new Box(mImpl.build(), mFingerprint);
}
}
}
@@ -1815,9 +2057,11 @@
*/
public static final class SpanText implements Span {
private final LayoutElementProto.SpanText mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private SpanText(LayoutElementProto.SpanText impl) {
+ SpanText(LayoutElementProto.SpanText impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the text to render. Intended for testing purposes only. */
@@ -1856,13 +2100,18 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static SpanText fromProto(@NonNull LayoutElementProto.SpanText proto) {
- return new SpanText(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static SpanText fromProto(@NonNull LayoutElementProto.SpanText proto) {
+ return new SpanText(proto, null);
+ }
+
@NonNull
LayoutElementProto.SpanText toProto() {
return mImpl;
@@ -1879,6 +2128,7 @@
public static final class Builder implements Span.Builder {
private final LayoutElementProto.SpanText.Builder mImpl =
LayoutElementProto.SpanText.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-221774557);
public Builder() {}
@@ -1886,12 +2136,16 @@
@NonNull
public Builder setText(@NonNull TypeBuilders.StringProp text) {
mImpl.setText(text.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(text.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/** Sets the text to render. */
@NonNull
public Builder setText(@NonNull String text) {
mImpl.setText(TypesProto.StringProp.newBuilder().setValue(text));
+ mFingerprint.recordPropertyUpdate(1, text.hashCode());
return this;
}
@@ -1902,6 +2156,8 @@
@NonNull
public Builder setFontStyle(@NonNull FontStyle fontStyle) {
mImpl.setFontStyle(fontStyle.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(fontStyle.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -1909,13 +2165,15 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.SpanModifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public SpanText build() {
- return SpanText.fromProto(mImpl.build());
+ return new SpanText(mImpl.build(), mFingerprint);
}
}
}
@@ -1923,9 +2181,11 @@
/** An image which can be added to a {@link Span}. */
public static final class SpanImage implements Span {
private final LayoutElementProto.SpanImage mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private SpanImage(LayoutElementProto.SpanImage impl) {
+ SpanImage(LayoutElementProto.SpanImage impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -1993,13 +2253,18 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static SpanImage fromProto(@NonNull LayoutElementProto.SpanImage proto) {
- return new SpanImage(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static SpanImage fromProto(@NonNull LayoutElementProto.SpanImage proto) {
+ return new SpanImage(proto, null);
+ }
+
@NonNull
LayoutElementProto.SpanImage toProto() {
return mImpl;
@@ -2016,6 +2281,7 @@
public static final class Builder implements Span.Builder {
private final LayoutElementProto.SpanImage.Builder mImpl =
LayoutElementProto.SpanImage.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(502289772);
public Builder() {}
@@ -2026,8 +2292,11 @@
@NonNull
public Builder setResourceId(@NonNull TypeBuilders.StringProp resourceId) {
mImpl.setResourceId(resourceId.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(resourceId.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the resource_id of the image to render. This must exist in the supplied resource
* bundle.
@@ -2035,6 +2304,7 @@
@NonNull
public Builder setResourceId(@NonNull String resourceId) {
mImpl.setResourceId(TypesProto.StringProp.newBuilder().setValue(resourceId));
+ mFingerprint.recordPropertyUpdate(1, resourceId.hashCode());
return this;
}
@@ -2042,6 +2312,8 @@
@NonNull
public Builder setWidth(@NonNull DimensionBuilders.DpProp width) {
mImpl.setWidth(width.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -2049,6 +2321,8 @@
@NonNull
public Builder setHeight(@NonNull DimensionBuilders.DpProp height) {
mImpl.setHeight(height.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -2056,6 +2330,8 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.SpanModifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -2066,8 +2342,11 @@
@NonNull
public Builder setAlignment(@NonNull SpanVerticalAlignmentProp alignment) {
mImpl.setAlignment(alignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(alignment.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets alignment of this image within the line height of the surrounding {@link
* Spannable}. If undefined, defaults to SPAN_VERTICAL_ALIGN_BOTTOM.
@@ -2079,13 +2358,14 @@
.setValue(
LayoutElementProto.SpanVerticalAlignment.forNumber(
alignment)));
+ mFingerprint.recordPropertyUpdate(5, alignment);
return this;
}
@Override
@NonNull
public SpanImage build() {
- return SpanImage.fromProto(mImpl.build());
+ return new SpanImage(mImpl.build(), mFingerprint);
}
}
}
@@ -2101,21 +2381,10 @@
@NonNull
LayoutElementProto.Span toSpanProto();
- /**
- * Return an instance of one of this object's subtypes, from the protocol buffer
- * representation.
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- static Span fromSpanProto(@NonNull LayoutElementProto.Span proto) {
- if (proto.hasText()) {
- return SpanText.fromProto(proto.getText());
- }
- if (proto.hasImage()) {
- return SpanImage.fromProto(proto.getImage());
- }
- throw new IllegalStateException("Proto was not a recognised instance of Span");
- }
+ @Nullable
+ Fingerprint getFingerprint();
/** Builder to create {@link Span} objects. */
@SuppressLint("StaticFinalBuilder")
@@ -2128,16 +2397,33 @@
}
/**
- * A container of {@link Span} elements. Currently, this only supports {@link Text} elements,
- * where each individual {@link Span} can have different styling applied to it but the resulting
- * text will flow naturally. This allows sections of a paragraph of text to have different
- * styling applied to it, for example, making one or two words bold or italic.
+ * Return an instance of one of this object's subtypes, from the protocol buffer
+ * representation.
+ */
+ @NonNull
+ static Span spanFromProto(@NonNull LayoutElementProto.Span proto) {
+ if (proto.hasText()) {
+ return SpanText.fromProto(proto.getText());
+ }
+ if (proto.hasImage()) {
+ return SpanImage.fromProto(proto.getImage());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of Span");
+ }
+
+ /**
+ * A container of {@link Span} elements. Currently, this supports {@link SpanImage} and {@link
+ * SpanText} elements, where each individual {@link Span} can have different styling applied to
+ * it but the resulting text will flow naturally. This allows sections of a paragraph of text to
+ * have different styling applied to it, for example, making one or two words bold or italic.
*/
public static final class Spannable implements LayoutElement {
private final LayoutElementProto.Spannable mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Spannable(LayoutElementProto.Spannable impl) {
+ Spannable(LayoutElementProto.Spannable impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -2147,7 +2433,8 @@
@NonNull
public List<Span> getSpans() {
return Collections.unmodifiableList(
- mImpl.getSpansList().stream().map(Span::fromSpanProto).collect(toList()));
+ mImpl.getSpansList().stream().map(
+ LayoutElementBuilders::spanFromProto).collect(toList()));
}
/**
@@ -2224,13 +2511,19 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Spannable fromProto(@NonNull LayoutElementProto.Spannable proto) {
- return new Spannable(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static Spannable fromProto(
+ @NonNull LayoutElementProto.Spannable proto, @Nullable Fingerprint fingerprint) {
+ return new Spannable(proto, fingerprint);
+ }
+
@NonNull
LayoutElementProto.Spannable toProto() {
return mImpl;
@@ -2247,6 +2540,7 @@
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Spannable.Builder mImpl =
LayoutElementProto.Spannable.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1690284372);
public Builder() {}
@@ -2254,6 +2548,8 @@
@NonNull
public Builder addSpan(@NonNull Span span) {
mImpl.addSpans(span.toSpanProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(span.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -2261,6 +2557,8 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.Modifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -2272,8 +2570,11 @@
@NonNull
public Builder setMaxLines(@NonNull TypeBuilders.Int32Prop maxLines) {
mImpl.setMaxLines(maxLines.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(maxLines.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the maximum number of lines that can be represented by the {@link Spannable}
* element. If not defined, the {@link Spannable} element will be treated as a
@@ -2282,6 +2583,7 @@
@NonNull
public Builder setMaxLines(@IntRange(from = 1) int maxLines) {
mImpl.setMaxLines(TypesProto.Int32Prop.newBuilder().setValue(maxLines));
+ mFingerprint.recordPropertyUpdate(3, maxLines);
return this;
}
@@ -2296,8 +2598,11 @@
public Builder setMultilineAlignment(
@NonNull HorizontalAlignmentProp multilineAlignment) {
mImpl.setMultilineAlignment(multilineAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(multilineAlignment.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets alignment of the {@link Spannable} content within its bounds. Note that a {@link
* Spannable} element will size itself to wrap its contents, so this option is
@@ -2312,6 +2617,7 @@
.setValue(
AlignmentProto.HorizontalAlignment.forNumber(
multilineAlignment)));
+ mFingerprint.recordPropertyUpdate(4, multilineAlignment);
return this;
}
@@ -2325,8 +2631,11 @@
@NonNull
public Builder setOverflow(@NonNull TextOverflowProp overflow) {
mImpl.setOverflow(overflow.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(overflow.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets how to handle content which overflows the bound of the {@link Spannable}
* element. A {@link Spannable} element will grow as large as possible inside its parent
@@ -2339,6 +2648,7 @@
mImpl.setOverflow(
LayoutElementProto.TextOverflowProp.newBuilder()
.setValue(LayoutElementProto.TextOverflow.forNumber(overflow)));
+ mFingerprint.recordPropertyUpdate(5, overflow);
return this;
}
@@ -2350,13 +2660,15 @@
@NonNull
public Builder setLineHeight(@NonNull DimensionBuilders.SpProp lineHeight) {
mImpl.setLineHeight(lineHeight.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 7, checkNotNull(lineHeight.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public Spannable build() {
- return Spannable.fromProto(mImpl.build());
+ return new Spannable(mImpl.build(), mFingerprint);
}
}
}
@@ -2373,9 +2685,11 @@
*/
public static final class Column implements LayoutElement {
private final LayoutElementProto.Column mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Column(LayoutElementProto.Column impl) {
+ Column(LayoutElementProto.Column impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -2386,7 +2700,7 @@
public List<LayoutElement> getContents() {
return Collections.unmodifiableList(
mImpl.getContentsList().stream()
- .map(LayoutElement::fromLayoutElementProto)
+ .map(LayoutElementBuilders::layoutElementFromProto)
.collect(toList()));
}
@@ -2411,7 +2725,7 @@
@Nullable
public DimensionBuilders.ContainerDimension getWidth() {
if (mImpl.hasWidth()) {
- return DimensionBuilders.ContainerDimension.fromContainerDimensionProto(
+ return DimensionBuilders.containerDimensionFromProto(
mImpl.getWidth());
} else {
return null;
@@ -2425,7 +2739,7 @@
@Nullable
public DimensionBuilders.ContainerDimension getHeight() {
if (mImpl.hasHeight()) {
- return DimensionBuilders.ContainerDimension.fromContainerDimensionProto(
+ return DimensionBuilders.containerDimensionFromProto(
mImpl.getHeight());
} else {
return null;
@@ -2445,13 +2759,19 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Column fromProto(@NonNull LayoutElementProto.Column proto) {
- return new Column(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static Column fromProto(
+ @NonNull LayoutElementProto.Column proto, @Nullable Fingerprint fingerprint) {
+ return new Column(proto, fingerprint);
+ }
+
@NonNull
LayoutElementProto.Column toProto() {
return mImpl;
@@ -2468,6 +2788,7 @@
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Column.Builder mImpl =
LayoutElementProto.Column.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1411218529);
public Builder() {}
@@ -2475,6 +2796,7 @@
@NonNull
public Builder addContent(@NonNull LayoutElement content) {
mImpl.addContents(content.toLayoutElementProto());
+ mFingerprint.addChildNode(checkNotNull(content.getFingerprint()));
return this;
}
@@ -2487,8 +2809,12 @@
public Builder setHorizontalAlignment(
@NonNull HorizontalAlignmentProp horizontalAlignment) {
mImpl.setHorizontalAlignment(horizontalAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2,
+ checkNotNull(horizontalAlignment.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the horizontal alignment of elements inside this column, if they are narrower
* than the resulting width of the column. If not defined, defaults to
@@ -2501,6 +2827,7 @@
.setValue(
AlignmentProto.HorizontalAlignment.forNumber(
horizontalAlignment)));
+ mFingerprint.recordPropertyUpdate(2, horizontalAlignment);
return this;
}
@@ -2511,6 +2838,8 @@
@NonNull
public Builder setWidth(@NonNull DimensionBuilders.ContainerDimension width) {
mImpl.setWidth(width.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -2521,6 +2850,8 @@
@NonNull
public Builder setHeight(@NonNull DimensionBuilders.ContainerDimension height) {
mImpl.setHeight(height.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -2528,13 +2859,15 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.Modifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public Column build() {
- return Column.fromProto(mImpl.build());
+ return new Column(mImpl.build(), mFingerprint);
}
}
}
@@ -2551,9 +2884,11 @@
*/
public static final class Row implements LayoutElement {
private final LayoutElementProto.Row mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Row(LayoutElementProto.Row impl) {
+ Row(LayoutElementProto.Row impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -2564,7 +2899,7 @@
public List<LayoutElement> getContents() {
return Collections.unmodifiableList(
mImpl.getContentsList().stream()
- .map(LayoutElement::fromLayoutElementProto)
+ .map(LayoutElementBuilders::layoutElementFromProto)
.collect(toList()));
}
@@ -2589,7 +2924,7 @@
@Nullable
public DimensionBuilders.ContainerDimension getWidth() {
if (mImpl.hasWidth()) {
- return DimensionBuilders.ContainerDimension.fromContainerDimensionProto(
+ return DimensionBuilders.containerDimensionFromProto(
mImpl.getWidth());
} else {
return null;
@@ -2603,7 +2938,7 @@
@Nullable
public DimensionBuilders.ContainerDimension getHeight() {
if (mImpl.hasHeight()) {
- return DimensionBuilders.ContainerDimension.fromContainerDimensionProto(
+ return DimensionBuilders.containerDimensionFromProto(
mImpl.getHeight());
} else {
return null;
@@ -2623,13 +2958,19 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Row fromProto(@NonNull LayoutElementProto.Row proto) {
- return new Row(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static Row fromProto(
+ @NonNull LayoutElementProto.Row proto, @Nullable Fingerprint fingerprint) {
+ return new Row(proto, fingerprint);
+ }
+
@NonNull
LayoutElementProto.Row toProto() {
return mImpl;
@@ -2646,6 +2987,7 @@
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Row.Builder mImpl =
LayoutElementProto.Row.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1537205448);
public Builder() {}
@@ -2653,6 +2995,7 @@
@NonNull
public Builder addContent(@NonNull LayoutElement content) {
mImpl.addContents(content.toLayoutElementProto());
+ mFingerprint.addChildNode(checkNotNull(content.getFingerprint()));
return this;
}
@@ -2663,8 +3006,11 @@
@NonNull
public Builder setVerticalAlignment(@NonNull VerticalAlignmentProp verticalAlignment) {
mImpl.setVerticalAlignment(verticalAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(verticalAlignment.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets the vertical alignment of elements inside this row, if they are narrower than
* the resulting height of the row. If not defined, defaults to VERTICAL_ALIGN_CENTER.
@@ -2676,6 +3022,7 @@
.setValue(
AlignmentProto.VerticalAlignment.forNumber(
verticalAlignment)));
+ mFingerprint.recordPropertyUpdate(2, verticalAlignment);
return this;
}
@@ -2686,6 +3033,8 @@
@NonNull
public Builder setWidth(@NonNull DimensionBuilders.ContainerDimension width) {
mImpl.setWidth(width.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -2696,6 +3045,8 @@
@NonNull
public Builder setHeight(@NonNull DimensionBuilders.ContainerDimension height) {
mImpl.setHeight(height.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -2703,13 +3054,15 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.Modifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public Row build() {
- return Row.fromProto(mImpl.build());
+ return new Row(mImpl.build(), mFingerprint);
}
}
}
@@ -2721,9 +3074,11 @@
*/
public static final class Arc implements LayoutElement {
private final LayoutElementProto.Arc mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Arc(LayoutElementProto.Arc impl) {
+ Arc(LayoutElementProto.Arc impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets contents of this container. Intended for testing purposes only. */
@@ -2731,7 +3086,7 @@
public List<ArcLayoutElement> getContents() {
return Collections.unmodifiableList(
mImpl.getContentsList().stream()
- .map(ArcLayoutElement::fromArcLayoutElementProto)
+ .map(LayoutElementBuilders::arcLayoutElementFromProto)
.collect(toList()));
}
@@ -2794,13 +3149,19 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Arc fromProto(@NonNull LayoutElementProto.Arc proto) {
- return new Arc(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static Arc fromProto(
+ @NonNull LayoutElementProto.Arc proto, @Nullable Fingerprint fingerprint) {
+ return new Arc(proto, fingerprint);
+ }
+
@NonNull
LayoutElementProto.Arc toProto() {
return mImpl;
@@ -2817,6 +3178,7 @@
public static final class Builder implements LayoutElement.Builder {
private final LayoutElementProto.Arc.Builder mImpl =
LayoutElementProto.Arc.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(299028337);
public Builder() {}
@@ -2824,6 +3186,7 @@
@NonNull
public Builder addContent(@NonNull ArcLayoutElement content) {
mImpl.addContents(content.toArcLayoutElementProto());
+ mFingerprint.addChildNode(checkNotNull(content.getFingerprint()));
return this;
}
@@ -2839,6 +3202,8 @@
@NonNull
public Builder setAnchorAngle(@NonNull DimensionBuilders.DegreesProp anchorAngle) {
mImpl.setAnchorAngle(anchorAngle.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(anchorAngle.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -2849,8 +3214,11 @@
@NonNull
public Builder setAnchorType(@NonNull ArcAnchorTypeProp anchorType) {
mImpl.setAnchorType(anchorType.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(anchorType.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets how to align the contents of this container relative to anchor_angle. If not
* defined, defaults to ARC_ANCHOR_CENTER.
@@ -2860,6 +3228,7 @@
mImpl.setAnchorType(
AlignmentProto.ArcAnchorTypeProp.newBuilder()
.setValue(AlignmentProto.ArcAnchorType.forNumber(anchorType)));
+ mFingerprint.recordPropertyUpdate(3, anchorType);
return this;
}
@@ -2872,8 +3241,11 @@
@NonNull
public Builder setVerticalAlign(@NonNull VerticalAlignmentProp verticalAlign) {
mImpl.setVerticalAlign(verticalAlign.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(verticalAlign.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets vertical alignment of elements within the arc. If the {@link Arc}'s thickness is
* larger than the thickness of the element being drawn, this controls whether the
@@ -2886,6 +3258,7 @@
AlignmentProto.VerticalAlignmentProp.newBuilder()
.setValue(
AlignmentProto.VerticalAlignment.forNumber(verticalAlign)));
+ mFingerprint.recordPropertyUpdate(4, verticalAlign);
return this;
}
@@ -2893,13 +3266,15 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.Modifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public Arc build() {
- return Arc.fromProto(mImpl.build());
+ return new Arc(mImpl.build(), mFingerprint);
}
}
}
@@ -2907,9 +3282,11 @@
/** A text element that can be used in an {@link Arc}. */
public static final class ArcText implements ArcLayoutElement {
private final LayoutElementProto.ArcText mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ArcText(LayoutElementProto.ArcText impl) {
+ ArcText(LayoutElementProto.ArcText impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the text to render. Intended for testing purposes only. */
@@ -2948,13 +3325,18 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static ArcText fromProto(@NonNull LayoutElementProto.ArcText proto) {
- return new ArcText(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static ArcText fromProto(@NonNull LayoutElementProto.ArcText proto) {
+ return new ArcText(proto, null);
+ }
+
@NonNull
LayoutElementProto.ArcText toProto() {
return mImpl;
@@ -2971,6 +3353,7 @@
public static final class Builder implements ArcLayoutElement.Builder {
private final LayoutElementProto.ArcText.Builder mImpl =
LayoutElementProto.ArcText.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(434391973);
public Builder() {}
@@ -2978,12 +3361,16 @@
@NonNull
public Builder setText(@NonNull TypeBuilders.StringProp text) {
mImpl.setText(text.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(text.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/** Sets the text to render. */
@NonNull
public Builder setText(@NonNull String text) {
mImpl.setText(TypesProto.StringProp.newBuilder().setValue(text));
+ mFingerprint.recordPropertyUpdate(1, text.hashCode());
return this;
}
@@ -2994,6 +3381,8 @@
@NonNull
public Builder setFontStyle(@NonNull FontStyle fontStyle) {
mImpl.setFontStyle(fontStyle.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(fontStyle.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -3001,13 +3390,15 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.ArcModifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public ArcText build() {
- return ArcText.fromProto(mImpl.build());
+ return new ArcText(mImpl.build(), mFingerprint);
}
}
}
@@ -3015,9 +3406,11 @@
/** A line that can be used in an {@link Arc} and renders as a round progress bar. */
public static final class ArcLine implements ArcLayoutElement {
private final LayoutElementProto.ArcLine mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ArcLine(LayoutElementProto.ArcLine impl) {
+ ArcLine(LayoutElementProto.ArcLine impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -3069,13 +3462,18 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static ArcLine fromProto(@NonNull LayoutElementProto.ArcLine proto) {
- return new ArcLine(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static ArcLine fromProto(@NonNull LayoutElementProto.ArcLine proto) {
+ return new ArcLine(proto, null);
+ }
+
@NonNull
LayoutElementProto.ArcLine toProto() {
return mImpl;
@@ -3092,6 +3490,7 @@
public static final class Builder implements ArcLayoutElement.Builder {
private final LayoutElementProto.ArcLine.Builder mImpl =
LayoutElementProto.ArcLine.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1371793535);
public Builder() {}
@@ -3099,6 +3498,8 @@
@NonNull
public Builder setLength(@NonNull DimensionBuilders.DegreesProp length) {
mImpl.setLength(length.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(length.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -3106,6 +3507,8 @@
@NonNull
public Builder setThickness(@NonNull DimensionBuilders.DpProp thickness) {
mImpl.setThickness(thickness.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(thickness.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -3113,6 +3516,8 @@
@NonNull
public Builder setColor(@NonNull ColorBuilders.ColorProp color) {
mImpl.setColor(color.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(color.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -3120,13 +3525,15 @@
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.ArcModifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public ArcLine build() {
- return ArcLine.fromProto(mImpl.build());
+ return new ArcLine(mImpl.build(), mFingerprint);
}
}
}
@@ -3134,9 +3541,11 @@
/** A simple spacer used to provide padding between adjacent elements in an {@link Arc}. */
public static final class ArcSpacer implements ArcLayoutElement {
private final LayoutElementProto.ArcSpacer mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ArcSpacer(LayoutElementProto.ArcSpacer impl) {
+ ArcSpacer(LayoutElementProto.ArcSpacer impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -3178,13 +3587,18 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static ArcSpacer fromProto(@NonNull LayoutElementProto.ArcSpacer proto) {
- return new ArcSpacer(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static ArcSpacer fromProto(@NonNull LayoutElementProto.ArcSpacer proto) {
+ return new ArcSpacer(proto, null);
+ }
+
@NonNull
LayoutElementProto.ArcSpacer toProto() {
return mImpl;
@@ -3201,6 +3615,7 @@
public static final class Builder implements ArcLayoutElement.Builder {
private final LayoutElementProto.ArcSpacer.Builder mImpl =
LayoutElementProto.ArcSpacer.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-179760535);
public Builder() {}
@@ -3208,27 +3623,34 @@
@NonNull
public Builder setLength(@NonNull DimensionBuilders.DegreesProp length) {
mImpl.setLength(length.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(length.getFingerprint()).aggregateValueAsInt());
return this;
}
/** Sets the thickness of this spacer, in DP. If not defined, defaults to 0. */
@NonNull
public Builder setThickness(@NonNull DimensionBuilders.DpProp thickness) {
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(thickness.getFingerprint()).aggregateValueAsInt());
mImpl.setThickness(thickness.toProto());
return this;
}
+
/** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
@NonNull
public Builder setModifiers(@NonNull ModifiersBuilders.ArcModifiers modifiers) {
mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public ArcSpacer build() {
- return ArcSpacer.fromProto(mImpl.build());
+ return new ArcSpacer(mImpl.build(), mFingerprint);
}
}
}
@@ -3236,16 +3658,18 @@
/** A container that allows a standard {@link LayoutElement} to be added to an {@link Arc}. */
public static final class ArcAdapter implements ArcLayoutElement {
private final LayoutElementProto.ArcAdapter mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ArcAdapter(LayoutElementProto.ArcAdapter impl) {
+ ArcAdapter(LayoutElementProto.ArcAdapter impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the element to adapt to an {@link Arc}. Intended for testing purposes only. */
@Nullable
public LayoutElement getContent() {
if (mImpl.hasContent()) {
- return LayoutElement.fromLayoutElementProto(mImpl.getContent());
+ return LayoutElementBuilders.layoutElementFromProto(mImpl.getContent());
} else {
return null;
}
@@ -3269,13 +3693,18 @@
}
}
+ @Override
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static ArcAdapter fromProto(@NonNull LayoutElementProto.ArcAdapter proto) {
- return new ArcAdapter(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static ArcAdapter fromProto(@NonNull LayoutElementProto.ArcAdapter proto) {
+ return new ArcAdapter(proto, null);
+ }
+
@NonNull
LayoutElementProto.ArcAdapter toProto() {
return mImpl;
@@ -3292,6 +3721,7 @@
public static final class Builder implements ArcLayoutElement.Builder {
private final LayoutElementProto.ArcAdapter.Builder mImpl =
LayoutElementProto.ArcAdapter.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1696473935);
public Builder() {}
@@ -3299,6 +3729,7 @@
@NonNull
public Builder setContent(@NonNull LayoutElement content) {
mImpl.setContent(content.toLayoutElementProto());
+ mFingerprint.addChildNode(checkNotNull(content.getFingerprint()));
return this;
}
@@ -3313,8 +3744,11 @@
@NonNull
public Builder setRotateContents(@NonNull TypeBuilders.BoolProp rotateContents) {
mImpl.setRotateContents(rotateContents.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(rotateContents.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets whether this adapter's contents should be rotated, according to its position in
* the arc or not. As an example, assume that an {@link Image} has been added to the
@@ -3327,13 +3761,14 @@
@NonNull
public Builder setRotateContents(boolean rotateContents) {
mImpl.setRotateContents(TypesProto.BoolProp.newBuilder().setValue(rotateContents));
+ mFingerprint.recordPropertyUpdate(2, Boolean.hashCode(rotateContents));
return this;
}
@Override
@NonNull
public ArcAdapter build() {
- return ArcAdapter.fromProto(mImpl.build());
+ return new ArcAdapter(mImpl.build(), mFingerprint);
}
}
}
@@ -3348,40 +3783,10 @@
@NonNull
LayoutElementProto.LayoutElement toLayoutElementProto();
- /**
- * Return an instance of one of this object's subtypes, from the protocol buffer
- * representation.
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- static LayoutElement fromLayoutElementProto(
- @NonNull LayoutElementProto.LayoutElement proto) {
- if (proto.hasColumn()) {
- return Column.fromProto(proto.getColumn());
- }
- if (proto.hasRow()) {
- return Row.fromProto(proto.getRow());
- }
- if (proto.hasBox()) {
- return Box.fromProto(proto.getBox());
- }
- if (proto.hasSpacer()) {
- return Spacer.fromProto(proto.getSpacer());
- }
- if (proto.hasText()) {
- return Text.fromProto(proto.getText());
- }
- if (proto.hasImage()) {
- return Image.fromProto(proto.getImage());
- }
- if (proto.hasArc()) {
- return Arc.fromProto(proto.getArc());
- }
- if (proto.hasSpannable()) {
- return Spannable.fromProto(proto.getSpannable());
- }
- throw new IllegalStateException("Proto was not a recognised instance of LayoutElement");
- }
+ @Nullable
+ Fingerprint getFingerprint();
/** Builder to create {@link LayoutElement} objects. */
@SuppressLint("StaticFinalBuilder")
@@ -3393,6 +3798,43 @@
}
}
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public static LayoutElement layoutElementFromProto(
+ @NonNull LayoutElementProto.LayoutElement proto, @Nullable Fingerprint fingerprint) {
+ if (proto.hasColumn()) {
+ return Column.fromProto(proto.getColumn(), fingerprint);
+ }
+ if (proto.hasRow()) {
+ return Row.fromProto(proto.getRow(), fingerprint);
+ }
+ if (proto.hasBox()) {
+ return Box.fromProto(proto.getBox(), fingerprint);
+ }
+ if (proto.hasSpacer()) {
+ return Spacer.fromProto(proto.getSpacer(), fingerprint);
+ }
+ if (proto.hasText()) {
+ return Text.fromProto(proto.getText(), fingerprint);
+ }
+ if (proto.hasImage()) {
+ return Image.fromProto(proto.getImage(), fingerprint);
+ }
+ if (proto.hasArc()) {
+ return Arc.fromProto(proto.getArc(), fingerprint);
+ }
+ if (proto.hasSpannable()) {
+ return Spannable.fromProto(proto.getSpannable(), fingerprint);
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of LayoutElement");
+ }
+
+ @NonNull
+ static LayoutElement layoutElementFromProto(@NonNull LayoutElementProto.LayoutElement proto) {
+ return layoutElementFromProto(proto, null);
+ }
+
/**
* Interface defining the root of all elements that can be used in an {@link Arc}. This exists
* to act as a holder for all of the actual arc layout elements above.
@@ -3403,29 +3845,10 @@
@NonNull
LayoutElementProto.ArcLayoutElement toArcLayoutElementProto();
- /**
- * Return an instance of one of this object's subtypes, from the protocol buffer
- * representation.
- */
+ /** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- static ArcLayoutElement fromArcLayoutElementProto(
- @NonNull LayoutElementProto.ArcLayoutElement proto) {
- if (proto.hasText()) {
- return ArcText.fromProto(proto.getText());
- }
- if (proto.hasLine()) {
- return ArcLine.fromProto(proto.getLine());
- }
- if (proto.hasSpacer()) {
- return ArcSpacer.fromProto(proto.getSpacer());
- }
- if (proto.hasAdapter()) {
- return ArcAdapter.fromProto(proto.getAdapter());
- }
- throw new IllegalStateException(
- "Proto was not a recognised instance of ArcLayoutElement");
- }
+ @Nullable
+ Fingerprint getFingerprint();
/** Builder to create {@link ArcLayoutElement} objects. */
@SuppressLint("StaticFinalBuilder")
@@ -3437,6 +3860,24 @@
}
}
+ @NonNull
+ static ArcLayoutElement arcLayoutElementFromProto(
+ @NonNull LayoutElementProto.ArcLayoutElement proto) {
+ if (proto.hasText()) {
+ return ArcText.fromProto(proto.getText());
+ }
+ if (proto.hasLine()) {
+ return ArcLine.fromProto(proto.getLine());
+ }
+ if (proto.hasSpacer()) {
+ return ArcSpacer.fromProto(proto.getSpacer());
+ }
+ if (proto.hasAdapter()) {
+ return ArcAdapter.fromProto(proto.getAdapter());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of ArcLayoutElement");
+ }
+
/** A complete layout. */
public static final class Layout {
private final LayoutElementProto.Layout mImpl;
@@ -3449,7 +3890,7 @@
@Nullable
public LayoutElement getRoot() {
if (mImpl.hasRoot()) {
- return LayoutElement.fromLayoutElementProto(mImpl.getRoot());
+ return LayoutElementBuilders.layoutElementFromProto(mImpl.getRoot());
} else {
return null;
}
@@ -3461,12 +3902,13 @@
return new Layout(proto);
}
- /** Returns the {@link Layout} object containing the given layout element. */
+ /** Creates a {@link Layout} object containing the given layout element. */
@NonNull
public static Layout fromLayoutElement(@NonNull LayoutElement layoutElement) {
return new Builder().setRoot(layoutElement).build();
}
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public LayoutElementProto.Layout toProto() {
@@ -3502,9 +3944,33 @@
@NonNull
public Builder setRoot(@NonNull LayoutElement root) {
mImpl.setRoot(root.toLayoutElementProto());
+ @Nullable Fingerprint fingerprint = root.getFingerprint();
+ if (fingerprint != null) {
+ mImpl.setFingerprint(
+ TreeFingerprint.newBuilder().setRoot(fingerprintToProto(fingerprint)));
+ }
return this;
}
+ private static FingerprintProto.NodeFingerprint fingerprintToProto(
+ Fingerprint fingerprint) {
+ FingerprintProto.NodeFingerprint.Builder builder =
+ FingerprintProto.NodeFingerprint.newBuilder();
+ if (fingerprint.selfTypeValue() != 0) {
+ builder.setSelfTypeValue(fingerprint.selfTypeValue());
+ }
+ if (fingerprint.selfPropsValue() != 0) {
+ builder.setSelfPropsValue(fingerprint.selfPropsValue());
+ }
+ if (fingerprint.childNodesValue() != 0) {
+ builder.setChildNodesValue(fingerprint.childNodesValue());
+ }
+ for (Fingerprint childNode : fingerprint.childNodes()) {
+ builder.addChildNodes(fingerprintToProto(childNode));
+ }
+ return builder.build();
+ }
+
/** Builds an instance from accumulated values. */
@NonNull
public Layout build() {
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ModifiersBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ModifiersBuilders.java
index 8be19c7..9c8c51e 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ModifiersBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ModifiersBuilders.java
@@ -16,16 +16,21 @@
package androidx.wear.tiles;
+import static androidx.wear.protolayout.expression.Preconditions.checkNotNull;
+
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.ModifiersProto;
import androidx.wear.protolayout.proto.TypesProto;
import androidx.wear.protolayout.protobuf.ByteString;
+import java.util.Arrays;
+
/**
* Builders for modifiers for composable layout elements.
*
@@ -41,9 +46,11 @@
*/
public static final class Clickable {
private final ModifiersProto.Clickable mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Clickable(ModifiersProto.Clickable impl) {
+ Clickable(ModifiersProto.Clickable impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the ID associated with this action. Intended for testing purposes only. */
@@ -59,18 +66,25 @@
@Nullable
public ActionBuilders.Action getOnClick() {
if (mImpl.hasOnClick()) {
- return ActionBuilders.Action.fromActionProto(mImpl.getOnClick());
+ return ActionBuilders.actionFromProto(mImpl.getOnClick());
} else {
return null;
}
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Clickable fromProto(@NonNull ModifiersProto.Clickable proto) {
- return new Clickable(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
+ @NonNull
+ static Clickable fromProto(@NonNull ModifiersProto.Clickable proto) {
+ return new Clickable(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ModifiersProto.Clickable toProto() {
@@ -81,6 +95,7 @@
public static final class Builder {
private final ModifiersProto.Clickable.Builder mImpl =
ModifiersProto.Clickable.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(595587995);
public Builder() {}
@@ -88,6 +103,7 @@
@NonNull
public Builder setId(@NonNull String id) {
mImpl.setId(id);
+ mFingerprint.recordPropertyUpdate(1, id.hashCode());
return this;
}
@@ -97,13 +113,15 @@
@NonNull
public Builder setOnClick(@NonNull ActionBuilders.Action onClick) {
mImpl.setOnClick(onClick.toActionProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(onClick.getFingerprint()).aggregateValueAsInt());
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public Clickable build() {
- return Clickable.fromProto(mImpl.build());
+ return new Clickable(mImpl.build(), mFingerprint);
}
}
}
@@ -115,9 +133,11 @@
*/
public static final class Semantics {
private final ModifiersProto.Semantics mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Semantics(ModifiersProto.Semantics impl) {
+ Semantics(ModifiersProto.Semantics impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -129,15 +149,20 @@
return mImpl.getObsoleteContentDescription();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Semantics fromProto(@NonNull ModifiersProto.Semantics proto) {
- return new Semantics(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public ModifiersProto.Semantics toProto() {
+ static Semantics fromProto(@NonNull ModifiersProto.Semantics proto) {
+ return new Semantics(proto, null);
+ }
+
+ @NonNull
+ ModifiersProto.Semantics toProto() {
return mImpl;
}
@@ -145,6 +170,7 @@
public static final class Builder {
private final ModifiersProto.Semantics.Builder mImpl =
ModifiersProto.Semantics.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1479823155);
public Builder() {}
@@ -153,15 +179,18 @@
* the element is focused by the screen reader.
*/
@NonNull
+ @SuppressWarnings(
+ "deprecation") // Updating a deprecated field for backward compatibility
public Builder setContentDescription(@NonNull String contentDescription) {
mImpl.setObsoleteContentDescription(contentDescription);
+ mFingerprint.recordPropertyUpdate(4, contentDescription.hashCode());
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public Semantics build() {
- return Semantics.fromProto(mImpl.build());
+ return new Semantics(mImpl.build(), mFingerprint);
}
}
}
@@ -169,9 +198,11 @@
/** A modifier to apply padding around an element. */
public static final class Padding {
private final ModifiersProto.Padding mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Padding(ModifiersProto.Padding impl) {
+ Padding(ModifiersProto.Padding impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -235,15 +266,20 @@
}
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Padding fromProto(@NonNull ModifiersProto.Padding proto) {
- return new Padding(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public ModifiersProto.Padding toProto() {
+ static Padding fromProto(@NonNull ModifiersProto.Padding proto) {
+ return new Padding(proto, null);
+ }
+
+ @NonNull
+ ModifiersProto.Padding toProto() {
return mImpl;
}
@@ -251,6 +287,7 @@
public static final class Builder {
private final ModifiersProto.Padding.Builder mImpl =
ModifiersProto.Padding.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1120275440);
public Builder() {}
@@ -261,6 +298,8 @@
@NonNull
public Builder setEnd(@NonNull DimensionBuilders.DpProp end) {
mImpl.setEnd(end.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(end.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -271,6 +310,8 @@
@NonNull
public Builder setStart(@NonNull DimensionBuilders.DpProp start) {
mImpl.setStart(start.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(start.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -278,6 +319,8 @@
@NonNull
public Builder setTop(@NonNull DimensionBuilders.DpProp top) {
mImpl.setTop(top.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(top.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -285,6 +328,8 @@
@NonNull
public Builder setBottom(@NonNull DimensionBuilders.DpProp bottom) {
mImpl.setBottom(bottom.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(bottom.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -297,8 +342,11 @@
@NonNull
public Builder setRtlAware(@NonNull TypeBuilders.BoolProp rtlAware) {
mImpl.setRtlAware(rtlAware.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(rtlAware.getFingerprint()).aggregateValueAsInt());
return this;
}
+
/**
* Sets whether the start/end padding is aware of RTL support. If true, the values for
* start/end will follow the layout direction (i.e. start will refer to the right hand
@@ -309,6 +357,7 @@
@NonNull
public Builder setRtlAware(boolean rtlAware) {
mImpl.setRtlAware(TypesProto.BoolProp.newBuilder().setValue(rtlAware));
+ mFingerprint.recordPropertyUpdate(5, Boolean.hashCode(rtlAware));
return this;
}
@@ -322,7 +371,7 @@
/** Builds an instance from accumulated values. */
@NonNull
public Padding build() {
- return Padding.fromProto(mImpl.build());
+ return new Padding(mImpl.build(), mFingerprint);
}
}
}
@@ -330,9 +379,11 @@
/** A modifier to apply a border around an element. */
public static final class Border {
private final ModifiersProto.Border mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Border(ModifiersProto.Border impl) {
+ Border(ModifiersProto.Border impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the width of the border, in DP. Intended for testing purposes only. */
@@ -355,21 +406,27 @@
}
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Border fromProto(@NonNull ModifiersProto.Border proto) {
- return new Border(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public ModifiersProto.Border toProto() {
+ static Border fromProto(@NonNull ModifiersProto.Border proto) {
+ return new Border(proto, null);
+ }
+
+ @NonNull
+ ModifiersProto.Border toProto() {
return mImpl;
}
/** Builder for {@link Border} */
public static final class Builder {
private final ModifiersProto.Border.Builder mImpl = ModifiersProto.Border.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(2085330827);
public Builder() {}
@@ -377,6 +434,8 @@
@NonNull
public Builder setWidth(@NonNull DimensionBuilders.DpProp width) {
mImpl.setWidth(width.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -384,13 +443,15 @@
@NonNull
public Builder setColor(@NonNull ColorBuilders.ColorProp color) {
mImpl.setColor(color.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(color.getFingerprint()).aggregateValueAsInt());
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public Border build() {
- return Border.fromProto(mImpl.build());
+ return new Border(mImpl.build(), mFingerprint);
}
}
}
@@ -398,9 +459,11 @@
/** The corner of a {@link androidx.wear.tiles.LayoutElementBuilders.Box} element. */
public static final class Corner {
private final ModifiersProto.Corner mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Corner(ModifiersProto.Corner impl) {
+ Corner(ModifiersProto.Corner impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the radius of the corner in DP. Intended for testing purposes only. */
@@ -413,21 +476,27 @@
}
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Corner fromProto(@NonNull ModifiersProto.Corner proto) {
- return new Corner(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public ModifiersProto.Corner toProto() {
+ static Corner fromProto(@NonNull ModifiersProto.Corner proto) {
+ return new Corner(proto, null);
+ }
+
+ @NonNull
+ ModifiersProto.Corner toProto() {
return mImpl;
}
/** Builder for {@link Corner} */
public static final class Builder {
private final ModifiersProto.Corner.Builder mImpl = ModifiersProto.Corner.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-623478338);
public Builder() {}
@@ -435,13 +504,15 @@
@NonNull
public Builder setRadius(@NonNull DimensionBuilders.DpProp radius) {
mImpl.setRadius(radius.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(radius.getFingerprint()).aggregateValueAsInt());
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public Corner build() {
- return Corner.fromProto(mImpl.build());
+ return new Corner(mImpl.build(), mFingerprint);
}
}
}
@@ -449,9 +520,11 @@
/** A modifier to apply a background to an element. */
public static final class Background {
private final ModifiersProto.Background mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Background(ModifiersProto.Background impl) {
+ Background(ModifiersProto.Background impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -481,15 +554,20 @@
}
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Background fromProto(@NonNull ModifiersProto.Background proto) {
- return new Background(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public ModifiersProto.Background toProto() {
+ static Background fromProto(@NonNull ModifiersProto.Background proto) {
+ return new Background(proto, null);
+ }
+
+ @NonNull
+ ModifiersProto.Background toProto() {
return mImpl;
}
@@ -497,6 +575,7 @@
public static final class Builder {
private final ModifiersProto.Background.Builder mImpl =
ModifiersProto.Background.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(374507572);
public Builder() {}
@@ -507,6 +586,8 @@
@NonNull
public Builder setColor(@NonNull ColorBuilders.ColorProp color) {
mImpl.setColor(color.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(color.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -518,13 +599,15 @@
@NonNull
public Builder setCorner(@NonNull Corner corner) {
mImpl.setCorner(corner.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(corner.getFingerprint()).aggregateValueAsInt());
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public Background build() {
- return Background.fromProto(mImpl.build());
+ return new Background(mImpl.build(), mFingerprint);
}
}
}
@@ -535,9 +618,12 @@
*/
public static final class ElementMetadata {
private final ModifiersProto.ElementMetadata mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ElementMetadata(ModifiersProto.ElementMetadata impl) {
+ ElementMetadata(
+ ModifiersProto.ElementMetadata impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -549,12 +635,19 @@
return mImpl.getTagData().toByteArray();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static ElementMetadata fromProto(@NonNull ModifiersProto.ElementMetadata proto) {
- return new ElementMetadata(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
+ @NonNull
+ static ElementMetadata fromProto(@NonNull ModifiersProto.ElementMetadata proto) {
+ return new ElementMetadata(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ModifiersProto.ElementMetadata toProto() {
@@ -565,6 +658,7 @@
public static final class Builder {
private final ModifiersProto.ElementMetadata.Builder mImpl =
ModifiersProto.ElementMetadata.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-589294723);
public Builder() {}
@@ -576,13 +670,14 @@
@NonNull
public Builder setTagData(@NonNull byte[] tagData) {
mImpl.setTagData(ByteString.copyFrom(tagData));
+ mFingerprint.recordPropertyUpdate(1, Arrays.hashCode(tagData));
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public ElementMetadata build() {
- return ElementMetadata.fromProto(mImpl.build());
+ return new ElementMetadata(mImpl.build(), mFingerprint);
}
}
}
@@ -594,14 +689,17 @@
*/
public static final class Modifiers {
private final ModifiersProto.Modifiers mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Modifiers(ModifiersProto.Modifiers impl) {
+ Modifiers(ModifiersProto.Modifiers impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
- * Gets allows its wrapped element to have actions associated with it, which will be
- * executed when the element is tapped. Intended for testing purposes only.
+ * Gets the clickable property of the modified element. It allows its wrapped element to
+ * have actions associated with it, which will be executed when the element is tapped.
+ * Intended for testing purposes only.
*/
@Nullable
public Clickable getClickable() {
@@ -613,8 +711,9 @@
}
/**
- * Gets adds metadata for the modified element, for example, screen reader content
- * descriptions. Intended for testing purposes only.
+ * Gets the semantics of the modified element. This can be used to add metadata to the
+ * modified element (eg. screen reader content descriptions). Intended for testing purposes
+ * only.
*/
@Nullable
public Semantics getSemantics() {
@@ -625,7 +724,7 @@
}
}
- /** Gets adds padding to the modified element. Intended for testing purposes only. */
+ /** Gets the padding of the modified element. Intended for testing purposes only. */
@Nullable
public Padding getPadding() {
if (mImpl.hasPadding()) {
@@ -635,7 +734,7 @@
}
}
- /** Gets draws a border around the modified element. Intended for testing purposes only. */
+ /** Gets the border of the modified element. Intended for testing purposes only. */
@Nullable
public Border getBorder() {
if (mImpl.hasBorder()) {
@@ -646,8 +745,8 @@
}
/**
- * Gets adds a background (with optional corner radius) to the modified element. Intended
- * for testing purposes only.
+ * Gets the background (with optional corner radius) of the modified element. Intended for
+ * testing purposes only.
*/
@Nullable
public Background getBackground() {
@@ -671,12 +770,32 @@
}
}
+ /** Get the fingerprint for this object, or null if unknown. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public static Modifiers fromProto(
+ @NonNull ModifiersProto.Modifiers proto, @Nullable Fingerprint fingerprint) {
+ return new Modifiers(proto, fingerprint);
+ }
+
+ /**
+ * Creates a new wrapper instance from the proto. Intended for testing purposes only. An
+ * object created using this method can't be added to any other wrapper.
+ */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static Modifiers fromProto(@NonNull ModifiersProto.Modifiers proto) {
- return new Modifiers(proto);
+ return fromProto(proto, null);
}
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ModifiersProto.Modifiers toProto() {
@@ -687,47 +806,58 @@
public static final class Builder {
private final ModifiersProto.Modifiers.Builder mImpl =
ModifiersProto.Modifiers.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-170942531);
public Builder() {}
/**
- * Sets allows its wrapped element to have actions associated with it, which will be
- * executed when the element is tapped.
+ * Sets the clickable property of the modified element. It allows its wrapped element to
+ * have actions associated with it, which will be executed when the element is tapped.
*/
@NonNull
public Builder setClickable(@NonNull Clickable clickable) {
mImpl.setClickable(clickable.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(clickable.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
- * Sets adds metadata for the modified element, for example, screen reader content
- * descriptions.
+ * Sets the semantics of the modified element. This can be used to add metadata to the
+ * modified element (eg. screen reader content descriptions).
*/
@NonNull
public Builder setSemantics(@NonNull Semantics semantics) {
mImpl.setSemantics(semantics.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(semantics.getFingerprint()).aggregateValueAsInt());
return this;
}
- /** Sets adds padding to the modified element. */
+ /** Sets the padding of the modified element. */
@NonNull
public Builder setPadding(@NonNull Padding padding) {
mImpl.setPadding(padding.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(padding.getFingerprint()).aggregateValueAsInt());
return this;
}
- /** Sets draws a border around the modified element. */
+ /** Sets the border of the modified element. */
@NonNull
public Builder setBorder(@NonNull Border border) {
mImpl.setBorder(border.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(border.getFingerprint()).aggregateValueAsInt());
return this;
}
- /** Sets adds a background (with optional corner radius) to the modified element. */
+ /** Sets the background (with optional corner radius) of the modified element. */
@NonNull
public Builder setBackground(@NonNull Background background) {
mImpl.setBackground(background.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(background.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -738,13 +868,15 @@
@NonNull
public Builder setMetadata(@NonNull ElementMetadata metadata) {
mImpl.setMetadata(metadata.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 6, checkNotNull(metadata.getFingerprint()).aggregateValueAsInt());
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public Modifiers build() {
- return Modifiers.fromProto(mImpl.build());
+ return new Modifiers(mImpl.build(), mFingerprint);
}
}
}
@@ -755,9 +887,11 @@
*/
public static final class ArcModifiers {
private final ModifiersProto.ArcModifiers mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private ArcModifiers(ModifiersProto.ArcModifiers impl) {
+ ArcModifiers(ModifiersProto.ArcModifiers impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -786,12 +920,19 @@
}
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static ArcModifiers fromProto(@NonNull ModifiersProto.ArcModifiers proto) {
- return new ArcModifiers(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
+ @NonNull
+ static ArcModifiers fromProto(@NonNull ModifiersProto.ArcModifiers proto) {
+ return new ArcModifiers(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ModifiersProto.ArcModifiers toProto() {
@@ -802,6 +943,7 @@
public static final class Builder {
private final ModifiersProto.ArcModifiers.Builder mImpl =
ModifiersProto.ArcModifiers.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1648736168);
public Builder() {}
@@ -812,6 +954,8 @@
@NonNull
public Builder setClickable(@NonNull Clickable clickable) {
mImpl.setClickable(clickable.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(clickable.getFingerprint()).aggregateValueAsInt());
return this;
}
@@ -822,13 +966,15 @@
@NonNull
public Builder setSemantics(@NonNull Semantics semantics) {
mImpl.setSemantics(semantics.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(semantics.getFingerprint()).aggregateValueAsInt());
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public ArcModifiers build() {
- return ArcModifiers.fromProto(mImpl.build());
+ return new ArcModifiers(mImpl.build(), mFingerprint);
}
}
}
@@ -840,9 +986,12 @@
*/
public static final class SpanModifiers {
private final ModifiersProto.SpanModifiers mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private SpanModifiers(ModifiersProto.SpanModifiers impl) {
+ SpanModifiers(
+ ModifiersProto.SpanModifiers impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/**
@@ -858,12 +1007,19 @@
}
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static SpanModifiers fromProto(@NonNull ModifiersProto.SpanModifiers proto) {
- return new SpanModifiers(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
+ @NonNull
+ static SpanModifiers fromProto(@NonNull ModifiersProto.SpanModifiers proto) {
+ return new SpanModifiers(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ModifiersProto.SpanModifiers toProto() {
@@ -874,6 +1030,7 @@
public static final class Builder {
private final ModifiersProto.SpanModifiers.Builder mImpl =
ModifiersProto.SpanModifiers.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1318656482);
public Builder() {}
@@ -884,13 +1041,15 @@
@NonNull
public Builder setClickable(@NonNull Clickable clickable) {
mImpl.setClickable(clickable.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(clickable.getFingerprint()).aggregateValueAsInt());
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public SpanModifiers build() {
- return SpanModifiers.fromProto(mImpl.build());
+ return new SpanModifiers(mImpl.build(), mFingerprint);
}
}
}
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/RequestBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/RequestBuilders.java
index cde0e81..f68dd66 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/RequestBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/RequestBuilders.java
@@ -21,9 +21,9 @@
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters;
-import androidx.wear.protolayout.StateBuilders.State;
import androidx.wear.protolayout.proto.DeviceParametersProto;
import androidx.wear.protolayout.proto.StateProto;
+import androidx.wear.protolayout.StateBuilders.State;
import androidx.wear.tiles.proto.RequestProto;
import java.util.List;
@@ -46,8 +46,9 @@
}
/**
- * Gets the {@link DeviceParameters} describing the device requesting the tile update. If it
- * was not set, a default empty instance is returned.
+ * Gets the {@link androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters}
+ * object describing the device requesting the tile update. If not set, a default empty
+ * instance is used.
*
* @since 1.0
*/
@@ -62,7 +63,8 @@
}
/**
- * Gets the {@link State} that should be used when building the tile.
+ * Gets the {@link androidx.wear.protolayout.StateBuilders.State} that should be used when
+ * building the tile.
*
* @since 1.0
*/
@@ -137,6 +139,19 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "TileRequest{"
+ + "deviceConfiguration="
+ + getDeviceConfiguration()
+ + ", currentState="
+ + getCurrentState()
+ + ", tileId="
+ + getTileId()
+ + "}";
+ }
+
/** Builder for {@link TileRequest} */
public static final class Builder {
private final RequestProto.TileRequest.Builder mImpl =
@@ -145,8 +160,9 @@
public Builder() {}
/**
- * Sets a {@link DeviceParameters} object describing the device requesting the tile
- * update. If not set, a default empty instance is used.
+ * Sets the {@link androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters}
+ * object describing the device requesting the tile update. If not set, a default empty
+ * instance is used.
*
* @since 1.0
*/
@@ -157,7 +173,8 @@
}
/**
- * Sets the {@link State} that should be used when building the tile.
+ * Sets the {@link androidx.wear.protolayout.StateBuilders.State} that should be used
+ * when building the tile.
*
* @since 1.0
*/
@@ -179,7 +196,7 @@
}
/**
- * Sets a {@link androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters} object
+ * Sets the {@link androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters}
* describing the device requesting the tile update.
*
* @since 1.0
@@ -258,8 +275,8 @@
}
/**
- * Gets the {@link DeviceParameters} object describing the device requesting the resources.
- * If it was not set, a default empty instance is returned.
+ * Gets the {@link androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters}
+ * object describing the device requesting the resources.
*
* @since 1.0
*/
@@ -317,6 +334,21 @@
return mImpl;
}
+ @Override
+ @NonNull
+ public String toString() {
+ return "ResourcesRequest{"
+ + "version="
+ + getVersion()
+ + ", resourceIds="
+ + getResourceIds()
+ + ", deviceConfiguration="
+ + getDeviceConfiguration()
+ + ", tileId="
+ + getTileId()
+ + "}";
+ }
+
/** Builder for {@link ResourcesRequest} */
public static final class Builder {
private final RequestProto.ResourcesRequest.Builder mImpl =
@@ -355,8 +387,8 @@
}
/**
- * Sets a {@link DeviceParameters} object describing the device requesting the
- * resources. If not set, a default empty instance is used.
+ * Sets the {@link androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters}
+ * object describing the device requesting the resources.
*
* @since 1.0
*/
@@ -378,7 +410,7 @@
}
/**
- * Sets a {@link androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters} object
+ * Sets the {@link androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters}
* describing the device requesting the resources.
*
* @since 1.0
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ResourceBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ResourceBuilders.java
index 99b780f..8979d32 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ResourceBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/ResourceBuilders.java
@@ -79,16 +79,14 @@
return mImpl.getResourceId();
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public static AndroidImageResourceByResId fromProto(
+ static AndroidImageResourceByResId fromProto(
@NonNull ResourceProto.AndroidImageResourceByResId proto) {
return new AndroidImageResourceByResId(proto);
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public ResourceProto.AndroidImageResourceByResId toProto() {
+ ResourceProto.AndroidImageResourceByResId toProto() {
return mImpl;
}
@@ -165,16 +163,13 @@
return mImpl.getFormat().getNumber();
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public static InlineImageResource fromProto(
- @NonNull ResourceProto.InlineImageResource proto) {
+ static InlineImageResource fromProto(@NonNull ResourceProto.InlineImageResource proto) {
return new InlineImageResource(proto);
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public ResourceProto.InlineImageResource toProto() {
+ ResourceProto.InlineImageResource toProto() {
return mImpl;
}
@@ -269,15 +264,13 @@
}
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public static ImageResource fromProto(@NonNull ResourceProto.ImageResource proto) {
+ static ImageResource fromProto(@NonNull ResourceProto.ImageResource proto) {
return new ImageResource(proto);
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public ResourceProto.ImageResource toProto() {
+ ResourceProto.ImageResource toProto() {
return mImpl;
}
@@ -375,6 +368,7 @@
return new Resources(proto);
}
+ /** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public ResourceProto.Resources toProto() {
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TileBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TileBuilders.java
index 156d2ed..3a68720 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TileBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TileBuilders.java
@@ -56,8 +56,8 @@
}
/**
- * Gets a {@link Timeline} containing the layouts for the tiles to show in the carousel,
- * along with their validity periods.
+ * Gets the {@link androidx.wear.protolayout.TimelineBuilders.Timeline} containing the
+ * layouts for the tiles to show in the carousel, along with their validity periods.
*
* @since 1.0
*/
@@ -104,7 +104,7 @@
}
/**
- * Gets a {@link androidx.wear.tiles.TimelineBuilders.Timeline} containing the layouts for
+ * Gets the {@link androidx.wear.tiles.TimelineBuilders.Timeline} containing the layouts for
* the tiles to show in the carousel, along with their validity periods.
*
* @since 1.0
@@ -172,8 +172,8 @@
}
/**
- * Sets a {@link Timeline} containing the layouts for the tiles to show in the carousel,
- * along with their validity periods.
+ * Sets the {@link androidx.wear.protolayout.TimelineBuilders.Timeline} containing the
+ * layouts for the tiles to show in the carousel, along with their validity periods.
*
* @since 1.0
*/
@@ -216,7 +216,7 @@
}
/**
- * Sets a {@link androidx.wear.tiles.TimelineBuilders.Timeline} containing the layouts
+ * Sets the {@link androidx.wear.tiles.TimelineBuilders.Timeline} containing the layouts
* for the tiles to show in the carousel, along with their validity periods.
*
* @since 1.0
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TileService.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TileService.java
index 4ba5724..2b56a86 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TileService.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TileService.java
@@ -69,7 +69,10 @@
private static final String TAG = "TileService";
static final VersionInfo DEFAULT_VERSION =
VersionInfo.newBuilder().setMajor(1).setMinor(0).build();
- static final Resources EMPTY_RESOURCE = new Resources.Builder().build();
+ @SuppressWarnings("deprecation")
+ private static final ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources>
+ ON_RESOURCES_REQUEST_NOT_IMPLEMENTED = createFailedFuture(
+ new UnsupportedOperationException("onResourcesRequest not implemented"));
/**
* The intent action used to send update requests to the provider. Tile provider services must
@@ -116,8 +119,7 @@
@Deprecated
protected ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources> onResourcesRequest(
@NonNull ResourcesRequest requestParams) {
- return createFailedFuture(
- new UnsupportedOperationException("onResourcesRequest not implemented"));
+ return ON_RESOURCES_REQUEST_NOT_IMPLEMENTED;
}
/**
@@ -137,12 +139,30 @@
*/
@MainThread
@NonNull
- @SuppressWarnings("AsyncSuffixFuture")
+ @SuppressWarnings({"AsyncSuffixFuture", "deprecation"}) // For backward compatibility
protected ListenableFuture<Resources> onTileResourcesRequest(
@NonNull ResourcesRequest requestParams) {
// We are offering a default implementation for onTileResourcesRequest for backward
// compatibility as older clients are overriding onResourcesRequest.
- return createImmediateFuture(EMPTY_RESOURCE);
+ ListenableFuture<androidx.wear.tiles.ResourceBuilders.Resources>
+ legacyResourcesRequestResult = onResourcesRequest(requestParams);
+ if (legacyResourcesRequestResult == ON_RESOURCES_REQUEST_NOT_IMPLEMENTED){
+ return createFailedFuture(new UnsupportedOperationException("onTileResourcesRequest "
+ + "not implemented."));
+ }
+
+ ResolvableFuture<Resources> result = ResolvableFuture.create();
+ legacyResourcesRequestResult.addListener(
+ () -> {
+ try {
+ result.set(
+ Resources.fromProto(legacyResourcesRequestResult.get().toProto()));
+ } catch (RuntimeException | InterruptedException | ExecutionException e) {
+ result.setException(e);
+ }
+ },
+ Runnable::run);
+ return result;
}
/**
@@ -366,44 +386,13 @@
if (resourcesFuture.isDone()) {
try {
Resources resources = resourcesFuture.get();
- if (resources != EMPTY_RESOURCE) {
- // The subclass has overridden onTileResourceRequest.
- updateResources(
- callback, resources.toProto().toByteArray());
- } else {
- // Falling back to onResourcesRequest.
- ListenableFuture<
- androidx.wear.tiles.ResourceBuilders
- .Resources>
- resourcesFutureDeprecated =
- tileService.onResourcesRequest(req);
- resourcesFutureDeprecated.addListener(
- () -> {
- try {
- updateResources(
- callback,
- resourcesFutureDeprecated
- .get()
- .toProto()
- .toByteArray());
- } catch (ExecutionException
- | InterruptedException
- | CancellationException ex) {
- Log.e(
- TAG,
- "onResourcesRequest Future failed",
- ex);
- }
- },
- mHandler::post);
- }
+ updateResources(callback, resources.toProto().toByteArray());
} catch (ExecutionException
| InterruptedException
| CancellationException ex) {
Log.e(TAG, "onTileResourcesRequest Future failed", ex);
}
} else {
- // The subclass has overridden onTileResourceRequest.
resourcesFuture.addListener(
() -> {
try {
@@ -549,12 +538,6 @@
}
}
- private static <T> ListenableFuture<T> createImmediateFuture(@NonNull T value) {
- ResolvableFuture<T> future = ResolvableFuture.create();
- future.set(value);
- return future;
- }
-
private static <T> ListenableFuture<T> createFailedFuture(@NonNull Throwable throwable) {
ResolvableFuture<T> errorFuture = ResolvableFuture.create();
errorFuture.setException(throwable);
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TimelineBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TimelineBuilders.java
index fabffa6..9ec8f9e 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TimelineBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TimelineBuilders.java
@@ -62,15 +62,13 @@
return mImpl.getEndMillis();
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public static TimeInterval fromProto(@NonNull TimelineProto.TimeInterval proto) {
+ static TimeInterval fromProto(@NonNull TimelineProto.TimeInterval proto) {
return new TimeInterval(proto);
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public TimelineProto.TimeInterval toProto() {
+ TimelineProto.TimeInterval toProto() {
return mImpl;
}
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TypeBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TypeBuilders.java
index 4ba8800..60c066c 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TypeBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TypeBuilders.java
@@ -19,8 +19,10 @@
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
import androidx.wear.protolayout.proto.TypesProto;
/**
@@ -35,9 +37,11 @@
/** An int32 type. */
public static final class Int32Prop {
private final TypesProto.Int32Prop mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private Int32Prop(TypesProto.Int32Prop impl) {
+ Int32Prop(TypesProto.Int32Prop impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -45,21 +49,27 @@
return mImpl.getValue();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static Int32Prop fromProto(@NonNull TypesProto.Int32Prop proto) {
- return new Int32Prop(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public TypesProto.Int32Prop toProto() {
+ static Int32Prop fromProto(@NonNull TypesProto.Int32Prop proto) {
+ return new Int32Prop(proto, null);
+ }
+
+ @NonNull
+ TypesProto.Int32Prop toProto() {
return mImpl;
}
/** Builder for {@link Int32Prop} */
public static final class Builder {
private final TypesProto.Int32Prop.Builder mImpl = TypesProto.Int32Prop.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1809132005);
public Builder() {}
@@ -67,13 +77,14 @@
@NonNull
public Builder setValue(int value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, value);
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public Int32Prop build() {
- return Int32Prop.fromProto(mImpl.build());
+ return new Int32Prop(mImpl.build(), mFingerprint);
}
}
}
@@ -81,9 +92,11 @@
/** A string type. */
public static final class StringProp {
private final TypesProto.StringProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private StringProp(TypesProto.StringProp impl) {
+ StringProp(TypesProto.StringProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -92,21 +105,27 @@
return mImpl.getValue();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static StringProp fromProto(@NonNull TypesProto.StringProp proto) {
- return new StringProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public TypesProto.StringProp toProto() {
+ static StringProp fromProto(@NonNull TypesProto.StringProp proto) {
+ return new StringProp(proto, null);
+ }
+
+ @NonNull
+ TypesProto.StringProp toProto() {
return mImpl;
}
/** Builder for {@link StringProp} */
public static final class Builder {
private final TypesProto.StringProp.Builder mImpl = TypesProto.StringProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-319420356);
public Builder() {}
@@ -114,13 +133,14 @@
@NonNull
public Builder setValue(@NonNull String value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, value.hashCode());
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public StringProp build() {
- return StringProp.fromProto(mImpl.build());
+ return new StringProp(mImpl.build(), mFingerprint);
}
}
}
@@ -128,9 +148,11 @@
/** A float type. */
public static final class FloatProp {
private final TypesProto.FloatProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private FloatProp(TypesProto.FloatProp impl) {
+ FloatProp(TypesProto.FloatProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -138,21 +160,27 @@
return mImpl.getValue();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static FloatProp fromProto(@NonNull TypesProto.FloatProp proto) {
- return new FloatProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public TypesProto.FloatProp toProto() {
+ static FloatProp fromProto(@NonNull TypesProto.FloatProp proto) {
+ return new FloatProp(proto, null);
+ }
+
+ @NonNull
+ TypesProto.FloatProp toProto() {
return mImpl;
}
/** Builder for {@link FloatProp} */
public static final class Builder {
private final TypesProto.FloatProp.Builder mImpl = TypesProto.FloatProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(399943127);
public Builder() {}
@@ -160,13 +188,14 @@
@NonNull
public Builder setValue(float value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Float.floatToIntBits(value));
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public FloatProp build() {
- return FloatProp.fromProto(mImpl.build());
+ return new FloatProp(mImpl.build(), mFingerprint);
}
}
}
@@ -174,9 +203,11 @@
/** A boolean type. */
public static final class BoolProp {
private final TypesProto.BoolProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
- private BoolProp(TypesProto.BoolProp impl) {
+ BoolProp(TypesProto.BoolProp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
+ this.mFingerprint = fingerprint;
}
/** Gets the value. Intended for testing purposes only. */
@@ -184,21 +215,27 @@
return mImpl.getValue();
}
+ /** Get the fingerprint for this object, or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static BoolProp fromProto(@NonNull TypesProto.BoolProp proto) {
- return new BoolProp(proto);
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
}
- @RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public TypesProto.BoolProp toProto() {
+ static BoolProp fromProto(@NonNull TypesProto.BoolProp proto) {
+ return new BoolProp(proto, null);
+ }
+
+ @NonNull
+ TypesProto.BoolProp toProto() {
return mImpl;
}
/** Builder for {@link BoolProp} */
public static final class Builder {
private final TypesProto.BoolProp.Builder mImpl = TypesProto.BoolProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-278424864);
public Builder() {}
@@ -207,13 +244,14 @@
@NonNull
public Builder setValue(boolean value) {
mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Boolean.hashCode(value));
return this;
}
/** Builds an instance from accumulated values. */
@NonNull
public BoolProp build() {
- return BoolProp.fromProto(mImpl.build());
+ return new BoolProp(mImpl.build(), mFingerprint);
}
}
}
diff --git a/wear/watchface/watchface-complications-data-source-samples/build.gradle b/wear/watchface/watchface-complications-data-source-samples/build.gradle
index 6c7db9a..0ff1cd5 100644
--- a/wear/watchface/watchface-complications-data-source-samples/build.gradle
+++ b/wear/watchface/watchface-complications-data-source-samples/build.gradle
@@ -25,11 +25,14 @@
api(project(":wear:watchface:watchface-complications-data-source"))
api(libs.guavaAndroid)
api(libs.kotlinStdlib)
+ // TODO(b/267170061): Use released protolayout-expression, remove protolayout-proto.
+ implementation(project(":wear:protolayout:protolayout-expression"))
+ implementation(project(":wear:protolayout:protolayout-proto"))
}
android {
defaultConfig {
- minSdkVersion 26
+ minSdkVersion 29
}
namespace "androidx.wear.watchface.complications.datasource.samples"
}
diff --git a/wear/watchface/watchface-complications-data-source-samples/src/main/AndroidManifest.xml b/wear/watchface/watchface-complications-data-source-samples/src/main/AndroidManifest.xml
index dbbf0be..3b5bdf4 100644
--- a/wear/watchface/watchface-complications-data-source-samples/src/main/AndroidManifest.xml
+++ b/wear/watchface/watchface-complications-data-source-samples/src/main/AndroidManifest.xml
@@ -17,6 +17,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission
android:name="com.google.android.wearable.permission.USE_IMMEDIATE_COMPLICATION_UPDATE" />
+ <uses-permission
+ android:name="android.permission.ACTIVITY_RECOGNITION" />
+ <uses-permission
+ android:name="android.permission.BODY_SENSORS" />
<application
android:label="@string/app_name"
android:icon="@drawable/circle"
@@ -215,6 +219,123 @@
</intent-filter>
</service>
+ <service android:name=".dynamic.TimeDataSourceService"
+ android:label="@string/dynamic_time_data_source_name"
+ android:exported="true"
+ android:icon="@drawable/circle"
+ android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
+ <meta-data
+ android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ android:value="RANGED_VALUE"/>
+ <meta-data
+ android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
+ android:value="0"/>
+ <intent-filter>
+ <action android:name=
+ "android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
+ </intent-filter>
+ </service>
+
+ <service android:name=".dynamic.HealthDataSourceServices$Calories"
+ android:label="@string/dynamic_calories_data_source_name"
+ android:exported="true"
+ android:icon="@drawable/circle"
+ android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
+ <meta-data
+ android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ android:value="RANGED_VALUE"/>
+ <meta-data
+ android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
+ android:value="0"/>
+ <meta-data
+ android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION"
+ android:value="androidx.wear.watchface.complications.datasource.samples.dynamic.REQUEST_ACTIVITY_RECOGNITION_PERMISSION"/>
+ <intent-filter>
+ <action android:name=
+ "android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
+ </intent-filter>
+ </service>
+
+ <service android:name=".dynamic.HealthDataSourceServices$Distance"
+ android:label="@string/dynamic_distance_data_source_name"
+ android:exported="true"
+ android:icon="@drawable/circle"
+ android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
+ <meta-data
+ android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ android:value="RANGED_VALUE"/>
+ <meta-data
+ android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
+ android:value="0"/>
+ <meta-data
+ android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION"
+ android:value="androidx.wear.watchface.complications.datasource.samples.dynamic.REQUEST_ACTIVITY_RECOGNITION_PERMISSION"/>
+ <intent-filter>
+ <action android:name=
+ "android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
+ </intent-filter>
+ </service>
+
+ <service android:name=".dynamic.HealthDataSourceServices$Floors"
+ android:label="@string/dynamic_floors_data_source_name"
+ android:exported="true"
+ android:icon="@drawable/circle"
+ android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
+ <meta-data
+ android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ android:value="RANGED_VALUE"/>
+ <meta-data
+ android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
+ android:value="0"/>
+ <meta-data
+ android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION"
+ android:value="androidx.wear.watchface.complications.datasource.samples.dynamic.REQUEST_ACTIVITY_RECOGNITION_PERMISSION"/>
+ <intent-filter>
+ <action android:name=
+ "android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
+ </intent-filter>
+ </service>
+
+ <service android:name=".dynamic.HealthDataSourceServices$HeartRate"
+ android:label="@string/dynamic_heart_rate_data_source_name"
+ android:exported="true"
+ android:icon="@drawable/circle"
+ android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
+ <meta-data
+ android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ android:value="RANGED_VALUE"/>
+ <meta-data
+ android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
+ android:value="0"/>
+ <meta-data
+ android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION"
+ android:value="androidx.wear.watchface.complications.datasource.samples.dynamic.REQUEST_BODY_SENSORS_PERMISSION"/>
+ <intent-filter>
+ <action android:name=
+ "android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
+ </intent-filter>
+ </service>
+
+ <service android:name=".dynamic.HealthDataSourceServices$Steps"
+ android:label="@string/dynamic_steps_data_source_name"
+ android:exported="true"
+ android:icon="@drawable/circle"
+ android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
+ <meta-data
+ android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ android:value="RANGED_VALUE"/>
+ <meta-data
+ android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
+ android:value="0"/>
+ <meta-data
+ android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION"
+ android:value="androidx.wear.watchface.complications.datasource.samples.dynamic.REQUEST_ACTIVITY_RECOGNITION_PERMISSION"/>
+ <intent-filter>
+ <action android:name=
+ "android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
+ </intent-filter>
+ </service>
+
<activity
android:name=".ConfigActivity"
android:exported="true"
@@ -227,5 +348,19 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
+ <activity
+ android:name=".dynamic.RequestPermissionActivity"
+ android:exported="true"
+ android:label="@string/config_title" >
+ <intent-filter>
+ <action android:name=
+ "androidx.wear.watchface.complications.datasource.samples.dynamic.REQUEST_ACTIVITY_RECOGNITION_PERMISSION" />
+ <action android:name=
+ "androidx.wear.watchface.complications.datasource.samples.dynamic.REQUEST_BODY_SENSORS_PERMISSION" />
+ <category android:name=
+ "android.support.wearable.complications.category.PROVIDER_CONFIG" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/HealthDataSourceServices.kt b/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/HealthDataSourceServices.kt
new file mode 100644
index 0000000..a01ba4c
--- /dev/null
+++ b/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/HealthDataSourceServices.kt
@@ -0,0 +1,190 @@
+/*
+ * 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.watchface.complications.datasource.samples.dynamic
+
+import android.Manifest.permission
+import android.content.pm.PackageManager.PERMISSION_GRANTED
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat
+import androidx.wear.protolayout.expression.PlatformHealthSources
+import androidx.wear.watchface.complications.data.ComplicationData
+import androidx.wear.watchface.complications.data.ComplicationType
+import androidx.wear.watchface.complications.data.DynamicComplicationText
+import androidx.wear.watchface.complications.data.PlainComplicationText
+import androidx.wear.watchface.complications.data.RangedValueComplicationData
+import androidx.wear.watchface.complications.datasource.ComplicationDataSourceService
+import androidx.wear.watchface.complications.datasource.ComplicationRequest
+import androidx.wear.watchface.complications.datasource.samples.R
+
+object HealthDataSourceServices {
+ class Calories :
+ Base(
+ max = 1000f,
+ title = "Calories",
+ ) {
+ override val value: DynamicFloat?
+ get() =
+ if (checkSelfPermission(permission.ACTIVITY_RECOGNITION) == PERMISSION_GRANTED) {
+ PlatformHealthSources.dailyCalories()
+ } else {
+ null
+ }
+ }
+
+ class Distance :
+ Base(
+ max = 1000f,
+ title = "Distance",
+ ) {
+ override val value: DynamicFloat?
+ get() =
+ if (checkSelfPermission(permission.ACTIVITY_RECOGNITION) == PERMISSION_GRANTED) {
+ PlatformHealthSources.dailyDistanceMeters()
+ } else {
+ null
+ }
+ }
+
+ class Floors :
+ Base(
+ max = 1000f,
+ title = "Floors",
+ ) {
+ override val value: DynamicFloat?
+ get() =
+ if (checkSelfPermission(permission.ACTIVITY_RECOGNITION) == PERMISSION_GRANTED) {
+ PlatformHealthSources.dailyFloors()
+ } else {
+ null
+ }
+ }
+
+ class HeartRate :
+ Base(
+ max = 200f,
+ title = "HR",
+ ) {
+ override val value: DynamicFloat?
+ get() =
+ if (checkSelfPermission(permission.BODY_SENSORS) == PERMISSION_GRANTED) {
+ PlatformHealthSources.heartRateBpm()
+ } else {
+ null
+ }
+ }
+
+ class Steps :
+ Base(
+ max = 1000f,
+ title = "Steps",
+ ) {
+ override val value: DynamicFloat?
+ get() =
+ if (checkSelfPermission(permission.ACTIVITY_RECOGNITION) == PERMISSION_GRANTED) {
+ PlatformHealthSources.dailySteps().asFloat()
+ } else {
+ null
+ }
+ }
+
+ abstract class Base(
+ private val max: Float,
+ title: String,
+ ) : ComplicationDataSourceService() {
+ private val title = PlainComplicationText.Builder(title).build()
+
+ /** Returns [DynamicFloat] or `null` if missing permissions. */
+ abstract val value: DynamicFloat?
+
+ override fun onComplicationRequest(
+ request: ComplicationRequest,
+ listener: ComplicationRequestListener
+ ) {
+ val value = value
+ if (value == null) {
+ // Missing permission.
+ val text =
+ PlainComplicationText.Builder(getString(R.string.dynamic_data_no_permission))
+ .build()
+
+ listener.onComplicationData(
+ RangedValueComplicationData.Builder(
+ value = 0f,
+ min = 0f,
+ max = max,
+ contentDescription = text,
+ )
+ .setTitle(title)
+ .setText(text)
+ .build()
+ )
+ return
+ }
+
+ val text =
+ DynamicComplicationText(
+ value.format(),
+ getString(R.string.dynamic_data_not_supported)
+ )
+ val fallbackText =
+ PlainComplicationText.Builder(
+ getString(R.string.dynamic_data_not_available_or_ready)
+ )
+ .build()
+
+ listener.onComplicationData(
+ RangedValueComplicationData.Builder(
+ dynamicValue =
+ DynamicFloat.onCondition(value.gt(max))
+ .use(DynamicFloat.constant(max))
+ .elseUse(value),
+ fallbackValue = 0f,
+ min = 0f,
+ max = max,
+ contentDescription = text,
+ )
+ .setTitle(title)
+ .setText(text)
+ .setDynamicValueInvalidationFallback(
+ RangedValueComplicationData.Builder(
+ value = 0f,
+ min = 0f,
+ max = max,
+ contentDescription = fallbackText,
+ )
+ .setTitle(title)
+ .setText(fallbackText)
+ .build()
+ )
+ .build()
+ )
+ }
+
+ override fun getPreviewData(type: ComplicationType): ComplicationData {
+ val value = max / 4
+ val text = PlainComplicationText.Builder(value.toInt().toString()).build()
+ return RangedValueComplicationData.Builder(
+ value = value,
+ min = 0f,
+ max = max,
+ contentDescription = text,
+ )
+ .setTitle(title)
+ .setText(text)
+ .build()
+ }
+ }
+}
diff --git a/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/RequestPermissionActivity.kt b/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/RequestPermissionActivity.kt
new file mode 100644
index 0000000..037c838
--- /dev/null
+++ b/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/RequestPermissionActivity.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.watchface.complications.datasource.samples.dynamic
+
+import android.Manifest.permission
+import android.app.Activity
+import android.content.pm.PackageManager.PERMISSION_GRANTED
+import android.os.Bundle
+
+class RequestPermissionActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val permission =
+ requireNotNull(ACTION_TO_PERMISSION[intent.action]) {
+ "Unknown action: ${intent.action}"
+ }
+ if (checkSelfPermission(permission) == PERMISSION_GRANTED) {
+ setResult(RESULT_OK)
+ finish()
+ return
+ }
+ requestPermissions(arrayOf(permission), 0)
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array<out String>,
+ grantResults: IntArray
+ ) {
+ if (grantResults contentEquals intArrayOf(PERMISSION_GRANTED)) {
+ setResult(RESULT_OK)
+ } else {
+ setResult(RESULT_CANCELED)
+ }
+ finish()
+ }
+
+ companion object {
+ private val ACTION_TO_PERMISSION: Map<String, String> =
+ mapOf(
+ "androidx.wear.watchface.complications.datasource.samples.dynamic.REQUEST_ACTIVITY_RECOGNITION_PERMISSION" to // ktlint-disable max-line-length
+ permission.ACTIVITY_RECOGNITION,
+ "androidx.wear.watchface.complications.datasource.samples.dynamic.REQUEST_BODY_SENSORS_PERMISSION" to // ktlint-disable max-line-length
+ permission.BODY_SENSORS,
+ )
+ }
+}
diff --git a/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/TimeDataSourceService.kt b/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/TimeDataSourceService.kt
new file mode 100644
index 0000000..5e9ccf8
--- /dev/null
+++ b/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/TimeDataSourceService.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ * 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.watchface.complications.datasource.samples.dynamic
+
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicDuration
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString
+import androidx.wear.watchface.complications.data.ComplicationData
+import androidx.wear.watchface.complications.data.ComplicationType
+import androidx.wear.watchface.complications.data.DynamicComplicationText
+import androidx.wear.watchface.complications.data.PlainComplicationText
+import androidx.wear.watchface.complications.data.RangedValueComplicationData
+import androidx.wear.watchface.complications.datasource.ComplicationDataSourceService
+import androidx.wear.watchface.complications.datasource.ComplicationRequest
+import java.time.Instant.EPOCH
+
+class TimeDataSourceService : ComplicationDataSourceService() {
+ override fun onComplicationRequest(
+ request: ComplicationRequest,
+ listener: ComplicationRequestListener
+ ) {
+ val epochDuration: DynamicDuration =
+ DynamicInstant.withSecondsPrecision(EPOCH)
+ .durationUntil(DynamicInstant.platformTimeWithSecondsPrecision())
+ val text =
+ DynamicComplicationText(
+ epochDuration.minutesPart
+ .format()
+ .concat(DynamicString.constant(":"))
+ .concat(epochDuration.secondsPart.format()),
+ "--"
+ )
+
+ listener.onComplicationData(
+ RangedValueComplicationData.Builder(
+ dynamicValue = epochDuration.secondsPart.rem(10f),
+ fallbackValue = 0f,
+ min = 0f,
+ max = 9f,
+ contentDescription = text,
+ )
+ .setText(text)
+ .build()
+ )
+ }
+
+ override fun getPreviewData(type: ComplicationType): ComplicationData {
+ val text = PlainComplicationText.Builder("12:42").build()
+ return RangedValueComplicationData.Builder(
+ value = 2f,
+ min = 0f,
+ max = 9f,
+ contentDescription = text,
+ )
+ .setText(text)
+ .build()
+ }
+}
diff --git a/wear/watchface/watchface-complications-data-source-samples/src/main/res/values/strings.xml b/wear/watchface/watchface-complications-data-source-samples/src/main/res/values/strings.xml
index 84c8731..5a4d2ff 100644
--- a/wear/watchface/watchface-complications-data-source-samples/src/main/res/values/strings.xml
+++ b/wear/watchface/watchface-complications-data-source-samples/src/main/res/values/strings.xml
@@ -26,6 +26,16 @@
<string name="color_ramp2_data_source_name" translatable="false">Non interpolated color ramp</string>
<string name="goal_progress_data_source_name" translatable="false">Goal Progress</string>
<string name="weighted_elements_data_source_name" translatable="false">Weighted Elements</string>
+ <string name="dynamic_time_data_source_name" translatable="false">Example Dynamic Time</string>
+ <string name="dynamic_calories_data_source_name" translatable="false">Example Dynamic Calories</string>
+ <string name="dynamic_distance_data_source_name" translatable="false">Example Dynamic Distance</string>
+ <string name="dynamic_floors_data_source_name" translatable="false">Example Dynamic Floors</string>
+ <string name="dynamic_heart_rate_data_source_name" translatable="false">Example Dynamic Heart Rate</string>
+ <string name="dynamic_steps_data_source_name" translatable="false">Example Dynamic Steps</string>
+
+ <string name="dynamic_data_no_permission" translatable="false">NP</string>
+ <string name="dynamic_data_not_supported" translatable="false">NS</string>
+ <string name="dynamic_data_not_available_or_ready" translatable="false">NA</string>
<string name="config_title" translatable="false">Configuration</string>
<string name="config_button_title" translatable="false">Generate</string>
diff --git a/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceService.kt b/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceService.kt
index 7174168..59670b9 100644
--- a/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceService.kt
+++ b/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceService.kt
@@ -482,6 +482,7 @@
),
object : ComplicationRequestListener {
override fun onComplicationData(complicationData: ComplicationData?) {
+ complicationData?.validate()
// This can be run on an arbitrary thread, but that's OK.
val dataType = complicationData?.type ?: ComplicationType.NO_DATA
require(
@@ -517,6 +518,7 @@
override fun onComplicationDataTimeline(
complicationDataTimeline: ComplicationDataTimeline?
) {
+ complicationDataTimeline?.validate()
// This can be run on an arbitrary thread, but that's OK.
val defaultComplicationData =
complicationDataTimeline?.defaultComplicationData
@@ -617,22 +619,21 @@
override fun getComplicationPreviewData(type: Int): WireComplicationData? =
aidlMethod(TAG, "getComplicationPreviewData") {
val expectedDataType = fromWireType(type)
- val complicationData = getPreviewData(expectedDataType)
- val dataType = complicationData?.type ?: ComplicationType.NO_DATA
+ val complicationData = getPreviewData(expectedDataType) ?: return null
+ complicationData.validate()
+ val dataType = complicationData.type
require(dataType == ComplicationType.NO_DATA || dataType == expectedDataType) {
"Preview data should match the requested type. " +
"Expected $expectedDataType got $dataType."
}
- if (complicationData != null) {
- require(complicationData.validTimeRange == TimeRange.ALWAYS) {
- "Preview data should have time range set to ALWAYS."
- }
- require(!complicationData.asWireComplicationData().hasDynamicValues()) {
- "Preview data must not have dynamic values."
- }
+ require(complicationData.validTimeRange == TimeRange.ALWAYS) {
+ "Preview data should have time range set to ALWAYS."
}
- return complicationData?.asWireComplicationData()
+ require(!complicationData.asWireComplicationData().hasDynamicValues()) {
+ "Preview data must not have dynamic values."
+ }
+ return complicationData.asWireComplicationData()
}
override fun onStartSynchronousComplicationRequests(complicationInstanceId: Int): Unit =
@@ -685,6 +686,7 @@
),
object : ComplicationRequestListener {
override fun onComplicationData(complicationData: ComplicationData?) {
+ complicationData?.validate()
// This can be run on an arbitrary thread, but that's OK.
val dataType = complicationData?.type ?: ComplicationType.NO_DATA
require(
@@ -711,6 +713,7 @@
override fun onComplicationDataTimeline(
complicationDataTimeline: ComplicationDataTimeline?
) {
+ complicationDataTimeline?.validate()
// This can be run on an arbitrary thread, but that's OK.
val dataType =
complicationDataTimeline?.defaultComplicationData?.type
diff --git a/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataTimeline.kt b/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataTimeline.kt
index 53d5646..450c930 100644
--- a/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataTimeline.kt
+++ b/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataTimeline.kt
@@ -116,9 +116,12 @@
public val defaultComplicationData: ComplicationData,
public val timelineEntries: Collection<TimelineEntry>
) {
- init {
+ /** Throws [IllegalArgumentException] if the [ComplicationDataTimeline] is invalid. */
+ internal fun validate() {
+ defaultComplicationData.validate()
for (entry in timelineEntries) {
val complicationData = entry.complicationData
+ complicationData.validate()
if (complicationData is NoDataComplicationData) {
require(
complicationData.placeholder == null ||
diff --git a/wear/watchface/watchface-complications-data-source/src/test/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceServiceTest.kt b/wear/watchface/watchface-complications-data-source/src/test/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceServiceTest.kt
index eb60b48..a5bfa74 100644
--- a/wear/watchface/watchface-complications-data-source/src/test/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceServiceTest.kt
+++ b/wear/watchface/watchface-complications-data-source/src/test/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceServiceTest.kt
@@ -250,6 +250,31 @@
assertThat(exceptionLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
assertThat(exception.get()).isInstanceOf(IllegalArgumentException::class.java)
+ assertThat(exception.get())
+ .hasMessageThat()
+ .isEqualTo(
+ "Complication data should match the requested type. " +
+ "Expected SHORT_TEXT got LONG_TEXT."
+ )
+ }
+
+ @Test
+ fun testOnComplicationRequest_invalidData() {
+ mService.responseData = INVALID_DATA
+ val id = 123
+ val exception = AtomicReference<Throwable>()
+ val exceptionLatch = CountDownLatch(1)
+
+ mPretendMainThread.uncaughtExceptionHandler =
+ Thread.UncaughtExceptionHandler { _, throwable ->
+ exception.set(throwable)
+ exceptionLatch.countDown()
+ }
+ mProvider.onUpdate(id, INVALID_DATA.type.toWireComplicationType(), mLocalManager)
+
+ assertThat(exceptionLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+ assertThat(exception.get()).isInstanceOf(IllegalArgumentException::class.java)
+ assertThat(exception.get()).hasMessageThat().isEqualTo(INVALID_DATA_ERROR_MESSAGE)
}
@Test
@@ -283,8 +308,12 @@
.isEqualTo("hello preview")
}
- enum class DataWithDynamicValueScenario(val data: ComplicationData) {
- RANGED_VALUE(
+ enum class GetComplicationPreviewDataInvalidScenario(
+ val data: ComplicationData,
+ val message: String
+ ) {
+ INVALID_PREVIEW_DATA(INVALID_DATA, INVALID_DATA_ERROR_MESSAGE),
+ DYNAMIC_RANGED_VALUE(
RangedValueComplicationData.Builder(
dynamicValue = DynamicFloat.constant(1f),
fallbackValue = 0f,
@@ -293,32 +322,36 @@
contentDescription = ComplicationText.EMPTY
)
.setText(ComplicationText.EMPTY)
- .build()
+ .build(),
+ "Preview data must not have dynamic values."
),
- LONG_TEXT(
+ DYNAMIC_LONG_TEXT(
LongTextComplicationData.Builder(
text = DynamicComplicationText(DynamicString.constant("Long Text"), "fallback"),
contentDescription = ComplicationText.EMPTY
)
- .build()
+ .build(),
+ "Preview data must not have dynamic values."
),
- LONG_TITLE(
+ DYNAMIC_LONG_TITLE(
LongTextComplicationData.Builder(
text = ComplicationText.EMPTY,
contentDescription = ComplicationText.EMPTY
)
.setTitle(DynamicComplicationText(DynamicString.constant("Long Title"), "fallback"))
- .build()
+ .build(),
+ "Preview data must not have dynamic values."
),
- SHORT_TEXT(
+ DYNAMIC_SHORT_TEXT(
ShortTextComplicationData.Builder(
text =
DynamicComplicationText(DynamicString.constant("Short Text"), "fallback"),
contentDescription = ComplicationText.EMPTY
)
- .build()
+ .build(),
+ "Preview data must not have dynamic values."
),
- SHORT_TITLE(
+ DYNAMIC_SHORT_TITLE(
ShortTextComplicationData.Builder(
text = ComplicationText.EMPTY,
contentDescription = ComplicationText.EMPTY
@@ -326,21 +359,23 @@
.setTitle(
DynamicComplicationText(DynamicString.constant("Short Title"), "fallback")
)
- .build()
+ .build(),
+ "Preview data must not have dynamic values."
),
- CONTENT_DESCRIPTION(
+ DYNAMIC_CONTENT_DESCRIPTION(
LongTextComplicationData.Builder(
text = ComplicationText.EMPTY,
contentDescription =
DynamicComplicationText(DynamicString.constant("Long Text"), "fallback"),
)
- .build()
+ .build(),
+ "Preview data must not have dynamic values."
),
}
@Test
- fun testGetComplicationPreviewData_withDynamicValue_fails() {
- for (scenario in DataWithDynamicValueScenario.values()) {
+ fun testGetComplicationPreviewData_invalid_fails() {
+ for (scenario in GetComplicationPreviewDataInvalidScenario.values()) {
mService.previewData = scenario.data
val exception =
@@ -354,12 +389,12 @@
.withMessage(scenario.name)
.that(exception)
.hasMessageThat()
- .isEqualTo("Preview data must not have dynamic values.")
+ .isEqualTo(scenario.message)
}
}
@Test
- fun testTimelineTestService() {
+ fun testTimeline() {
mService.respondWithTimeline = true
val timeline = ArrayList<TimelineEntry>()
timeline.add(
@@ -413,6 +448,26 @@
}
@Test
+ fun testTimeline_invalidData() {
+ mService.respondWithTimeline = true
+ mService.responseDataTimeline = ComplicationDataTimeline(INVALID_DATA, listOf())
+ val id = 123
+ val exception = AtomicReference<Throwable>()
+ val exceptionLatch = CountDownLatch(1)
+
+ mPretendMainThread.uncaughtExceptionHandler =
+ Thread.UncaughtExceptionHandler { _, throwable ->
+ exception.set(throwable)
+ exceptionLatch.countDown()
+ }
+ mProvider.onUpdate(id, INVALID_DATA.type.toWireComplicationType(), mLocalManager)
+
+ assertThat(exceptionLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+ assertThat(exception.get()).isInstanceOf(IllegalArgumentException::class.java)
+ assertThat(exception.get()).hasMessageThat().isEqualTo(INVALID_DATA_ERROR_MESSAGE)
+ }
+
+ @Test
fun testImmediateRequest() {
mService.responseData =
LongTextComplicationData.Builder(
@@ -542,6 +597,83 @@
}
}
+ @Test
+ fun testImmediateRequest_invalidData() {
+ mService.responseData = INVALID_DATA
+ val thread = HandlerThread("testThread")
+
+ try {
+ thread.start()
+ val threadHandler = Handler(thread.looper)
+ val response = AtomicReference<WireComplicationData>()
+ val exception = AtomicReference<Throwable>()
+ val exceptionLatch = CountDownLatch(1)
+
+ mPretendMainThread.uncaughtExceptionHandler =
+ Thread.UncaughtExceptionHandler { _, throwable ->
+ exception.set(throwable)
+ exceptionLatch.countDown()
+ }
+ threadHandler.post {
+ try {
+ response.set(
+ mProvider.onSynchronousComplicationRequest(
+ 123,
+ INVALID_DATA.type.toWireComplicationType()
+ )
+ )
+ } catch (e: RemoteException) {
+ // Should not happen
+ }
+ }
+
+ assertThat(exceptionLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+ assertThat(exception.get()).isInstanceOf(IllegalArgumentException::class.java)
+ assertThat(exception.get()).hasMessageThat().isEqualTo(INVALID_DATA_ERROR_MESSAGE)
+ } finally {
+ thread.quitSafely()
+ }
+ }
+
+ @Test
+ fun testImmediateRequest_invalidTimelineData() {
+ mService.respondWithTimeline = true
+ mService.responseDataTimeline = ComplicationDataTimeline(INVALID_DATA, listOf())
+ val thread = HandlerThread("testThread")
+
+ try {
+ thread.start()
+ val threadHandler = Handler(thread.looper)
+ val response = AtomicReference<WireComplicationData>()
+ val exception = AtomicReference<Throwable>()
+ val exceptionLatch = CountDownLatch(1)
+
+ mPretendMainThread.uncaughtExceptionHandler =
+ Thread.UncaughtExceptionHandler { _, throwable ->
+ exception.set(throwable)
+ exceptionLatch.countDown()
+ }
+ threadHandler.post {
+ try {
+ response.set(
+ mProvider.onSynchronousComplicationRequest(
+ 123,
+ INVALID_DATA.type.toWireComplicationType()
+ )
+ )
+ } catch (e: RemoteException) {
+ // Should not happen
+ }
+ }
+
+ assertThat(exceptionLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+ assertThat(exception.get()).isInstanceOf(IllegalArgumentException::class.java)
+ assertThat(exception.get()).hasMessageThat().isEqualTo(INVALID_DATA_ERROR_MESSAGE)
+ } finally {
+ thread.quitSafely()
+ }
+ }
+
private fun runUiThreadTasksWhileAwaitingDataLatch(timeout: Long) {
// Allowing UI thread to execute while we wait for the data latch.
var attempts: Long = 0
@@ -553,5 +685,16 @@
companion object {
private const val TAG = "ComplicationDataSourceServiceTest"
+
+ private val INVALID_DATA =
+ RangedValueComplicationData.Builder(
+ value = 100f, // Higher than max.
+ min = 0f,
+ max = 10f,
+ contentDescription = ComplicationText.EMPTY
+ )
+ .setText(ComplicationText.EMPTY)
+ .build()
+ private val INVALID_DATA_ERROR_MESSAGE = "value must be between min and max"
}
}
diff --git a/wear/watchface/watchface-complications-data/api/current.txt b/wear/watchface/watchface-complications-data/api/current.txt
index c9bc3f0..34d8538 100644
--- a/wear/watchface/watchface-complications-data/api/current.txt
+++ b/wear/watchface/watchface-complications-data/api/current.txt
@@ -89,15 +89,15 @@
}
public final class DynamicComplicationText implements androidx.wear.watchface.complications.data.ComplicationText {
- ctor public DynamicComplicationText(androidx.wear.protolayout.expression.DynamicBuilders.DynamicString dynamicValue, String fallbackValue);
+ ctor public DynamicComplicationText(androidx.wear.protolayout.expression.DynamicBuilders.DynamicString dynamicValue, CharSequence fallbackValue);
method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicString getDynamicValue();
- method public String getFallbackValue();
+ method public CharSequence getFallbackValue();
method public java.time.Instant getNextChangeTime(java.time.Instant afterInstant);
method public CharSequence getTextAt(android.content.res.Resources resources, java.time.Instant instant);
method public boolean isAlwaysEmpty();
method public boolean returnsSameText(java.time.Instant firstInstant, java.time.Instant secondInstant);
property public final androidx.wear.protolayout.expression.DynamicBuilders.DynamicString dynamicValue;
- property public final String fallbackValue;
+ property public final CharSequence fallbackValue;
}
public final class EmptyComplicationData extends androidx.wear.watchface.complications.data.ComplicationData {
diff --git a/wear/watchface/watchface-complications-data/api/restricted_current.txt b/wear/watchface/watchface-complications-data/api/restricted_current.txt
index ffdd4bf..fbf24b3 100644
--- a/wear/watchface/watchface-complications-data/api/restricted_current.txt
+++ b/wear/watchface/watchface-complications-data/api/restricted_current.txt
@@ -89,16 +89,16 @@
}
public final class DynamicComplicationText implements androidx.wear.watchface.complications.data.ComplicationText {
- ctor public DynamicComplicationText(androidx.wear.protolayout.expression.DynamicBuilders.DynamicString dynamicValue, String fallbackValue);
+ ctor public DynamicComplicationText(androidx.wear.protolayout.expression.DynamicBuilders.DynamicString dynamicValue, CharSequence fallbackValue);
method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicString getDynamicValue();
- method public String getFallbackValue();
+ method public CharSequence getFallbackValue();
method public java.time.Instant getNextChangeTime(java.time.Instant afterInstant);
method public CharSequence getTextAt(android.content.res.Resources resources, java.time.Instant instant);
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public android.support.wearable.complications.TimeDependentText getTimeDependentText();
method public boolean isAlwaysEmpty();
method public boolean returnsSameText(java.time.Instant firstInstant, java.time.Instant secondInstant);
property public final androidx.wear.protolayout.expression.DynamicBuilders.DynamicString dynamicValue;
- property public final String fallbackValue;
+ property public final CharSequence fallbackValue;
}
public final class EmptyComplicationData extends androidx.wear.watchface.complications.data.ComplicationData {
diff --git a/wear/watchface/watchface-complications-data/lint-baseline.xml b/wear/watchface/watchface-complications-data/lint-baseline.xml
index 6ffccee..3687f5e4 100644
--- a/wear/watchface/watchface-complications-data/lint-baseline.xml
+++ b/wear/watchface/watchface-complications-data/lint-baseline.xml
@@ -163,4 +163,58 @@
file="src/main/java/androidx/wear/watchface/complications/data/Type.kt"/>
</issue>
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable ComplicationData;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/wearable/complications/ComplicationData.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable ComplicationProviderInfo;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/wearable/complications/ComplicationProviderInfo.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IComplicationManager {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/android/support/wearable/complications/IComplicationManager.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IComplicationProvider {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/android/support/wearable/complications/IComplicationProvider.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="oneway interface IPreviewComplicationDataCallback {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/android/support/wearable/complications/IPreviewComplicationDataCallback.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IProviderInfoService {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/android/support/wearable/complications/IProviderInfoService.aidl"/>
+ </issue>
+
</issues>
diff --git a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluator.kt b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluator.kt
index 7aee659..7a606f0 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluator.kt
+++ b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluator.kt
@@ -20,38 +20,34 @@
import android.support.wearable.complications.ComplicationData as WireComplicationData
import android.support.wearable.complications.ComplicationData.Companion.TYPE_NO_DATA
import android.support.wearable.complications.ComplicationText as WireComplicationText
-import androidx.annotation.MainThread
+import android.util.Log
import androidx.annotation.RestrictTo
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString
import androidx.wear.protolayout.expression.PlatformDataKey
-import androidx.wear.protolayout.expression.PlatformHealthSources
import androidx.wear.protolayout.expression.pipeline.BoundDynamicType
import androidx.wear.protolayout.expression.pipeline.DynamicTypeBindingRequest
import androidx.wear.protolayout.expression.pipeline.DynamicTypeEvaluator
import androidx.wear.protolayout.expression.pipeline.DynamicTypeValueReceiver
-import androidx.wear.protolayout.expression.pipeline.SensorGatewaySingleDataProvider
+import androidx.wear.protolayout.expression.pipeline.PlatformDataProvider
+import androidx.wear.protolayout.expression.pipeline.PlatformTimeUpdateNotifier
import androidx.wear.protolayout.expression.pipeline.StateStore
-import androidx.wear.protolayout.expression.pipeline.TimeGateway
-import androidx.wear.protolayout.expression.pipeline.sensor.SensorGateway
-import java.util.Collections
import java.util.concurrent.Executor
import kotlin.coroutines.ContinuationInterceptor
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.channels.SendChannel
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.channels.onFailure
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.emitAll
-import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.mapNotNull
-import kotlinx.coroutines.flow.merge
-import kotlinx.coroutines.flow.update
-import kotlinx.coroutines.flow.updateAndGet
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.invoke
import kotlinx.coroutines.launch
@@ -62,11 +58,23 @@
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class ComplicationDataEvaluator(
private val stateStore: StateStore? = StateStore(emptyMap()),
- private val timeGateway: TimeGateway? = null,
- // TODO(b/281664278): remove the SensorGateway usage, implement PlatformDataProvider instead.
- private val sensorGateway: SensorGateway? = null,
+ private val platformTimeUpdateNotifier: PlatformTimeUpdateNotifier? = null,
+ private val platformDataProviders: Map<PlatformDataProvider, Set<PlatformDataKey<*>>> = mapOf(),
private val keepDynamicValues: Boolean = false,
) {
+ private val evaluator =
+ DynamicTypeEvaluator(
+ DynamicTypeEvaluator.Config.Builder()
+ .apply { stateStore?.let { setStateStore(it) } }
+ .apply { platformTimeUpdateNotifier?.let { setPlatformTimeUpdateNotifier(it) } }
+ .apply {
+ for ((platformDataProvider, dataKeys) in platformDataProviders) {
+ addPlatformDataProvider(platformDataProvider, dataKeys)
+ }
+ }
+ .build()
+ )
+
/**
* Returns a [Flow] that provides the evaluated [WireComplicationData].
*
@@ -86,29 +94,57 @@
.combineWithEvaluatedPlaceholder(unevaluatedData.placeholder)
.distinctUntilChanged()
- /** Evaluates "local" fields, excluding fields of type WireComplicationData. */
+ /** Evaluates "local" fields, excluding fields of type [WireComplicationData]. */
private fun evaluateTopLevelFields(
unevaluatedData: WireComplicationData
- ): Flow<WireComplicationData> = flow {
- val state: MutableStateFlow<State> = unevaluatedData.buildState()
- state.value.use {
- val evaluatedData: Flow<WireComplicationData> =
- state.mapNotNull {
- when {
- // Emitting INVALID_DATA if there's an invalid receiver.
- it.invalidReceivers.isNotEmpty() -> INVALID_DATA
- // Emitting the data if all pending receivers are done and all
- // pre-updates are satisfied.
- it.pendingReceivers.isEmpty() -> it.data
- // Skipping states that are not ready for be emitted.
- else -> null
- }
+ ): Flow<WireComplicationData> {
+ // Combine setter flows into one flow...
+ return combine(
+ unevaluatedData.topLevelSetterFlows().ifEmpty {
+ return flowOf(unevaluatedData) // If no field needs evaluation, don't combine.
+ }
+ ) { setters ->
+ // ... that builds the data from all the setters.
+ setters
+ .fold(WireComplicationData.Builder(unevaluatedData)) { builder, setter ->
+ setter(builder) ?: return@combine INVALID_DATA
}
- emitAll(evaluatedData)
+ .build()
}
}
/**
+ * Returns list of [Flow]s describing how to build the [WireComplicationData] based on dynamic
+ * values in "local" fields, excluding fields of type [WireComplicationData].
+ *
+ * When evaluation is triggered, the [Flow] emits a method that sets field(s) in the provided
+ * [WireComplicationData.Builder].
+ *
+ * Each `bindX` call returns a [Flow] of [WireComplicationDataSetter] that sets the provided
+ * fields based on the type (e.g. [Float] vs [String]), and potentially trims the dynamic value
+ * (based on [keepDynamicValues]).
+ */
+ private fun WireComplicationData.topLevelSetterFlows(): List<Flow<WireComplicationDataSetter>> =
+ buildList {
+ if (hasRangedDynamicValue()) {
+ add(
+ bindDynamicFloat(
+ rangedDynamicValue,
+ dynamicValueTrimmer = { setRangedDynamicValue(null) },
+ floatSetter = { setRangedValue(it) },
+ )
+ )
+ }
+ if (hasLongText()) add(bindDynamicText(longText) { setLongText(it) })
+ if (hasLongTitle()) add(bindDynamicText(longTitle) { setLongTitle(it) })
+ if (hasShortText()) add(bindDynamicText(shortText) { setShortText(it) })
+ if (hasShortTitle()) add(bindDynamicText(shortTitle) { setShortTitle(it) })
+ if (hasContentDescription()) {
+ add(bindDynamicText(contentDescription) { setContentDescription(it) })
+ }
+ }
+
+ /**
* Combines the receiver with the evaluated version of the provided list.
*
* If the receiver [Flow] emits [INVALID_DATA] or the input list is null or empty, this does not
@@ -125,17 +161,21 @@
) -> WireComplicationData.Builder,
): Flow<WireComplicationData> {
if (unevaluatedEntries.isNullOrEmpty()) return this
- val evaluatedEntriesFlow: Flow<List<WireComplicationData>> =
- combine(unevaluatedEntries.map { evaluate(it) })
+ val evaluatedEntriesFlow: Flow<Array<WireComplicationData>> =
+ combine(unevaluatedEntries.map { evaluate(it) }) { it }
- return this.combine(evaluatedEntriesFlow).map {
- (data: WireComplicationData, evaluatedEntries: List<WireComplicationData>?) ->
+ return this.combine(evaluatedEntriesFlow) {
+ data: WireComplicationData,
+ evaluatedEntries: Array<WireComplicationData> ->
+
// Not mutating if invalid.
- if (data === INVALID_DATA) return@map data
+ if (data === INVALID_DATA) return@combine data
// An entry is invalid, emitting invalid.
- if (evaluatedEntries.any { it === INVALID_DATA }) return@map INVALID_DATA
+ if (evaluatedEntries.any { it === INVALID_DATA }) return@combine INVALID_DATA
// All is well, mutating the input.
- return@map WireComplicationData.Builder(data).setter(evaluatedEntries).build()
+ return@combine WireComplicationData.Builder(data)
+ .setter(evaluatedEntries.toList())
+ .build()
}
}
@@ -152,257 +192,164 @@
if (unevaluatedPlaceholder == null) return this
val evaluatedPlaceholderFlow: Flow<WireComplicationData> = evaluate(unevaluatedPlaceholder)
- return this.combine(evaluatedPlaceholderFlow).map {
- (data: WireComplicationData, evaluatedPlaceholder: WireComplicationData?) ->
+ return this.combine(evaluatedPlaceholderFlow) {
+ data: WireComplicationData,
+ evaluatedPlaceholder: WireComplicationData ->
if (!keepDynamicValues && data.type != TYPE_NO_DATA) {
// Clearing the placeholder when data is not TYPE_NO_DATA (it was meant as an
// dynamic value fallback).
- return@map WireComplicationData.Builder(data).setPlaceholder(null).build()
+ return@combine WireComplicationData.Builder(data).setPlaceholder(null).build()
}
// Placeholder required but invalid, emitting invalid.
- if (evaluatedPlaceholder === INVALID_DATA) return@map INVALID_DATA
+ if (evaluatedPlaceholder === INVALID_DATA) return@combine INVALID_DATA
// All is well, mutating the input.
- return@map WireComplicationData.Builder(data)
+ return@combine WireComplicationData.Builder(data)
.setPlaceholder(evaluatedPlaceholder)
.build()
}
}
- private suspend fun WireComplicationData.buildState() =
- MutableStateFlow(State(this)).apply {
- if (hasRangedDynamicValue()) {
- addReceiver(
- rangedDynamicValue,
- dynamicValueTrimmer = { setRangedDynamicValue(null) },
- setter = { setRangedValue(it) },
- )
- }
- if (hasLongText()) addReceiver(longText) { setLongText(it) }
- if (hasLongTitle()) addReceiver(longTitle) { setLongTitle(it) }
- if (hasShortText()) addReceiver(shortText) { setShortText(it) }
- if (hasShortTitle()) addReceiver(shortTitle) { setShortTitle(it) }
- if (hasContentDescription()) {
- addReceiver(contentDescription) { setContentDescription(it) }
- }
- // Add all the receivers before we start binding them because binding can synchronously
- // trigger the receiver, which would update the data before all the fields are
- // evaluated.
- value.initEvaluation()
- }
-
- private suspend fun MutableStateFlow<State>.addReceiver(
- dynamicValue: DynamicFloat?,
+ /**
+ * Returns a [Flow] of [WireComplicationDataSetter] based on [DynamicFloat] evaluation.
+ *
+ * Uses the generic [bindDynamicType] that provides a default [Executor] and
+ * [DynamicTypeValueReceiver] based on the generated [Flow].
+ */
+ private fun bindDynamicFloat(
+ dynamicFloat: DynamicFloat?,
dynamicValueTrimmer: WireComplicationData.Builder.() -> WireComplicationData.Builder,
- setter: WireComplicationData.Builder.(Float) -> WireComplicationData.Builder,
- ) {
- dynamicValue ?: return
- val executor = currentCoroutineContext().asExecutor()
- update { state ->
- state.withPendingReceiver(
- ComplicationEvaluationResultReceiver<Float>(
- this,
- setter = { value ->
- if (!keepDynamicValues) dynamicValueTrimmer(this)
- setter(this, value)
- },
- binder = { receiver ->
- value.evaluator.bind(
- DynamicTypeBindingRequest.forDynamicFloat(
- dynamicValue,
- executor,
- receiver
- )
- )
- },
- )
- )
- }
- }
-
- private suspend fun MutableStateFlow<State>.addReceiver(
- text: WireComplicationText?,
- setter: WireComplicationData.Builder.(WireComplicationText) -> WireComplicationData.Builder,
- ) {
- val dynamicValue = text?.dynamicValue ?: return
- val executor = currentCoroutineContext().asExecutor()
- update {
- it.withPendingReceiver(
- ComplicationEvaluationResultReceiver<String>(
- this,
- setter = { value ->
- setter(
- if (keepDynamicValues) {
- WireComplicationText(value, dynamicValue)
- } else {
- WireComplicationText(value)
- }
- )
- },
- binder = { receiver ->
- value.evaluator.bind(
- DynamicTypeBindingRequest.forDynamicString(
- dynamicValue,
- ULocale.getDefault(),
- executor,
- receiver
- )
- )
- },
- )
- )
- }
+ floatSetter: WireComplicationData.Builder.(Float) -> WireComplicationData.Builder,
+ ): Flow<WireComplicationDataSetter> {
+ // If there's no dynamic value, return a no-op setter.
+ dynamicFloat ?: return flowOf { it }
+ return bindDynamicType(
+ bindingRequest = { executor, receiver ->
+ DynamicTypeBindingRequest.forDynamicFloat(dynamicFloat, executor, receiver)
+ },
+ builderSetter = { builder, value ->
+ val trimmed = if (keepDynamicValues) builder else dynamicValueTrimmer(builder)
+ floatSetter(trimmed, value)
+ }
+ )
}
/**
- * Holds the state of the continuously evaluated [WireComplicationData] and the various
- * [ComplicationEvaluationResultReceiver] that are evaluating it.
+ * Returns a [Flow] of [WireComplicationDataSetter] based on [DynamicString] evaluation (within
+ * a [WireComplicationText].
+ *
+ * Uses the generic [bindDynamicType] that provides a default [Executor] and
+ * [DynamicTypeValueReceiver] based on the generated [Flow].
*/
- private inner class State(
- val data: WireComplicationData,
- val pendingReceivers: Set<ComplicationEvaluationResultReceiver<out Any>> = setOf(),
- val invalidReceivers: Set<ComplicationEvaluationResultReceiver<out Any>> = setOf(),
- val completeReceivers: Set<ComplicationEvaluationResultReceiver<out Any>> = setOf(),
- ) : AutoCloseable {
- lateinit var evaluator: DynamicTypeEvaluator
-
- fun withPendingReceiver(receiver: ComplicationEvaluationResultReceiver<out Any>) =
- copy(pendingReceivers = pendingReceivers + receiver)
-
- fun withInvalidReceiver(receiver: ComplicationEvaluationResultReceiver<out Any>) =
- copy(
- pendingReceivers = pendingReceivers - receiver,
- invalidReceivers = invalidReceivers + receiver,
- completeReceivers = completeReceivers - receiver,
- )
-
- fun withUpdatedData(
- data: WireComplicationData,
- receiver: ComplicationEvaluationResultReceiver<out Any>,
- ) =
- copy(
- data,
- pendingReceivers = pendingReceivers - receiver,
- invalidReceivers = invalidReceivers - receiver,
- completeReceivers = completeReceivers + receiver,
- )
-
- /**
- * Initializes the internal [DynamicTypeEvaluator] if there are pending receivers.
- *
- * Should be called after all receivers were added.
- */
- suspend fun initEvaluation() {
- if (pendingReceivers.isEmpty()) return
- require(!this::evaluator.isInitialized) { "initEvaluator must be called exactly once." }
- evaluator =
- DynamicTypeEvaluator(
- DynamicTypeEvaluator.Config.Builder()
- .apply { stateStore?.let { setStateStore(it) } }
- .apply { timeGateway?.let { setTimeGateway(it) } }
- .apply { sensorGateway?.let {
- addPlatformDataProvider(
- SensorGatewaySingleDataProvider(
- sensorGateway, PlatformHealthSources.Keys.HEART_RATE_BPM
- ),
- Collections.singleton(PlatformHealthSources.Keys.HEART_RATE_BPM)
- as Set<PlatformDataKey<*>>
- )
- addPlatformDataProvider(
- SensorGatewaySingleDataProvider(
- sensorGateway, PlatformHealthSources.Keys.DAILY_STEPS
- ),
- Collections.singleton(PlatformHealthSources.Keys.DAILY_STEPS)
- as Set<PlatformDataKey<*>>
- )
- } }
- .build()
+ private fun bindDynamicText(
+ unevaluatedText: WireComplicationText?,
+ textSetter:
+ WireComplicationData.Builder.(WireComplicationText) -> WireComplicationData.Builder,
+ ): Flow<WireComplicationDataSetter> {
+ // If there's no dynamic value, return a no-op setter.
+ val dynamicString: DynamicString = unevaluatedText?.dynamicValue ?: return flowOf { it }
+ return bindDynamicType(
+ bindingRequest = { executor, receiver ->
+ DynamicTypeBindingRequest.forDynamicString(
+ dynamicString,
+ ULocale.getDefault(),
+ executor,
+ receiver,
)
- try {
- for (receiver in pendingReceivers) receiver.bind()
- // TODO(b/270697243): Remove this invoke once DynamicTypeEvaluator is thread safe.
- Dispatchers.Main.immediate.invoke {
- // These need to be called on the main thread.
- for (receiver in pendingReceivers) receiver.startEvaluation()
- }
- } catch (e: Throwable) {
- // Cleanup on initialization failure.
- close()
- throw e
+ },
+ builderSetter = { builder, value ->
+ val evaluatedText =
+ if (keepDynamicValues) {
+ WireComplicationText(value, dynamicString)
+ } else {
+ WireComplicationText(value)
+ }
+ textSetter(builder, evaluatedText)
}
- }
-
- override fun close() {
- // TODO(b/270697243): Remove this launch once DynamicTypeEvaluator is thread safe.
- CoroutineScope(Dispatchers.Main.immediate).launch {
- // These need to be called on the main thread.
- for (receiver in pendingReceivers + invalidReceivers + completeReceivers) {
- receiver.close()
- }
- }
- }
-
- private fun copy(
- data: WireComplicationData = this.data,
- pendingReceivers: Set<ComplicationEvaluationResultReceiver<out Any>> =
- this.pendingReceivers,
- invalidReceivers: Set<ComplicationEvaluationResultReceiver<out Any>> =
- this.invalidReceivers,
- completeReceivers: Set<ComplicationEvaluationResultReceiver<out Any>> =
- this.completeReceivers,
- ) =
- State(
- data = data,
- pendingReceivers = pendingReceivers,
- invalidReceivers = invalidReceivers,
- completeReceivers = completeReceivers,
- )
+ )
}
- private inner class ComplicationEvaluationResultReceiver<T : Any>(
- private val state: MutableStateFlow<State>,
- private val setter: WireComplicationData.Builder.(T) -> WireComplicationData.Builder,
- private val binder: (ComplicationEvaluationResultReceiver<T>) -> BoundDynamicType,
- ) : DynamicTypeValueReceiver<T>, AutoCloseable {
- @Volatile // In case bind() and close() are called on different threads.
- private lateinit var boundDynamicType: BoundDynamicType
-
- fun bind() {
- boundDynamicType = binder(this)
- }
-
- // TODO(b/270697243): Remove this annotation once DynamicTypeEvaluator is thread safe.
- @MainThread
- fun startEvaluation() {
- boundDynamicType.startEvaluation()
- }
-
- // TODO(b/270697243): Remove this annotation once DynamicTypeEvaluator is thread safe.
- @MainThread
- override fun close() {
- boundDynamicType.close()
- }
-
- override fun onData(newData: T) {
- state.update {
- it.withUpdatedData(
- setter(WireComplicationData.Builder(it.data), newData).build(),
- this
- )
+ /**
+ * Returns a [Flow] of [WireComplicationDataSetter] based on a [DynamicTypeBindingRequest] and a
+ * [builderSetter] that takes the evaluated raw value and sets the relevant builder field..
+ *
+ * In high-level terms, this converts the [DynamicTypeValueReceiver] callback given to
+ * [DynamicTypeEvaluator.bind] into a Kotlin [Flow], for easier use (e.g. to [combine] binding
+ * of multiple fields). The [Flow] is conflated (ignoring emissions that we didn't have time to
+ * process), as only the latest evaluation matters.
+ *
+ * The actual implementation of [DynamicTypeValueReceiver] is separated to the helper class
+ * [DynamicTypeValueReceiverToChannelConverter].
+ */
+ private fun <T : Any> bindDynamicType(
+ bindingRequest: (Executor, DynamicTypeValueReceiver<T>) -> DynamicTypeBindingRequest,
+ builderSetter: (WireComplicationData.Builder, T) -> WireComplicationData.Builder,
+ ): Flow<WireComplicationDataSetter> =
+ callbackFlow {
+ // Binding DynamicTypeEvaluator to the provided binding request.
+ val boundDynamicType: BoundDynamicType =
+ evaluator.bind(
+ bindingRequest(
+ currentCoroutineContext().asExecutor(),
+ DynamicTypeValueReceiverToChannelConverter(
+ /* callbackFlow */ channel,
+ builderSetter
+ )
+ )
+ )
+ // Start evaluation.
+ // TODO(b/267599473): Remove dispatches when DynamicTypeEvaluator is thread safe.
+ Dispatchers.Main.immediate { boundDynamicType.startEvaluation() }
+ awaitClose {
+ // Stop evaluation when the Flow (created by callbackFlow) is closed.
+ CoroutineScope(Dispatchers.Main.immediate).launch { boundDynamicType.close() }
+ }
}
+ .conflate() // We only care about the latest data for each field.
+
+ /**
+ * Converts [DynamicTypeValueReceiver] into a [SendChannel] (from a [callbackFlow]).
+ *
+ * When [onData] is invoked, emits a method that applies the [builderSetter] on the data. When
+ * [onInvalidated] is invoked, emits a method that returns `null`.
+ */
+ private class DynamicTypeValueReceiverToChannelConverter<T : Any>(
+ private val channel: SendChannel<WireComplicationDataSetter>,
+ private val builderSetter:
+ (WireComplicationData.Builder, T) -> WireComplicationData.Builder,
+ ) : DynamicTypeValueReceiver<T> {
+ override fun onData(newData: T) {
+ channel
+ // Setter method that applies the builderSetter.
+ .trySend { builder -> builderSetter(builder, newData) }
+ // Shouldn't fail for overflow as we conflate the flow.
+ .onFailure { e -> Log.e(TAG, "Failed sending dynamic update.", e) }
}
override fun onInvalidated() {
- state.update { it.withInvalidReceiver(this) }
+ channel
+ // Setter method that returns null.
+ .trySend { null }
+ // Shouldn't fail for overflow as we conflate the flow.
+ .onFailure { e -> Log.e(TAG, "Failed sending dynamic update.", e) }
}
}
companion object {
+ private const val TAG = "ComplicationDataEvaluator"
+
val INVALID_DATA: WireComplicationData = NoDataComplicationData().asWireComplicationData()
}
}
/**
- * Replacement for CoroutineDispatcher.asExecutor extension due to
+ * Describes a method that sets values on the [WireComplicationData.Builder]. When field is
+ * invalidated, the method should return `null`.
+ */
+private typealias WireComplicationDataSetter =
+ (WireComplicationData.Builder) -> WireComplicationData.Builder?
+
+/**
+ * Replacement for [kotlinx.coroutines.asExecutor] extension due to
* https://github.com/Kotlin/kotlinx.coroutines/pull/3683.
*/
internal fun CoroutineContext.asExecutor() = Executor { runnable ->
@@ -413,35 +360,3 @@
runnable.run()
}
}
-
-/** Replacement of [kotlinx.coroutines.flow.combine], which doesn't seem to work. */
-internal fun <T> combine(flows: List<Flow<T>>): Flow<List<T>> = flow {
- data class ValueExists(val value: T?, val exists: Boolean)
- val latest = MutableStateFlow(List(flows.size) { ValueExists(null, false) })
- @Suppress("UNCHECKED_CAST") // Flow<List<T?>> -> Flow<List<T>> safe after filtering exists.
- emitAll(
- flows
- .mapIndexed { i, flow -> flow.map { i to it } } // List<Flow<Int, T>> (indexed flows)
- .merge() // Flow<Int, T>
- .map { (i, value) ->
- // Updating latest and returning the current latest.
- latest.updateAndGet {
- val newLatest = it.toMutableList()
- newLatest[i] = ValueExists(value, true)
- newLatest
- }
- } // Flow<List<ValueExists>>
- // Filtering emissions until we have all values.
- .filter { values -> values.all { it.exists } }
- // Flow<List<T>> + defensive copy.
- .map { values -> values.map { it.value } } as Flow<List<T>>
- )
-}
-
-/**
- * Another replacement of [kotlinx.coroutines.flow.combine] which is similar to
- * `combine(List<Flow<T>>)` but allows different types for each flow.
- */
-@Suppress("UNCHECKED_CAST")
-internal fun <T1, T2> Flow<T1>.combine(other: Flow<T2>): Flow<Pair<T1, T2>> =
- combine(listOf(this as Flow<*>, other as Flow<*>)).map { (a, b) -> (a as T1) to (b as T2) }
diff --git a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
index 174af66..843ed4e 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
+++ b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
@@ -121,6 +121,9 @@
@ComplicationDisplayPolicy public val displayPolicy: Int,
public val dynamicValueInvalidationFallback: ComplicationData?,
) {
+ /** Throws [IllegalArgumentException] if the [ComplicationData] is invalid. */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) open fun validate() {}
+
/**
* [tapAction] which is a [PendingIntent] unfortunately can't be serialized. This property is
* 'true' if tapAction has been lost due to serialization (typically because it has been cached
@@ -187,10 +190,7 @@
override fun equals(other: Any?): Boolean =
other is ComplicationData && asWireComplicationData() == other.asWireComplicationData()
- /**
- * Similar to [equals], but avoids comparing evaluated fields (if dynamic values exist).
- *
- */
+ /** Similar to [equals], but avoids comparing evaluated fields (if dynamic values exist). */
@RestrictTo(RestrictTo.Scope.LIBRARY)
infix fun equalsUnevaluated(other: ComplicationData): Boolean =
asWireComplicationData() equalsUnevaluated other.asWireComplicationData()
@@ -791,7 +791,8 @@
@ColorInt val colors: IntArray,
@get:JvmName("isInterpolated") val interpolated: Boolean
) {
- init {
+ /** Throws [IllegalArgumentException] if the [ColorRamp] is invalid. */
+ internal fun validate() {
require(colors.size <= 7) { "colors can have no more than seven entries" }
}
@@ -914,7 +915,9 @@
dynamicValueInvalidationFallback = dynamicValueInvalidationFallback,
) {
- init {
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ override fun validate() {
+ super.validate()
require(min <= max) { "min must be lower than or equal to max" }
require(value == PLACEHOLDER || value in min..max) { "value must be between min and max" }
require(max != Float.MAX_VALUE) { "Float.MAX_VALUE is reserved and can't be used for max" }
@@ -922,8 +925,8 @@
"At least one of monochromaticImage, smallImage, text or title must be set"
}
if (valueType == TYPE_PERCENTAGE) {
- require(min == 0f)
- require(max == 100f)
+ require(min == 0f) { "min must be 0 for TYPE_PERCENTAGE" }
+ require(max == 100f) { "max must be 100 for TYPE_PERCENTAGE" }
}
}
@@ -1275,13 +1278,16 @@
dynamicValueInvalidationFallback = dynamicValueInvalidationFallback,
) {
- init {
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ override fun validate() {
+ super.validate()
require(targetValue != Float.MAX_VALUE) {
"Float.MAX_VALUE is reserved and can't be used for target"
}
require(monochromaticImage != null || smallImage != null || text != null || title != null) {
"At least one of monochromaticImage, smallImage, text or title must be set"
}
+ colorRamp?.validate()
}
/**
@@ -1575,10 +1581,15 @@
dynamicValueInvalidationFallback = dynamicValueInvalidationFallback,
) {
- init {
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ override fun validate() {
+ super.validate()
require(monochromaticImage != null || smallImage != null || text != null || title != null) {
"At least one of monochromaticImage, smallImage, text or title must be set"
}
+ for (element in elements) {
+ element.validate()
+ }
}
/**
* Describes a single value within a [WeightedElementsComplicationData].
@@ -1596,7 +1607,8 @@
@FloatRange(from = 0.0, fromInclusive = false) val weight: Float,
@ColorInt val color: Int
) {
- init {
+ /** Throws [IllegalArgumentException] if the [Element] is invalid. */
+ internal fun validate() {
require(weight > 0) { "The weight must be > 0" }
}
@@ -2452,15 +2464,17 @@
} else {
val elementWeights = this.elementWeights!!
val elementColors = this.elementColors!!
- require(elementWeights.size == elementColors.size) {
- "elementWeights and elementColors must have the same size"
+ if (elementWeights.size != elementColors.size) {
+ Log.e(
+ TAG,
+ "elementWeights and elementColors must have the same size"
+ )
}
elementWeights
- .mapIndexed { index, weight ->
- WeightedElementsComplicationData.Element(
- weight,
- elementColors[index]
- )
+ .asSequence()
+ .zip(elementColors.asSequence())
+ .map { (weight, color) ->
+ WeightedElementsComplicationData.Element(weight, color)
}
.toList()
},
diff --git a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Text.kt b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Text.kt
index 486e1a8..f6b9d00 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Text.kt
+++ b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Text.kt
@@ -549,10 +549,10 @@
internal fun WireComplicationText.toApiComplicationText(
placeholderAware: Boolean = false
): ComplicationText =
- if (placeholderAware && isPlaceholder) {
- ComplicationText.PLACEHOLDER
- } else {
- DelegatingComplicationText(this)
+ when {
+ placeholderAware && isPlaceholder -> ComplicationText.PLACEHOLDER
+ dynamicValue != null -> DynamicComplicationText(dynamicValue!!, surroundingText ?: "")
+ else -> DelegatingComplicationText(this)
}
/** Converts a [TimeZone] into an equivalent [java.util.TimeZone]. */
@@ -620,7 +620,7 @@
*/
public class DynamicComplicationText(
public val dynamicValue: DynamicString,
- public val fallbackValue: String,
+ public val fallbackValue: CharSequence,
) : ComplicationText {
private val delegate =
DelegatingComplicationText(WireComplicationText(fallbackValue, dynamicValue))
diff --git a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluatorTest.kt b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluatorTest.kt
index 01fdd1e..ac5eec6 100644
--- a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluatorTest.kt
+++ b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluatorTest.kt
@@ -23,22 +23,24 @@
import android.util.Log
import androidx.wear.protolayout.expression.AppDataKey
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat
-import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString
import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue
+import androidx.wear.protolayout.expression.PlatformHealthSources
+import androidx.wear.protolayout.expression.pipeline.PlatformDataProvider
import androidx.wear.protolayout.expression.pipeline.StateStore
-import androidx.wear.protolayout.expression.pipeline.TimeGateway
import androidx.wear.watchface.complications.data.ComplicationDataEvaluator.Companion.INVALID_DATA
import com.google.common.truth.Expect
import com.google.common.truth.Truth.assertThat
-import java.time.Instant
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestDispatcher
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -54,6 +56,9 @@
class ComplicationDataEvaluatorTest {
@get:Rule val expect = Expect.create()
+ @OptIn(ExperimentalCoroutinesApi::class) // StandardTestDispatcher no longer experimental.
+ private val dispatcher: CoroutineDispatcher = StandardTestDispatcher()
+
@Before
fun setup() {
ShadowLog.setLoggable("ComplicationData", Log.DEBUG)
@@ -300,13 +305,15 @@
evaluator
.evaluate(expressed)
.shareIn(
- CoroutineScope(Dispatchers.Main.immediate),
+ CoroutineScope(dispatcher),
SharingStarted.Eagerly,
replay = 10,
)
+ advanceUntilIdle()
for (state in scenario.states) {
stateStore.setAppStateEntryValues(state)
+ advanceUntilIdle()
}
expect
@@ -318,33 +325,38 @@
@Test
fun evaluate_cancelled_cleansUp() = runBlocking {
+ // Arrange
val expressed =
WireComplicationData.Builder(TYPE_NO_DATA)
- .setRangedDynamicValue(
- // Uses TimeGateway, which needs cleaning up.
- DynamicInstant.withSecondsPrecision(Instant.EPOCH)
- .durationUntil(DynamicInstant.platformTimeWithSecondsPrecision())
- .secondsPart
- .asFloat()
- )
+ .setRangedDynamicValue(PlatformHealthSources.heartRateBpm())
.build()
- val timeGateway = mock<TimeGateway>()
- val evaluator = ComplicationDataEvaluator(timeGateway = timeGateway)
+
+ val provider = mock<PlatformDataProvider>()
+ val evaluator = ComplicationDataEvaluator(
+ platformDataProviders = mapOf(
+ provider to setOf(PlatformHealthSources.Keys.HEART_RATE_BPM)
+ )
+ )
val flow = evaluator.evaluate(expressed)
- // Validity check - TimeGateway not used until Flow collection.
- verifyNoInteractions(timeGateway)
- val job = launch(Dispatchers.Main.immediate) { flow.collect {} }
+ // Validity check - Platform provider not used until Flow collection.
+ verifyNoInteractions(provider)
+ val job = launch(dispatcher) { flow.collect {} }
try {
- // Validity check - TimeGateway registered while collection is in progress.
- verify(timeGateway).registerForUpdates(any(), any())
- verifyNoMoreInteractions(timeGateway)
+ advanceUntilIdle()
+ // Validity check - Platform provider registered while collection is in progress.
+ verify(provider).setReceiver(any(), any())
+ verifyNoMoreInteractions(provider)
} finally {
+ // Act
job.cancel()
+ advanceUntilIdle()
}
- verify(timeGateway).unregisterForUpdates(any())
- verifyNoMoreInteractions(timeGateway)
+ // Assert
+ advanceUntilIdle()
+ verify(provider).clearReceiver()
+ verifyNoMoreInteractions(provider)
}
@Test
@@ -410,6 +422,11 @@
)
}
+ private fun advanceUntilIdle() {
+ @OptIn(ExperimentalCoroutinesApi::class) // StandardTestDispatcher no longer experimental.
+ (dispatcher as TestDispatcher).scheduler.advanceUntilIdle()
+ }
+
private companion object {
/** Converts `[{a: A}, {b: B}, {c: C}]` to `[{a: A}, {a: A, b: B}, {a: A, b: B, c: C}]`. */
fun <K, V> aggregate(vararg maps: Map<K, V>): List<Map<K, V>> =
diff --git a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt
index d975e3d..7ce2b0a 100644
--- a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt
+++ b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt
@@ -3011,7 +3011,7 @@
@Test
fun rangedValue_valid(@TestParameter scenario: RangedValueValidScenario) {
- scenario.build()
+ scenario.build().validate()
}
enum class RangedValueInvalidScenario(val build: () -> RangedValueComplicationData) {
@@ -3022,7 +3022,7 @@
@Test
fun rangedValue_invalid(@TestParameter scenario: RangedValueInvalidScenario) {
- assertFailsWith<IllegalArgumentException> { scenario.build() }
+ assertFailsWith<IllegalArgumentException> { scenario.build().validate() }
}
companion object {
diff --git a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/TextTest.kt b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/TextTest.kt
index bdb7c92..0af4fd4 100644
--- a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/TextTest.kt
+++ b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/TextTest.kt
@@ -18,12 +18,13 @@
import android.content.Context
import android.icu.util.TimeZone
-import android.support.wearable.complications.ComplicationText
import android.support.wearable.complications.ComplicationText as WireComplicationText
import android.support.wearable.complications.ComplicationText.TimeDifferenceBuilder as WireTimeDifferenceBuilder
import android.support.wearable.complications.ComplicationText.TimeFormatBuilder as WireTimeFormatBuilder
import android.support.wearable.complications.TimeFormatText
import androidx.test.core.app.ApplicationProvider
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString
+import androidx.wear.watchface.complications.data.ParcelableSubject.Companion.assertThat
import com.google.common.truth.Truth.assertThat
import java.time.Instant
import java.util.concurrent.TimeUnit
@@ -36,9 +37,9 @@
@Test
public fun plainText() {
val text = PlainComplicationText.Builder("abc").build()
- ParcelableSubject.assertThat(text.toWireComplicationText())
+ assertThat(text.toWireComplicationText())
.hasSameSerializationAs(WireComplicationText.plainText("abc"))
- ParcelableSubject.assertThat(text.toWireComplicationText())
+ assertThat(text.toWireComplicationText())
.hasDifferentSerializationAs(WireComplicationText.plainText("abc1"))
}
@@ -55,7 +56,7 @@
.setMinimumTimeUnit(TimeUnit.SECONDS)
.build()
- ParcelableSubject.assertThat(text.toWireComplicationText())
+ assertThat(text.toWireComplicationText())
.hasSameSerializationAs(
WireTimeDifferenceBuilder()
.setStyle(WireComplicationText.DIFFERENCE_STYLE_STOPWATCH)
@@ -85,7 +86,7 @@
.setMinimumTimeUnit(TimeUnit.SECONDS)
.build()
- ParcelableSubject.assertThat(text.toWireComplicationText())
+ assertThat(text.toWireComplicationText())
.hasSameSerializationAs(
WireTimeDifferenceBuilder()
.setStyle(WireComplicationText.DIFFERENCE_STYLE_STOPWATCH)
@@ -111,7 +112,7 @@
.setTimeZone(TimeZone.getTimeZone("Europe/London"))
.build()
- ParcelableSubject.assertThat(text.toWireComplicationText())
+ assertThat(text.toWireComplicationText())
.hasSameSerializationAs(
WireTimeFormatBuilder()
.setFormat("h:m")
@@ -122,6 +123,16 @@
)
}
+ @Test
+ public fun dynamicText() {
+ val text = DynamicComplicationText(DynamicString.constant("dynamic"), "fallback")
+
+ assertThat(text.toWireComplicationText())
+ .hasSameSerializationAs(
+ WireComplicationText("fallback", DynamicString.constant("dynamic"))
+ )
+ }
+
private fun getResource() = ApplicationProvider.getApplicationContext<Context>().resources
}
@@ -197,6 +208,19 @@
}
@Test
+ public fun dynamicText() {
+ val wireText = WireComplicationText("fallback", DynamicString.constant("dynamic"))
+
+ val text = wireText.toApiComplicationText()
+
+ assertThat(text).isInstanceOf(DynamicComplicationText::class.java)
+ text as DynamicComplicationText
+ assertThat(text.dynamicValue.toDynamicStringByteArray())
+ .isEqualTo(DynamicString.constant("dynamic").toDynamicStringByteArray())
+ assertThat(text.fallbackValue).isEqualTo("fallback")
+ }
+
+ @Test
public fun testGetMinimumTimeUnit_WithValidTimeDependentTextObject() {
val minimumTimeUnit = TimeUnit.SECONDS
@@ -227,8 +251,8 @@
@Test
public fun testGetMinimumTimeUnit_WithWrongTimeDependentTextObject() {
- val tft = TimeFormatText("E 'in' LLL", ComplicationText.FORMAT_STYLE_DEFAULT, null)
- val text = TimeDifferenceComplicationText(ComplicationText("test", tft))
+ val tft = TimeFormatText("E 'in' LLL", WireComplicationText.FORMAT_STYLE_DEFAULT, null)
+ val text = TimeDifferenceComplicationText(WireComplicationText("test", tft))
assertNull(text.getMinimumTimeUnit())
}
diff --git a/wear/watchface/watchface-data/lint-baseline.xml b/wear/watchface/watchface-data/lint-baseline.xml
index cc0a7eb..ca8460c 100644
--- a/wear/watchface/watchface-data/lint-baseline.xml
+++ b/wear/watchface/watchface-data/lint-baseline.xml
@@ -19,4 +19,337 @@
file="src/main/java/androidx/wear/watchface/data/WatchFaceColorsWireFormat.java"/>
</issue>
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable ComplicationRenderParams;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/data/ComplicationRenderParams.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable ComplicationSlotMetadataWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/data/ComplicationSlotMetadataWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable ComplicationStateWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/data/ComplicationStateWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable ContentDescriptionLabel;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/wearable/watchface/accessibility/ContentDescriptionLabel.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable CrashInfoParcel;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/data/CrashInfoParcel.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable DefaultProviderPoliciesParams;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/data/DefaultProviderPoliciesParams.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable EditorStateWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/editor/data/EditorStateWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable GetComplicationSlotMetadataParams;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/data/GetComplicationSlotMetadataParams.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable GetUserStyleFlavorsParams;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/data/GetUserStyleFlavorsParams.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable GetUserStyleSchemaParams;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/data/GetUserStyleSchemaParams.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable HeadlessWatchFaceInstanceParams;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/data/HeadlessWatchFaceInstanceParams.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IEditorObserver {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/editor/IEditorObserver.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IEditorService {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/editor/IEditorService.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IHeadlessWatchFace {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/IHeadlessWatchFace.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IInteractiveWatchFace {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/IInteractiveWatchFace.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IPendingInteractiveWatchFace {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/IPendingInteractiveWatchFace.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IRemoteWatchFaceView {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/IRemoteWatchFaceView.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IWatchFaceControlService {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/IWatchFaceControlService.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IWatchFaceService {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/android/support/wearable/watchface/IWatchFaceService.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IWatchfaceListener {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/IWatchfaceListener.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IWatchfaceReadyListener {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/IWatchfaceReadyListener.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable IdAndComplicationDataWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/data/IdAndComplicationDataWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable IdAndComplicationStateWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/data/IdAndComplicationStateWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable IdTypeAndDefaultProviderPolicyWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/data/IdTypeAndDefaultProviderPolicyWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable ImmutableSystemState;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/data/ImmutableSystemState.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable ParcelableWrapper;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/wearable/watchface/ParcelableWrapper.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable RenderParametersWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/data/RenderParametersWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable UserStyleFlavorsWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/style/data/UserStyleFlavorsWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable UserStyleSchemaWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/style/data/UserStyleSchemaWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable UserStyleWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/style/data/UserStyleWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable WallpaperInteractiveWatchFaceInstanceParams;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/data/WallpaperInteractiveWatchFaceInstanceParams.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable WatchFaceColorsWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/data/WatchFaceColorsWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable WatchFaceOverlayStyleWireFormat;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/data/WatchFaceOverlayStyleWireFormat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable WatchFaceRenderParams;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/data/WatchFaceRenderParams.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable WatchFaceStyle;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/wearable/watchface/WatchFaceStyle.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable WatchFaceSurfaceRenderParams;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/control/data/WatchFaceSurfaceRenderParams.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="parcelable WatchUiState;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/data/WatchUiState.aidl"/>
+ </issue>
+
</issues>
diff --git a/wear/watchface/watchface-guava/src/test/java/androidx/wear/watchface/GlesRenderer.java b/wear/watchface/watchface-guava/src/test/java/androidx/wear/watchface/GlesRenderer.java
index 7f70e72..c29bd9e 100644
--- a/wear/watchface/watchface-guava/src/test/java/androidx/wear/watchface/GlesRenderer.java
+++ b/wear/watchface/watchface-guava/src/test/java/androidx/wear/watchface/GlesRenderer.java
@@ -21,8 +21,6 @@
import androidx.annotation.NonNull;
import androidx.wear.watchface.style.CurrentUserStyleRepository;
-import org.jetbrains.annotations.NotNull;
-
import java.time.ZonedDateTime;
// This class tests that a Java class extending ListenableGlesRenderer can successfully be compiled.
@@ -30,9 +28,9 @@
public class GlesRenderer extends ListenableGlesRenderer {
public GlesRenderer(
- @NotNull SurfaceHolder surfaceHolder,
- @NotNull WatchState watchState,
- @NotNull CurrentUserStyleRepository currentUserStyleRepository,
+ @NonNull SurfaceHolder surfaceHolder,
+ @NonNull WatchState watchState,
+ @NonNull CurrentUserStyleRepository currentUserStyleRepository,
long interactiveTickInterval)
throws GlesException {
super(surfaceHolder, currentUserStyleRepository, watchState, interactiveTickInterval);
diff --git a/wear/watchface/watchface-samples-minimal-complications/src/main/java/androidx/wear/watchface/samples/minimal/complications/WatchFaceService.java b/wear/watchface/watchface-samples-minimal-complications/src/main/java/androidx/wear/watchface/samples/minimal/complications/WatchFaceService.java
index 091a976..0d72556 100644
--- a/wear/watchface/watchface-samples-minimal-complications/src/main/java/androidx/wear/watchface/samples/minimal/complications/WatchFaceService.java
+++ b/wear/watchface/watchface-samples-minimal-complications/src/main/java/androidx/wear/watchface/samples/minimal/complications/WatchFaceService.java
@@ -40,8 +40,6 @@
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import org.jetbrains.annotations.NotNull;
-
/** The service hosting the watch face. */
public class WatchFaceService extends ListenableWatchFaceService {
public static final RectF COMPLICATION_BOUNDS = new RectF(.3f, 0.7f, .7f, .9f);
@@ -51,13 +49,13 @@
return resources.getInteger(R.integer.complication_slot_id);
}
- @NotNull
+ @NonNull
@Override
protected ListenableFuture<WatchFace> createWatchFaceFuture(
- @NotNull SurfaceHolder surfaceHolder,
- @NotNull WatchState watchState,
- @NotNull ComplicationSlotsManager complicationSlotsManager,
- @NotNull CurrentUserStyleRepository currentUserStyleRepository) {
+ @NonNull SurfaceHolder surfaceHolder,
+ @NonNull WatchState watchState,
+ @NonNull ComplicationSlotsManager complicationSlotsManager,
+ @NonNull CurrentUserStyleRepository currentUserStyleRepository) {
Renderer renderer =
new WatchFaceRenderer(
getResources(),
@@ -73,7 +71,7 @@
new Intent(this, ComplicationRationalActivity.class)));
}
- @NotNull
+ @NonNull
@Override
public ComplicationSlotInflationFactory getComplicationSlotInflationFactory(
@NonNull CurrentUserStyleRepository currentUserStyleRepository) {
diff --git a/wear/watchface/watchface-samples-minimal-instances/src/main/java/androidx/wear/watchface/samples/minimal/instances/WatchFaceRenderer.java b/wear/watchface/watchface-samples-minimal-instances/src/main/java/androidx/wear/watchface/samples/minimal/instances/WatchFaceRenderer.java
index 6b3406a..801e194 100644
--- a/wear/watchface/watchface-samples-minimal-instances/src/main/java/androidx/wear/watchface/samples/minimal/instances/WatchFaceRenderer.java
+++ b/wear/watchface/watchface-samples-minimal-instances/src/main/java/androidx/wear/watchface/samples/minimal/instances/WatchFaceRenderer.java
@@ -44,8 +44,6 @@
import kotlin.Unit;
-import org.jetbrains.annotations.NotNull;
-
import java.time.ZonedDateTime;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@@ -71,10 +69,10 @@
private TimeRenderer mTimeRenderer;
public WatchFaceRenderer(
- @NotNull SurfaceHolder surfaceHolder,
- @NotNull CurrentUserStyleRepository currentUserStyleRepository,
- @NotNull WatchState watchState,
- @NotNull Resources resources) {
+ @NonNull SurfaceHolder surfaceHolder,
+ @NonNull CurrentUserStyleRepository currentUserStyleRepository,
+ @NonNull WatchState watchState,
+ @NonNull Resources resources) {
super(
surfaceHolder,
currentUserStyleRepository,
@@ -104,7 +102,7 @@
@Override
public void render(
- @NotNull Canvas canvas, @NotNull Rect rect, @NotNull ZonedDateTime zonedDateTime) {
+ @NonNull Canvas canvas, @NonNull Rect rect, @NonNull ZonedDateTime zonedDateTime) {
mTimeRenderer.render(canvas, rect, zonedDateTime, getRenderParameters());
}
@@ -130,9 +128,9 @@
private interface TimeRenderer {
void render(
- @NotNull Canvas canvas,
- @NotNull Rect rect,
- @NotNull ZonedDateTime zonedDateTime,
+ @NonNull Canvas canvas,
+ @NonNull Rect rect,
+ @NonNull ZonedDateTime zonedDateTime,
RenderParameters renderParameters);
}
@@ -195,9 +193,9 @@
@Override
public void render(
- @NotNull Canvas canvas,
- @NotNull Rect rect,
- @NotNull ZonedDateTime zonedDateTime,
+ @NonNull Canvas canvas,
+ @NonNull Rect rect,
+ @NonNull ZonedDateTime zonedDateTime,
RenderParameters renderParameters) {
mPaint.setColor(Color.BLACK);
canvas.drawRect(rect, mPaint);
@@ -269,9 +267,9 @@
@Override
public void render(
- @NotNull Canvas canvas,
- @NotNull Rect rect,
- @NotNull ZonedDateTime zonedDateTime,
+ @NonNull Canvas canvas,
+ @NonNull Rect rect,
+ @NonNull ZonedDateTime zonedDateTime,
RenderParameters renderParameters) {
boolean isActive = renderParameters.getDrawMode() != DrawMode.AMBIENT;
int hour = zonedDateTime.getHour();
diff --git a/wear/watchface/watchface-samples-minimal-instances/src/main/java/androidx/wear/watchface/samples/minimal/instances/WatchFaceService.java b/wear/watchface/watchface-samples-minimal-instances/src/main/java/androidx/wear/watchface/samples/minimal/instances/WatchFaceService.java
index c52bde5..d06480a 100644
--- a/wear/watchface/watchface-samples-minimal-instances/src/main/java/androidx/wear/watchface/samples/minimal/instances/WatchFaceService.java
+++ b/wear/watchface/watchface-samples-minimal-instances/src/main/java/androidx/wear/watchface/samples/minimal/instances/WatchFaceService.java
@@ -30,16 +30,14 @@
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import org.jetbrains.annotations.NotNull;
-
/** The service that defines the watch face. */
public class WatchFaceService extends ListenableWatchFaceService {
- @NotNull
+ @NonNull
@Override
protected ListenableFuture<WatchFace> createWatchFaceFuture(
- @NotNull SurfaceHolder surfaceHolder,
- @NotNull WatchState watchState,
+ @NonNull SurfaceHolder surfaceHolder,
+ @NonNull WatchState watchState,
@NonNull ComplicationSlotsManager complicationSlotsManager,
@NonNull CurrentUserStyleRepository currentUserStyleRepository) {
Renderer renderer =
diff --git a/wear/watchface/watchface-samples-minimal-style/src/main/java/androidx/wear/watchface/samples/minimal/style/WatchFaceRenderer.java b/wear/watchface/watchface-samples-minimal-style/src/main/java/androidx/wear/watchface/samples/minimal/style/WatchFaceRenderer.java
index 9ee42df..7bddee6 100644
--- a/wear/watchface/watchface-samples-minimal-style/src/main/java/androidx/wear/watchface/samples/minimal/style/WatchFaceRenderer.java
+++ b/wear/watchface/watchface-samples-minimal-style/src/main/java/androidx/wear/watchface/samples/minimal/style/WatchFaceRenderer.java
@@ -42,8 +42,6 @@
import kotlin.Unit;
-import org.jetbrains.annotations.NotNull;
-
import java.time.ZonedDateTime;
import java.util.concurrent.TimeUnit;
@@ -66,10 +64,10 @@
private TimeRenderer mTimeRenderer;
public WatchFaceRenderer(
- @NotNull SurfaceHolder surfaceHolder,
- @NotNull CurrentUserStyleRepository currentUserStyleRepository,
- @NotNull WatchState watchState,
- @NotNull Resources resources) {
+ @NonNull SurfaceHolder surfaceHolder,
+ @NonNull CurrentUserStyleRepository currentUserStyleRepository,
+ @NonNull WatchState watchState,
+ @NonNull Resources resources) {
super(
surfaceHolder,
currentUserStyleRepository,
@@ -97,7 +95,7 @@
@Override
public void render(
- @NotNull Canvas canvas, @NotNull Rect rect, @NotNull ZonedDateTime zonedDateTime) {
+ @NonNull Canvas canvas, @NonNull Rect rect, @NonNull ZonedDateTime zonedDateTime) {
mTimeRenderer.render(canvas, rect, zonedDateTime, getRenderParameters());
}
@@ -123,9 +121,9 @@
private interface TimeRenderer {
void render(
- @NotNull Canvas canvas,
- @NotNull Rect rect,
- @NotNull ZonedDateTime zonedDateTime,
+ @NonNull Canvas canvas,
+ @NonNull Rect rect,
+ @NonNull ZonedDateTime zonedDateTime,
RenderParameters renderParameters);
}
@@ -143,9 +141,9 @@
@Override
public void render(
- @NotNull Canvas canvas,
- @NotNull Rect rect,
- @NotNull ZonedDateTime zonedDateTime,
+ @NonNull Canvas canvas,
+ @NonNull Rect rect,
+ @NonNull ZonedDateTime zonedDateTime,
RenderParameters renderParameters) {
mPaint.setColor(Color.BLACK);
canvas.drawRect(rect, mPaint);
@@ -213,9 +211,9 @@
@Override
public void render(
- @NotNull Canvas canvas,
- @NotNull Rect rect,
- @NotNull ZonedDateTime zonedDateTime,
+ @NonNull Canvas canvas,
+ @NonNull Rect rect,
+ @NonNull ZonedDateTime zonedDateTime,
RenderParameters renderParameters) {
boolean isActive = renderParameters.getDrawMode() != DrawMode.AMBIENT;
int hour = zonedDateTime.getHour();
diff --git a/wear/watchface/watchface-samples-minimal-style/src/main/java/androidx/wear/watchface/samples/minimal/style/WatchFaceService.java b/wear/watchface/watchface-samples-minimal-style/src/main/java/androidx/wear/watchface/samples/minimal/style/WatchFaceService.java
index b1389cf..8756c93 100644
--- a/wear/watchface/watchface-samples-minimal-style/src/main/java/androidx/wear/watchface/samples/minimal/style/WatchFaceService.java
+++ b/wear/watchface/watchface-samples-minimal-style/src/main/java/androidx/wear/watchface/samples/minimal/style/WatchFaceService.java
@@ -30,16 +30,14 @@
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import org.jetbrains.annotations.NotNull;
-
/** The service that defines the watch face. */
public class WatchFaceService extends ListenableWatchFaceService {
- @NotNull
+ @NonNull
@Override
protected ListenableFuture<WatchFace> createWatchFaceFuture(
- @NotNull SurfaceHolder surfaceHolder,
- @NotNull WatchState watchState,
+ @NonNull SurfaceHolder surfaceHolder,
+ @NonNull WatchState watchState,
@NonNull ComplicationSlotsManager complicationSlotsManager,
@NonNull CurrentUserStyleRepository currentUserStyleRepository) {
Renderer renderer =
diff --git a/wear/watchface/watchface-style/old-api-test-stub/lint-baseline.xml b/wear/watchface/watchface-style/old-api-test-stub/lint-baseline.xml
new file mode 100644
index 0000000..a6236f9
--- /dev/null
+++ b/wear/watchface/watchface-style/old-api-test-stub/lint-baseline.xml
@@ -0,0 +1,13 @@
+<?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">
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IStyleEchoService {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/androidx/wear/watchface/style/test/IStyleEchoService.aidl"/>
+ </issue>
+
+</issues>
diff --git a/wear/watchface/watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceRenderer.java b/wear/watchface/watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceRenderer.java
index c56ae533..0579c17 100644
--- a/wear/watchface/watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceRenderer.java
+++ b/wear/watchface/watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceRenderer.java
@@ -29,8 +29,6 @@
import androidx.wear.watchface.WatchState;
import androidx.wear.watchface.style.CurrentUserStyleRepository;
-import org.jetbrains.annotations.NotNull;
-
import java.time.ZonedDateTime;
import java.util.concurrent.TimeUnit;
@@ -49,9 +47,9 @@
private final char[] mTimeText = new char[5];
public WatchFaceRenderer(
- @NotNull SurfaceHolder surfaceHolder,
- @NotNull CurrentUserStyleRepository currentUserStyleRepository,
- @NotNull WatchState watchState) {
+ @NonNull SurfaceHolder surfaceHolder,
+ @NonNull CurrentUserStyleRepository currentUserStyleRepository,
+ @NonNull WatchState watchState) {
super(
surfaceHolder,
currentUserStyleRepository,
@@ -66,7 +64,7 @@
@Override
public void render(
- @NotNull Canvas canvas, @NotNull Rect rect, @NotNull ZonedDateTime zonedDateTime) {
+ @NonNull Canvas canvas, @NonNull Rect rect, @NonNull ZonedDateTime zonedDateTime) {
mPaint.setColor(Color.BLACK);
canvas.drawRect(rect, mPaint);
mPaint.setColor(Color.WHITE);
diff --git a/wear/watchface/watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceService.java b/wear/watchface/watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceService.java
index 27905a9..41c1cef 100644
--- a/wear/watchface/watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceService.java
+++ b/wear/watchface/watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceService.java
@@ -30,16 +30,14 @@
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import org.jetbrains.annotations.NotNull;
-
/** The service that defines the watch face. */
public class WatchFaceService extends ListenableWatchFaceService {
- @NotNull
+ @NonNull
@Override
protected ListenableFuture<WatchFace> createWatchFaceFuture(
- @NotNull SurfaceHolder surfaceHolder,
- @NotNull WatchState watchState,
+ @NonNull SurfaceHolder surfaceHolder,
+ @NonNull WatchState watchState,
@NonNull ComplicationSlotsManager complicationSlotsManager,
@NonNull CurrentUserStyleRepository currentUserStyleRepository) {
Renderer renderer =
diff --git a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt
index 14fc4dd..ddfed4c 100644
--- a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt
+++ b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt
@@ -19,6 +19,7 @@
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.animation.TimeInterpolator
+import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
@@ -137,6 +138,8 @@
ComplicationType.SMALL_IMAGE
),
DefaultComplicationDataSourcePolicy(
+ ComponentName(COMPLICATION_PACKAGE, "$COMPLICATION_CLASS_PREFIX\$Steps"),
+ ComplicationType.RANGED_VALUE,
SystemDataSources.DATA_SOURCE_WATCH_BATTERY,
ComplicationType.SHORT_TEXT
),
@@ -165,6 +168,8 @@
ComplicationType.SMALL_IMAGE
),
DefaultComplicationDataSourcePolicy(
+ ComponentName(COMPLICATION_PACKAGE, "$COMPLICATION_CLASS_PREFIX\$HeartRate"),
+ ComplicationType.RANGED_VALUE,
SystemDataSources.DATA_SOURCE_DATE,
ComplicationType.SHORT_TEXT
),
@@ -198,6 +203,8 @@
canvasComplicationFactory,
upperAndLowerComplicationTypes,
DefaultComplicationDataSourcePolicy(
+ ComponentName(COMPLICATION_PACKAGE, "$COMPLICATION_CLASS_PREFIX\$Calories"),
+ ComplicationType.RANGED_VALUE,
SystemDataSources.DATA_SOURCE_WORLD_CLOCK,
ComplicationType.LONG_TEXT
),
@@ -229,6 +236,8 @@
canvasComplicationFactory,
upperAndLowerComplicationTypes,
DefaultComplicationDataSourcePolicy(
+ ComponentName(COMPLICATION_PACKAGE, "$COMPLICATION_CLASS_PREFIX\$Distance"),
+ ComplicationType.RANGED_VALUE,
SystemDataSources.DATA_SOURCE_NEXT_EVENT,
ComplicationType.LONG_TEXT
),
@@ -1105,6 +1114,11 @@
// Render at approximately 60fps in interactive mode.
private const val INTERACTIVE_UPDATE_RATE_MS = 16L
+ private const val COMPLICATION_PACKAGE =
+ "androidx.wear.watchface.complications.datasource.samples"
+ private const val COMPLICATION_CLASS_PREFIX =
+ "$COMPLICATION_PACKAGE.dynamic.HealthDataSourceServices"
+
// Constants for the size of complication.
private val CIRCLE_COMPLICATION_DIAMETER_FRACTION = Vec2f(0.252f, 0.252f)
private val ROUND_RECT_COMPLICATION_SIZE_FRACTION = Vec2f(0.645f, 0.168f)
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/BroadcastsReceiver.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/BroadcastsReceiver.kt
index a7130b9..9df1d3b 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/BroadcastsReceiver.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/BroadcastsReceiver.kt
@@ -123,7 +123,10 @@
addAction(WatchFaceImpl.MOCK_TIME_INTENT)
addAction(ACTION_AMBIENT_STARTED)
addAction(ACTION_AMBIENT_STOPPED)
- }
+ },
+ // Listen to broadcasts from the system or the app itself,
+ // so it does not have to be exported
+ Context.RECEIVER_NOT_EXPORTED
)
}
diff --git a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
index bba42d55..d4bbb81 100644
--- a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
+++ b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
@@ -47,6 +47,7 @@
import android.support.wearable.watchface.accessibility.ContentDescriptionLabel
import android.view.Choreographer
import android.view.Surface
+import android.view.SurfaceControl
import android.view.SurfaceHolder
import android.view.WindowInsets
import android.view.accessibility.AccessibilityManager
@@ -98,6 +99,7 @@
import androidx.wear.watchface.style.data.UserStyleWireFormat
import com.google.common.truth.Truth.assertThat
import java.io.StringWriter
+import java.lang.reflect.Field
import java.nio.ByteBuffer
import java.time.Instant
import java.time.ZoneId
@@ -750,6 +752,18 @@
}
if (this::engineWrapper.isInitialized && !engineWrapper.destroyed) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ /*
+ (TODO: b/264994539) - Explicitly releasing the mSurfaceControl field,
+ accessed via reflection. Remove when a proper fix is found
+ */
+ val mSurfaceControlObject: Field = WatchFaceService.EngineWrapper::class
+ .java.superclass // android.service.wallpaper.WallpaperService$Engine
+ .getDeclaredField("mSurfaceControl")
+ mSurfaceControlObject.isAccessible = true
+ (mSurfaceControlObject.get(engineWrapper) as SurfaceControl).release()
+ }
+
engineWrapper.onDestroy()
}
diff --git a/wear/wear-samples-ambient/build.gradle b/wear/wear-samples-ambient/build.gradle
index b73c613..29d1b8f 100644
--- a/wear/wear-samples-ambient/build.gradle
+++ b/wear/wear-samples-ambient/build.gradle
@@ -31,6 +31,7 @@
androidx {
name = "Android Wear Ambient Sample"
type = LibraryType.SAMPLES
+ mavenVersion = LibraryVersions.WEAR
inceptionYear = "2021"
description = "Contains the sample code for the ambient APIs defined in the androidx.wear:wear library"
}
diff --git a/wear/wear/api/1.3.0-beta01.txt b/wear/wear/api/1.3.0-beta01.txt
new file mode 100644
index 0000000..40f7aad
--- /dev/null
+++ b/wear/wear/api/1.3.0-beta01.txt
@@ -0,0 +1,492 @@
+// Signature format: 4.0
+package androidx.wear.activity {
+
+ public class ConfirmationActivity extends android.app.Activity {
+ ctor public ConfirmationActivity();
+ method protected void onAnimationFinished();
+ method public void onCreate(android.os.Bundle!);
+ field public static final String EXTRA_ANIMATION_DURATION_MILLIS = "androidx.wear.activity.extra.ANIMATION_DURATION_MILLIS";
+ field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
+ field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
+ field public static final int FAILURE_ANIMATION = 3; // 0x3
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 1; // 0x1
+ }
+
+}
+
+package androidx.wear.ambient {
+
+ public interface AmbientLifecycleObserver extends androidx.lifecycle.DefaultLifecycleObserver {
+ method public boolean isAmbient();
+ property public abstract boolean isAmbient;
+ }
+
+ public static final class AmbientLifecycleObserver.AmbientDetails {
+ ctor public AmbientLifecycleObserver.AmbientDetails(boolean burnInProtectionRequired, boolean deviceHasLowBitAmbient);
+ method public boolean getBurnInProtectionRequired();
+ method public boolean getDeviceHasLowBitAmbient();
+ property public final boolean burnInProtectionRequired;
+ property public final boolean deviceHasLowBitAmbient;
+ }
+
+ public static interface AmbientLifecycleObserver.AmbientLifecycleCallback {
+ method public default void onEnterAmbient(androidx.wear.ambient.AmbientLifecycleObserver.AmbientDetails ambientDetails);
+ method public default void onExitAmbient();
+ method public default void onUpdateAmbient();
+ }
+
+ public final class AmbientLifecycleObserverKt {
+ method public static androidx.wear.ambient.AmbientLifecycleObserver AmbientLifecycleObserver(android.app.Activity activity, androidx.wear.ambient.AmbientLifecycleObserver.AmbientLifecycleCallback callbacks);
+ method public static androidx.wear.ambient.AmbientLifecycleObserver AmbientLifecycleObserver(android.app.Activity activity, java.util.concurrent.Executor callbackExecutor, androidx.wear.ambient.AmbientLifecycleObserver.AmbientLifecycleCallback callbacks);
+ }
+
+ @Deprecated public final class AmbientMode extends android.app.Fragment {
+ ctor @Deprecated public AmbientMode();
+ method @Deprecated public static <T extends android.app.Activity> androidx.wear.ambient.AmbientMode.AmbientController! attachAmbientSupport(T!);
+ method @Deprecated public void dump(String!, java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+ method @Deprecated @CallSuper public void onAttach(android.content.Context!);
+ method @Deprecated @CallSuper public void onCreate(android.os.Bundle!);
+ method @Deprecated @CallSuper public void onDestroy();
+ method @Deprecated @CallSuper public void onDetach();
+ method @Deprecated @CallSuper public void onPause();
+ method @Deprecated @CallSuper public void onResume();
+ method @Deprecated @CallSuper public void onStop();
+ field @Deprecated public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field @Deprecated public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field @Deprecated public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ @Deprecated public abstract static class AmbientMode.AmbientCallback {
+ ctor @Deprecated public AmbientMode.AmbientCallback();
+ method @Deprecated public void onAmbientOffloadInvalidated();
+ method @Deprecated public void onEnterAmbient(android.os.Bundle!);
+ method @Deprecated public void onExitAmbient();
+ method @Deprecated public void onUpdateAmbient();
+ }
+
+ @Deprecated public static interface AmbientMode.AmbientCallbackProvider {
+ method @Deprecated public androidx.wear.ambient.AmbientMode.AmbientCallback! getAmbientCallback();
+ }
+
+ @Deprecated public final class AmbientMode.AmbientController {
+ method @Deprecated public boolean isAmbient();
+ method @Deprecated public void setAmbientOffloadEnabled(boolean);
+ }
+
+ @Deprecated public final class AmbientModeSupport extends androidx.fragment.app.Fragment {
+ ctor @Deprecated public AmbientModeSupport();
+ method @Deprecated public static <T extends androidx.fragment.app.FragmentActivity> androidx.wear.ambient.AmbientModeSupport.AmbientController! attach(T!);
+ field @Deprecated public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field @Deprecated public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field @Deprecated public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ @Deprecated public abstract static class AmbientModeSupport.AmbientCallback {
+ ctor @Deprecated public AmbientModeSupport.AmbientCallback();
+ method @Deprecated public void onAmbientOffloadInvalidated();
+ method @Deprecated public void onEnterAmbient(android.os.Bundle!);
+ method @Deprecated public void onExitAmbient();
+ method @Deprecated public void onUpdateAmbient();
+ }
+
+ @Deprecated public static interface AmbientModeSupport.AmbientCallbackProvider {
+ method @Deprecated public androidx.wear.ambient.AmbientModeSupport.AmbientCallback! getAmbientCallback();
+ }
+
+ @Deprecated public final class AmbientModeSupport.AmbientController {
+ method @Deprecated public boolean isAmbient();
+ method @Deprecated public void setAmbientOffloadEnabled(boolean);
+ method @Deprecated public void setAutoResumeEnabled(boolean);
+ }
+
+}
+
+package androidx.wear.provider {
+
+ public class WearableCalendarContract {
+ method public static void addCalendarAuthorityUri(android.content.UriMatcher, String, int);
+ method public static void addCalendarDataAuthority(android.content.IntentFilter, String?);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Attendees {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Instances {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Reminders {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+}
+
+package androidx.wear.utils {
+
+ public class MetadataConstants {
+ method public static int getPreviewDrawableResourceId(android.content.Context!, boolean);
+ method public static boolean isNotificationBridgingEnabled(android.content.Context!);
+ method public static boolean isStandalone(android.content.Context!);
+ field public static final String NOTIFICATION_BRIDGE_MODE_BRIDGING = "BRIDGING";
+ field public static final String NOTIFICATION_BRIDGE_MODE_METADATA_NAME = "com.google.android.wearable.notificationBridgeMode";
+ field public static final String NOTIFICATION_BRIDGE_MODE_NO_BRIDGING = "NO_BRIDGING";
+ field public static final String STANDALONE_METADATA_NAME = "com.google.android.wearable.standalone";
+ field public static final String WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME = "com.google.android.wearable.watchface.preview_circular";
+ field public static final String WATCH_FACE_PREVIEW_METADATA_NAME = "com.google.android.wearable.watchface.preview";
+ }
+
+ public final class WearTypeHelper {
+ method public static boolean isChinaBuild(android.content.Context);
+ }
+
+}
+
+package androidx.wear.widget {
+
+ @UiThread public class ArcLayout extends android.view.ViewGroup {
+ ctor public ArcLayout(android.content.Context);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method public int getAnchorType();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxAngleDegrees();
+ method public boolean isClockwise();
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(int);
+ method public void setClockwise(boolean);
+ method public void setMaxAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ field public static final int ANCHOR_CENTER = 1; // 0x1
+ field public static final int ANCHOR_END = 2; // 0x2
+ field public static final int ANCHOR_START = 0; // 0x0
+ }
+
+ public static class ArcLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public ArcLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public ArcLayout.LayoutParams(int, int);
+ method public int getVerticalAlignment();
+ method public float getWeight();
+ method public boolean isRotated();
+ method public void setRotated(boolean);
+ method public void setVerticalAlignment(int);
+ method public void setWeight(float);
+ field public static final int VERTICAL_ALIGN_CENTER = 1; // 0x1
+ field public static final int VERTICAL_ALIGN_INNER = 2; // 0x2
+ field public static final int VERTICAL_ALIGN_OUTER = 0; // 0x0
+ }
+
+ public static interface ArcLayout.Widget {
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method @Px public int getThickness();
+ method public boolean isPointInsideClickArea(float, float);
+ method public default void setSweepAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ }
+
+ @UiThread public class BoxInsetLayout extends android.view.ViewGroup {
+ ctor public BoxInsetLayout(android.content.Context);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?, @StyleRes int);
+ method public androidx.wear.widget.BoxInsetLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+ }
+
+ public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+ ctor public BoxInsetLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(androidx.wear.widget.BoxInsetLayout.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int, int);
+ field public static final int BOX_ALL = 15; // 0xf
+ field public static final int BOX_BOTTOM = 8; // 0x8
+ field public static final int BOX_LEFT = 1; // 0x1
+ field public static final int BOX_NONE = 0; // 0x0
+ field public static final int BOX_RIGHT = 4; // 0x4
+ field public static final int BOX_TOP = 2; // 0x2
+ field public int boxedEdges;
+ }
+
+ public class CircularProgressLayout extends android.widget.FrameLayout {
+ ctor public CircularProgressLayout(android.content.Context!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method @ColorInt public int getBackgroundColor();
+ method public int[]! getColorSchemeColors();
+ method public androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener? getOnTimerFinishedListener();
+ method public androidx.swiperefreshlayout.widget.CircularProgressDrawable getProgressDrawable();
+ method public float getStartingRotation();
+ method public float getStrokeWidth();
+ method public long getTotalTime();
+ method public boolean isIndeterminate();
+ method public boolean isTimerRunning();
+ method public void setColorSchemeColors(int...);
+ method public void setIndeterminate(boolean);
+ method public void setOnTimerFinishedListener(androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener?);
+ method public void setStartingRotation(float);
+ method public void setStrokeWidth(float);
+ method public void setTotalTime(long);
+ method public void startTimer();
+ method public void stopTimer();
+ }
+
+ public static interface CircularProgressLayout.OnTimerFinishedListener {
+ method public void onTimerFinished(androidx.wear.widget.CircularProgressLayout!);
+ }
+
+ public class ConfirmationOverlay {
+ ctor public ConfirmationOverlay();
+ method public androidx.wear.widget.ConfirmationOverlay setDuration(int);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setFinishedAnimationListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method public androidx.wear.widget.ConfirmationOverlay setMessage(CharSequence);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setMessage(String);
+ method public androidx.wear.widget.ConfirmationOverlay setOnAnimationFinishedListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method public androidx.wear.widget.ConfirmationOverlay setType(@androidx.wear.widget.ConfirmationOverlay.OverlayType int);
+ method @MainThread public void showAbove(android.view.View);
+ method @MainThread public void showOn(android.app.Activity);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final int FAILURE_ANIMATION = 1; // 0x1
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 0; // 0x0
+ }
+
+ public static interface ConfirmationOverlay.OnAnimationFinishedListener {
+ method public void onAnimationFinished();
+ }
+
+ @IntDef({androidx.wear.widget.ConfirmationOverlay.SUCCESS_ANIMATION, androidx.wear.widget.ConfirmationOverlay.FAILURE_ANIMATION, androidx.wear.widget.ConfirmationOverlay.OPEN_ON_PHONE_ANIMATION}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ConfirmationOverlay.OverlayType {
+ }
+
+ public class CurvedTextView extends android.view.View implements androidx.wear.widget.ArcLayout.Widget {
+ ctor public CurvedTextView(android.content.Context);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int, int);
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method public int getAnchorType();
+ method public android.text.TextUtils.TruncateAt? getEllipsize();
+ method public String? getFontFeatureSettings();
+ method public String? getFontVariationSettings();
+ method public float getLetterSpacing();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMinSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method public String? getText();
+ method @ColorInt public int getTextColor();
+ method public float getTextSize();
+ method @Px public int getThickness();
+ method public android.graphics.Typeface? getTypeface();
+ method public boolean isClockwise();
+ method public boolean isPointInsideClickArea(float, float);
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(int);
+ method public void setClockwise(boolean);
+ method public void setEllipsize(android.text.TextUtils.TruncateAt?);
+ method public void setFontFeatureSettings(String?);
+ method public void setFontVariationSettings(String?);
+ method public void setLetterSpacing(float);
+ method public void setSweepRangeDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float, @FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setText(String?);
+ method public void setTextColor(@ColorInt int);
+ method public void setTextSize(float);
+ method public void setTypeface(android.graphics.Typeface?);
+ method public void setTypeface(android.graphics.Typeface?, int);
+ }
+
+ public class CurvingLayoutCallback extends androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback {
+ ctor public CurvingLayoutCallback(android.content.Context!);
+ method public void adjustAnchorOffsetXY(android.view.View!, float[]!);
+ method public void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ @UiThread public class DismissibleFrameLayout extends android.widget.FrameLayout {
+ ctor public DismissibleFrameLayout(android.content.Context);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method public boolean isDismissableByBackButton();
+ method public boolean isDismissableBySwipe();
+ method protected void performDismissCanceledCallbacks();
+ method protected void performDismissFinishedCallbacks();
+ method protected void performDismissStartedCallbacks();
+ method @UiThread public final void registerCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ method public final void setBackButtonDismissible(boolean);
+ method public final void setSwipeDismissible(boolean);
+ method @UiThread public final void unregisterCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ }
+
+ @UiThread public abstract static class DismissibleFrameLayout.Callback {
+ ctor public DismissibleFrameLayout.Callback();
+ method public void onDismissCanceled(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissFinished(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissStarted(androidx.wear.widget.DismissibleFrameLayout);
+ }
+
+ public class RoundedDrawable extends android.graphics.drawable.Drawable {
+ ctor public RoundedDrawable();
+ method public void draw(android.graphics.Canvas);
+ method @ColorInt public int getBackgroundColor();
+ method public android.graphics.drawable.Drawable? getDrawable();
+ method public int getOpacity();
+ method public int getRadius();
+ method public boolean isClipEnabled();
+ method public void setAlpha(int);
+ method public void setBackgroundColor(@ColorInt int);
+ method public void setClipEnabled(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter?);
+ method public void setDrawable(android.graphics.drawable.Drawable?);
+ method public void setRadius(int);
+ }
+
+ @UiThread public class SwipeDismissFrameLayout extends androidx.wear.widget.DismissibleFrameLayout {
+ ctor public SwipeDismissFrameLayout(android.content.Context!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public float getDismissMinDragWidthRatio();
+ method public boolean isSwipeable();
+ method public void removeCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public void setDismissMinDragWidthRatio(float);
+ method public void setSwipeable(boolean);
+ field public static final float DEFAULT_DISMISS_DRAG_WIDTH_RATIO = 0.33f;
+ }
+
+ @UiThread public abstract static class SwipeDismissFrameLayout.Callback {
+ ctor public SwipeDismissFrameLayout.Callback();
+ method public void onDismissed(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeCanceled(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeStarted(androidx.wear.widget.SwipeDismissFrameLayout!);
+ }
+
+ public class WearableLinearLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
+ ctor public WearableLinearLayoutManager(android.content.Context!);
+ ctor public WearableLinearLayoutManager(android.content.Context!, androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback!);
+ method public androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback? getLayoutCallback();
+ method public void setLayoutCallback(androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback?);
+ }
+
+ public abstract static class WearableLinearLayoutManager.LayoutCallback {
+ ctor public WearableLinearLayoutManager.LayoutCallback();
+ method public abstract void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ public class WearableRecyclerView extends androidx.recyclerview.widget.RecyclerView {
+ ctor public WearableRecyclerView(android.content.Context!);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int, int);
+ method public float getBezelFraction();
+ method public float getScrollDegreesPerScreen();
+ method public boolean isCircularScrollingGestureEnabled();
+ method public boolean isEdgeItemsCenteringEnabled();
+ method public void setBezelFraction(float);
+ method public void setCircularScrollingGestureEnabled(boolean);
+ method public void setEdgeItemsCenteringEnabled(boolean);
+ method public void setScrollDegreesPerScreen(float);
+ }
+
+}
+
+package androidx.wear.widget.drawer {
+
+ public class WearableActionDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableActionDrawerView(android.content.Context!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public android.view.Menu! getMenu();
+ method public void setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener!);
+ method public void setTitle(CharSequence?);
+ }
+
+ public class WearableDrawerController {
+ method public void closeDrawer();
+ method public void openDrawer();
+ method public void peekDrawer();
+ }
+
+ public class WearableDrawerLayout extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingParent android.view.View.OnLayoutChangeListener {
+ ctor public WearableDrawerLayout(android.content.Context!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void onFlingComplete(android.view.View!);
+ method public void onLayoutChange(android.view.View!, int, int, int, int, int, int, int, int);
+ method public void setDrawerStateCallback(androidx.wear.widget.drawer.WearableDrawerLayout.DrawerStateCallback!);
+ }
+
+ public static class WearableDrawerLayout.DrawerStateCallback {
+ ctor public WearableDrawerLayout.DrawerStateCallback();
+ method public void onDrawerClosed(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerOpened(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerStateChanged(androidx.wear.widget.drawer.WearableDrawerLayout!, int);
+ }
+
+ public class WearableDrawerView extends android.widget.FrameLayout {
+ ctor public WearableDrawerView(android.content.Context!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public androidx.wear.widget.drawer.WearableDrawerController! getController();
+ method public android.view.View? getDrawerContent();
+ method public int getDrawerState();
+ method public boolean isAutoPeekEnabled();
+ method public boolean isClosed();
+ method public boolean isLocked();
+ method public boolean isLockedWhenClosed();
+ method public boolean isOpenOnlyAtTopEnabled();
+ method public boolean isOpened();
+ method public boolean isPeekOnScrollDownEnabled();
+ method public boolean isPeeking();
+ method public void onDrawerClosed();
+ method public void onDrawerOpened();
+ method public void onDrawerStateChanged(int);
+ method public void onPeekContainerClicked(android.view.View!);
+ method public void setDrawerContent(android.view.View?);
+ method public void setIsAutoPeekEnabled(boolean);
+ method public void setIsLocked(boolean);
+ method public void setLockedWhenClosed(boolean);
+ method public void setOpenOnlyAtTopEnabled(boolean);
+ method public void setPeekContent(android.view.View!);
+ method public void setPeekOnScrollDownEnabled(boolean);
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public class WearableNavigationDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableNavigationDrawerView(android.content.Context!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public int getNavigationStyle();
+ method public void removeOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public void setAdapter(androidx.wear.widget.drawer.WearableNavigationDrawerView.WearableNavigationDrawerAdapter!);
+ method public void setCurrentItem(int, boolean);
+ field public static final int MULTI_PAGE = 1; // 0x1
+ field public static final int SINGLE_PAGE = 0; // 0x0
+ }
+
+ public static interface WearableNavigationDrawerView.OnItemSelectedListener {
+ method public void onItemSelected(int);
+ }
+
+ public abstract static class WearableNavigationDrawerView.WearableNavigationDrawerAdapter {
+ ctor public WearableNavigationDrawerView.WearableNavigationDrawerAdapter();
+ method public abstract int getCount();
+ method public abstract android.graphics.drawable.Drawable! getItemDrawable(int);
+ method public abstract CharSequence! getItemText(int);
+ method public void notifyDataSetChanged();
+ }
+
+}
+
diff --git a/wear/wear/api/res-1.3.0-beta01.txt b/wear/wear/api/res-1.3.0-beta01.txt
new file mode 100644
index 0000000..44b0b55
--- /dev/null
+++ b/wear/wear/api/res-1.3.0-beta01.txt
@@ -0,0 +1 @@
+style Widget_Wear_RoundSwitch
diff --git a/wear/wear/api/restricted_1.3.0-beta01.txt b/wear/wear/api/restricted_1.3.0-beta01.txt
new file mode 100644
index 0000000..31c3f46
--- /dev/null
+++ b/wear/wear/api/restricted_1.3.0-beta01.txt
@@ -0,0 +1,499 @@
+// Signature format: 4.0
+package androidx.wear.activity {
+
+ public class ConfirmationActivity extends android.app.Activity {
+ ctor public ConfirmationActivity();
+ method protected void onAnimationFinished();
+ method public void onCreate(android.os.Bundle!);
+ field public static final String EXTRA_ANIMATION_DURATION_MILLIS = "androidx.wear.activity.extra.ANIMATION_DURATION_MILLIS";
+ field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
+ field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
+ field public static final int FAILURE_ANIMATION = 3; // 0x3
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 1; // 0x1
+ }
+
+}
+
+package androidx.wear.ambient {
+
+ public interface AmbientLifecycleObserver extends androidx.lifecycle.DefaultLifecycleObserver {
+ method public boolean isAmbient();
+ property public abstract boolean isAmbient;
+ }
+
+ public static final class AmbientLifecycleObserver.AmbientDetails {
+ ctor public AmbientLifecycleObserver.AmbientDetails(boolean burnInProtectionRequired, boolean deviceHasLowBitAmbient);
+ method public boolean getBurnInProtectionRequired();
+ method public boolean getDeviceHasLowBitAmbient();
+ property public final boolean burnInProtectionRequired;
+ property public final boolean deviceHasLowBitAmbient;
+ }
+
+ public static interface AmbientLifecycleObserver.AmbientLifecycleCallback {
+ method public default void onEnterAmbient(androidx.wear.ambient.AmbientLifecycleObserver.AmbientDetails ambientDetails);
+ method public default void onExitAmbient();
+ method public default void onUpdateAmbient();
+ }
+
+ public final class AmbientLifecycleObserverKt {
+ method public static androidx.wear.ambient.AmbientLifecycleObserver AmbientLifecycleObserver(android.app.Activity activity, androidx.wear.ambient.AmbientLifecycleObserver.AmbientLifecycleCallback callbacks);
+ method public static androidx.wear.ambient.AmbientLifecycleObserver AmbientLifecycleObserver(android.app.Activity activity, java.util.concurrent.Executor callbackExecutor, androidx.wear.ambient.AmbientLifecycleObserver.AmbientLifecycleCallback callbacks);
+ }
+
+ @Deprecated public final class AmbientMode extends android.app.Fragment {
+ ctor @Deprecated public AmbientMode();
+ method @Deprecated public static <T extends android.app.Activity> androidx.wear.ambient.AmbientMode.AmbientController! attachAmbientSupport(T!);
+ method @Deprecated public void dump(String!, java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+ method @Deprecated @CallSuper public void onAttach(android.content.Context!);
+ method @Deprecated @CallSuper public void onCreate(android.os.Bundle!);
+ method @Deprecated @CallSuper public void onDestroy();
+ method @Deprecated @CallSuper public void onDetach();
+ method @Deprecated @CallSuper public void onPause();
+ method @Deprecated @CallSuper public void onResume();
+ method @Deprecated @CallSuper public void onStop();
+ field @Deprecated public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field @Deprecated public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field @Deprecated public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ @Deprecated public abstract static class AmbientMode.AmbientCallback {
+ ctor @Deprecated public AmbientMode.AmbientCallback();
+ method @Deprecated public void onAmbientOffloadInvalidated();
+ method @Deprecated public void onEnterAmbient(android.os.Bundle!);
+ method @Deprecated public void onExitAmbient();
+ method @Deprecated public void onUpdateAmbient();
+ }
+
+ @Deprecated public static interface AmbientMode.AmbientCallbackProvider {
+ method @Deprecated public androidx.wear.ambient.AmbientMode.AmbientCallback! getAmbientCallback();
+ }
+
+ @Deprecated public final class AmbientMode.AmbientController {
+ method @Deprecated public boolean isAmbient();
+ method @Deprecated public void setAmbientOffloadEnabled(boolean);
+ }
+
+ @Deprecated public final class AmbientModeSupport extends androidx.fragment.app.Fragment {
+ ctor @Deprecated public AmbientModeSupport();
+ method @Deprecated public static <T extends androidx.fragment.app.FragmentActivity> androidx.wear.ambient.AmbientModeSupport.AmbientController! attach(T!);
+ field @Deprecated public static final String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+ field @Deprecated public static final String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+ field @Deprecated public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+ }
+
+ @Deprecated public abstract static class AmbientModeSupport.AmbientCallback {
+ ctor @Deprecated public AmbientModeSupport.AmbientCallback();
+ method @Deprecated public void onAmbientOffloadInvalidated();
+ method @Deprecated public void onEnterAmbient(android.os.Bundle!);
+ method @Deprecated public void onExitAmbient();
+ method @Deprecated public void onUpdateAmbient();
+ }
+
+ @Deprecated public static interface AmbientModeSupport.AmbientCallbackProvider {
+ method @Deprecated public androidx.wear.ambient.AmbientModeSupport.AmbientCallback! getAmbientCallback();
+ }
+
+ @Deprecated public final class AmbientModeSupport.AmbientController {
+ method @Deprecated public boolean isAmbient();
+ method @Deprecated public void setAmbientOffloadEnabled(boolean);
+ method @Deprecated public void setAutoResumeEnabled(boolean);
+ }
+
+}
+
+package androidx.wear.provider {
+
+ public class WearableCalendarContract {
+ method public static void addCalendarAuthorityUri(android.content.UriMatcher, String, int);
+ method public static void addCalendarDataAuthority(android.content.IntentFilter, String?);
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Attendees {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Instances {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ public static final class WearableCalendarContract.Reminders {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+}
+
+package androidx.wear.utils {
+
+ public class MetadataConstants {
+ method public static int getPreviewDrawableResourceId(android.content.Context!, boolean);
+ method public static boolean isNotificationBridgingEnabled(android.content.Context!);
+ method public static boolean isStandalone(android.content.Context!);
+ field public static final String NOTIFICATION_BRIDGE_MODE_BRIDGING = "BRIDGING";
+ field public static final String NOTIFICATION_BRIDGE_MODE_METADATA_NAME = "com.google.android.wearable.notificationBridgeMode";
+ field public static final String NOTIFICATION_BRIDGE_MODE_NO_BRIDGING = "NO_BRIDGING";
+ field public static final String STANDALONE_METADATA_NAME = "com.google.android.wearable.standalone";
+ field public static final String WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME = "com.google.android.wearable.watchface.preview_circular";
+ field public static final String WATCH_FACE_PREVIEW_METADATA_NAME = "com.google.android.wearable.watchface.preview";
+ }
+
+ public final class WearTypeHelper {
+ method public static boolean isChinaBuild(android.content.Context);
+ }
+
+}
+
+package androidx.wear.widget {
+
+ @UiThread public class ArcLayout extends android.view.ViewGroup {
+ ctor public ArcLayout(android.content.Context);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method @androidx.wear.widget.ArcLayout.AnchorType public int getAnchorType();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxAngleDegrees();
+ method public boolean isClockwise();
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(@androidx.wear.widget.ArcLayout.AnchorType int);
+ method public void setClockwise(boolean);
+ method public void setMaxAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ field public static final int ANCHOR_CENTER = 1; // 0x1
+ field public static final int ANCHOR_END = 2; // 0x2
+ field public static final int ANCHOR_START = 0; // 0x0
+ }
+
+ @IntDef({androidx.wear.widget.ArcLayout.ANCHOR_START, androidx.wear.widget.ArcLayout.ANCHOR_CENTER, androidx.wear.widget.ArcLayout.ANCHOR_END}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ArcLayout.AnchorType {
+ }
+
+ public static class ArcLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public ArcLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public ArcLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public ArcLayout.LayoutParams(int, int);
+ method @androidx.wear.widget.ArcLayout.LayoutParams.VerticalAlignment public int getVerticalAlignment();
+ method public float getWeight();
+ method public boolean isRotated();
+ method public void setRotated(boolean);
+ method public void setVerticalAlignment(@androidx.wear.widget.ArcLayout.LayoutParams.VerticalAlignment int);
+ method public void setWeight(float);
+ field public static final int VERTICAL_ALIGN_CENTER = 1; // 0x1
+ field public static final int VERTICAL_ALIGN_INNER = 2; // 0x2
+ field public static final int VERTICAL_ALIGN_OUTER = 0; // 0x0
+ }
+
+ @IntDef({androidx.wear.widget.ArcLayout.LayoutParams.VERTICAL_ALIGN_OUTER, androidx.wear.widget.ArcLayout.LayoutParams.VERTICAL_ALIGN_CENTER, androidx.wear.widget.ArcLayout.LayoutParams.VERTICAL_ALIGN_INNER}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ArcLayout.LayoutParams.VerticalAlignment {
+ }
+
+ public static interface ArcLayout.Widget {
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method @Px public int getThickness();
+ method public boolean isPointInsideClickArea(float, float);
+ method public default void setSweepAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ }
+
+ @UiThread public class BoxInsetLayout extends android.view.ViewGroup {
+ ctor public BoxInsetLayout(android.content.Context);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet?, @StyleRes int);
+ method public androidx.wear.widget.BoxInsetLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+ }
+
+ public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+ ctor public BoxInsetLayout.LayoutParams(android.content.Context, android.util.AttributeSet?);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(androidx.wear.widget.BoxInsetLayout.LayoutParams);
+ ctor public BoxInsetLayout.LayoutParams(int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int);
+ ctor public BoxInsetLayout.LayoutParams(int, int, int, int);
+ field public static final int BOX_ALL = 15; // 0xf
+ field public static final int BOX_BOTTOM = 8; // 0x8
+ field public static final int BOX_LEFT = 1; // 0x1
+ field public static final int BOX_NONE = 0; // 0x0
+ field public static final int BOX_RIGHT = 4; // 0x4
+ field public static final int BOX_TOP = 2; // 0x2
+ field public int boxedEdges;
+ }
+
+ public class CircularProgressLayout extends android.widget.FrameLayout {
+ ctor public CircularProgressLayout(android.content.Context!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public CircularProgressLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method @ColorInt public int getBackgroundColor();
+ method public int[]! getColorSchemeColors();
+ method public androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener? getOnTimerFinishedListener();
+ method public androidx.swiperefreshlayout.widget.CircularProgressDrawable getProgressDrawable();
+ method public float getStartingRotation();
+ method public float getStrokeWidth();
+ method public long getTotalTime();
+ method public boolean isIndeterminate();
+ method public boolean isTimerRunning();
+ method public void setColorSchemeColors(int...);
+ method public void setIndeterminate(boolean);
+ method public void setOnTimerFinishedListener(androidx.wear.widget.CircularProgressLayout.OnTimerFinishedListener?);
+ method public void setStartingRotation(float);
+ method public void setStrokeWidth(float);
+ method public void setTotalTime(long);
+ method public void startTimer();
+ method public void stopTimer();
+ }
+
+ public static interface CircularProgressLayout.OnTimerFinishedListener {
+ method public void onTimerFinished(androidx.wear.widget.CircularProgressLayout!);
+ }
+
+ public class ConfirmationOverlay {
+ ctor public ConfirmationOverlay();
+ method @MainThread @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @VisibleForTesting public void hide();
+ method public androidx.wear.widget.ConfirmationOverlay setDuration(int);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setFinishedAnimationListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method public androidx.wear.widget.ConfirmationOverlay setMessage(CharSequence);
+ method @Deprecated public androidx.wear.widget.ConfirmationOverlay setMessage(String);
+ method public androidx.wear.widget.ConfirmationOverlay setOnAnimationFinishedListener(androidx.wear.widget.ConfirmationOverlay.OnAnimationFinishedListener?);
+ method public androidx.wear.widget.ConfirmationOverlay setType(@androidx.wear.widget.ConfirmationOverlay.OverlayType int);
+ method @MainThread public void showAbove(android.view.View);
+ method @MainThread public void showOn(android.app.Activity);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final int FAILURE_ANIMATION = 1; // 0x1
+ field public static final int OPEN_ON_PHONE_ANIMATION = 2; // 0x2
+ field public static final int SUCCESS_ANIMATION = 0; // 0x0
+ }
+
+ public static interface ConfirmationOverlay.OnAnimationFinishedListener {
+ method public void onAnimationFinished();
+ }
+
+ @IntDef({androidx.wear.widget.ConfirmationOverlay.SUCCESS_ANIMATION, androidx.wear.widget.ConfirmationOverlay.FAILURE_ANIMATION, androidx.wear.widget.ConfirmationOverlay.OPEN_ON_PHONE_ANIMATION}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ConfirmationOverlay.OverlayType {
+ }
+
+ public class CurvedTextView extends android.view.View implements androidx.wear.widget.ArcLayout.Widget {
+ ctor public CurvedTextView(android.content.Context);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int);
+ ctor public CurvedTextView(android.content.Context, android.util.AttributeSet?, int, int);
+ method public void checkInvalidAttributeAsChild();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
+ method @androidx.wear.widget.ArcLayout.AnchorType public int getAnchorType();
+ method public android.text.TextUtils.TruncateAt? getEllipsize();
+ method public String? getFontFeatureSettings();
+ method public String? getFontVariationSettings();
+ method public float getLetterSpacing();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMinSweepDegrees();
+ method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
+ method public String? getText();
+ method @ColorInt public int getTextColor();
+ method public float getTextSize();
+ method @Px public int getThickness();
+ method public android.graphics.Typeface? getTypeface();
+ method public boolean isClockwise();
+ method public boolean isPointInsideClickArea(float, float);
+ method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setAnchorType(@androidx.wear.widget.ArcLayout.AnchorType int);
+ method public void setClockwise(boolean);
+ method public void setEllipsize(android.text.TextUtils.TruncateAt?);
+ method public void setFontFeatureSettings(String?);
+ method public void setFontVariationSettings(String?);
+ method public void setLetterSpacing(float);
+ method public void setSweepRangeDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float, @FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
+ method public void setText(String?);
+ method public void setTextColor(@ColorInt int);
+ method public void setTextSize(float);
+ method public void setTypeface(android.graphics.Typeface?);
+ method public void setTypeface(android.graphics.Typeface?, int);
+ }
+
+ public class CurvingLayoutCallback extends androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback {
+ ctor public CurvingLayoutCallback(android.content.Context!);
+ method public void adjustAnchorOffsetXY(android.view.View!, float[]!);
+ method public void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ @UiThread public class DismissibleFrameLayout extends android.widget.FrameLayout {
+ ctor public DismissibleFrameLayout(android.content.Context);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int);
+ ctor public DismissibleFrameLayout(android.content.Context, android.util.AttributeSet?, int, int);
+ method public boolean isDismissableByBackButton();
+ method public boolean isDismissableBySwipe();
+ method protected void performDismissCanceledCallbacks();
+ method protected void performDismissFinishedCallbacks();
+ method protected void performDismissStartedCallbacks();
+ method @UiThread public final void registerCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ method public final void setBackButtonDismissible(boolean);
+ method public final void setSwipeDismissible(boolean);
+ method @UiThread public final void unregisterCallback(androidx.wear.widget.DismissibleFrameLayout.Callback);
+ }
+
+ @UiThread public abstract static class DismissibleFrameLayout.Callback {
+ ctor public DismissibleFrameLayout.Callback();
+ method public void onDismissCanceled(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissFinished(androidx.wear.widget.DismissibleFrameLayout);
+ method public void onDismissStarted(androidx.wear.widget.DismissibleFrameLayout);
+ }
+
+ public class RoundedDrawable extends android.graphics.drawable.Drawable {
+ ctor public RoundedDrawable();
+ method public void draw(android.graphics.Canvas);
+ method @ColorInt public int getBackgroundColor();
+ method public android.graphics.drawable.Drawable? getDrawable();
+ method public int getOpacity();
+ method public int getRadius();
+ method public boolean isClipEnabled();
+ method public void setAlpha(int);
+ method public void setBackgroundColor(@ColorInt int);
+ method public void setClipEnabled(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter?);
+ method public void setDrawable(android.graphics.drawable.Drawable?);
+ method public void setRadius(int);
+ }
+
+ @UiThread public class SwipeDismissFrameLayout extends androidx.wear.widget.DismissibleFrameLayout {
+ ctor public SwipeDismissFrameLayout(android.content.Context!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public SwipeDismissFrameLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public float getDismissMinDragWidthRatio();
+ method public boolean isSwipeable();
+ method public void removeCallback(androidx.wear.widget.SwipeDismissFrameLayout.Callback!);
+ method public void setDismissMinDragWidthRatio(float);
+ method public void setSwipeable(boolean);
+ field public static final float DEFAULT_DISMISS_DRAG_WIDTH_RATIO = 0.33f;
+ }
+
+ @UiThread public abstract static class SwipeDismissFrameLayout.Callback {
+ ctor public SwipeDismissFrameLayout.Callback();
+ method public void onDismissed(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeCanceled(androidx.wear.widget.SwipeDismissFrameLayout!);
+ method public void onSwipeStarted(androidx.wear.widget.SwipeDismissFrameLayout!);
+ }
+
+ public class WearableLinearLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
+ ctor public WearableLinearLayoutManager(android.content.Context!);
+ ctor public WearableLinearLayoutManager(android.content.Context!, androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback!);
+ method public androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback? getLayoutCallback();
+ method public void setLayoutCallback(androidx.wear.widget.WearableLinearLayoutManager.LayoutCallback?);
+ }
+
+ public abstract static class WearableLinearLayoutManager.LayoutCallback {
+ ctor public WearableLinearLayoutManager.LayoutCallback();
+ method public abstract void onLayoutFinished(android.view.View!, androidx.recyclerview.widget.RecyclerView!);
+ }
+
+ public class WearableRecyclerView extends androidx.recyclerview.widget.RecyclerView {
+ ctor public WearableRecyclerView(android.content.Context!);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int);
+ ctor public WearableRecyclerView(android.content.Context!, android.util.AttributeSet?, int, int);
+ method public float getBezelFraction();
+ method public float getScrollDegreesPerScreen();
+ method public boolean isCircularScrollingGestureEnabled();
+ method public boolean isEdgeItemsCenteringEnabled();
+ method public void setBezelFraction(float);
+ method public void setCircularScrollingGestureEnabled(boolean);
+ method public void setEdgeItemsCenteringEnabled(boolean);
+ method public void setScrollDegreesPerScreen(float);
+ }
+
+}
+
+package androidx.wear.widget.drawer {
+
+ public class WearableActionDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableActionDrawerView(android.content.Context!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableActionDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public android.view.Menu! getMenu();
+ method public void setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener!);
+ method public void setTitle(CharSequence?);
+ }
+
+ public class WearableDrawerController {
+ method public void closeDrawer();
+ method public void openDrawer();
+ method public void peekDrawer();
+ }
+
+ public class WearableDrawerLayout extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingParent android.view.View.OnLayoutChangeListener {
+ ctor public WearableDrawerLayout(android.content.Context!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerLayout(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void onFlingComplete(android.view.View!);
+ method public void onLayoutChange(android.view.View!, int, int, int, int, int, int, int, int);
+ method public void setDrawerStateCallback(androidx.wear.widget.drawer.WearableDrawerLayout.DrawerStateCallback!);
+ }
+
+ public static class WearableDrawerLayout.DrawerStateCallback {
+ ctor public WearableDrawerLayout.DrawerStateCallback();
+ method public void onDrawerClosed(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerOpened(androidx.wear.widget.drawer.WearableDrawerLayout!, androidx.wear.widget.drawer.WearableDrawerView!);
+ method public void onDrawerStateChanged(androidx.wear.widget.drawer.WearableDrawerLayout!, int);
+ }
+
+ public class WearableDrawerView extends android.widget.FrameLayout {
+ ctor public WearableDrawerView(android.content.Context!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public androidx.wear.widget.drawer.WearableDrawerController! getController();
+ method public android.view.View? getDrawerContent();
+ method public int getDrawerState();
+ method public boolean isAutoPeekEnabled();
+ method public boolean isClosed();
+ method public boolean isLocked();
+ method public boolean isLockedWhenClosed();
+ method public boolean isOpenOnlyAtTopEnabled();
+ method public boolean isOpened();
+ method public boolean isPeekOnScrollDownEnabled();
+ method public boolean isPeeking();
+ method public void onDrawerClosed();
+ method public void onDrawerOpened();
+ method public void onDrawerStateChanged(int);
+ method public void onPeekContainerClicked(android.view.View!);
+ method public void setDrawerContent(android.view.View?);
+ method public void setIsAutoPeekEnabled(boolean);
+ method public void setIsLocked(boolean);
+ method public void setLockedWhenClosed(boolean);
+ method public void setOpenOnlyAtTopEnabled(boolean);
+ method public void setPeekContent(android.view.View!);
+ method public void setPeekOnScrollDownEnabled(boolean);
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public class WearableNavigationDrawerView extends androidx.wear.widget.drawer.WearableDrawerView {
+ ctor public WearableNavigationDrawerView(android.content.Context!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int);
+ ctor public WearableNavigationDrawerView(android.content.Context!, android.util.AttributeSet!, int, int);
+ method public void addOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public int getNavigationStyle();
+ method public void removeOnItemSelectedListener(androidx.wear.widget.drawer.WearableNavigationDrawerView.OnItemSelectedListener!);
+ method public void setAdapter(androidx.wear.widget.drawer.WearableNavigationDrawerView.WearableNavigationDrawerAdapter!);
+ method public void setCurrentItem(int, boolean);
+ field public static final int MULTI_PAGE = 1; // 0x1
+ field public static final int SINGLE_PAGE = 0; // 0x0
+ }
+
+ public static interface WearableNavigationDrawerView.OnItemSelectedListener {
+ method public void onItemSelected(int);
+ }
+
+ public abstract static class WearableNavigationDrawerView.WearableNavigationDrawerAdapter {
+ ctor public WearableNavigationDrawerView.WearableNavigationDrawerAdapter();
+ method public abstract int getCount();
+ method public abstract android.graphics.drawable.Drawable! getItemDrawable(int);
+ method public abstract CharSequence! getItemText(int);
+ method public void notifyDataSetChanged();
+ }
+
+}
+
diff --git a/webkit/integration-tests/testapp/src/androidTest/java/com/example/androidx/webkit/AssetLoaderAjaxActivityTestAppTest.java b/webkit/integration-tests/testapp/src/androidTest/java/com/example/androidx/webkit/AssetLoaderAjaxActivityTestAppTest.java
index e472760..7325510 100644
--- a/webkit/integration-tests/testapp/src/androidTest/java/com/example/androidx/webkit/AssetLoaderAjaxActivityTestAppTest.java
+++ b/webkit/integration-tests/testapp/src/androidTest/java/com/example/androidx/webkit/AssetLoaderAjaxActivityTestAppTest.java
@@ -23,6 +23,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,6 +52,7 @@
activity.getUriIdlingResource()));
}
+ @Ignore("b/283485965")
@Test
public void testAssetLoaderAjaxActivity() {
mRule.getScenario().onActivity(activity -> activity.loadUrl());
diff --git a/webkit/webkit/api/api_lint.ignore b/webkit/webkit/api/api_lint.ignore
index a08e8bd..15a029d 100644
--- a/webkit/webkit/api/api_lint.ignore
+++ b/webkit/webkit/api/api_lint.ignore
@@ -1,6 +1,8 @@
// Baseline format: 1.0
ArrayReturn: androidx.webkit.WebMessageCompat#WebMessageCompat(String, androidx.webkit.WebMessagePortCompat[]) parameter #1:
Method parameter should be Collection<WebMessagePortCompat> (or subclass) instead of raw array; was `androidx.webkit.WebMessagePortCompat[]`
+ArrayReturn: androidx.webkit.WebMessageCompat#WebMessageCompat(byte[], androidx.webkit.WebMessagePortCompat[]) parameter #1:
+ Method parameter should be Collection<WebMessagePortCompat> (or subclass) instead of raw array; was `androidx.webkit.WebMessagePortCompat[]`
ArrayReturn: androidx.webkit.WebMessageCompat#getPorts():
Method should return Collection<WebMessagePortCompat> (or subclass) instead of raw array; was `androidx.webkit.WebMessagePortCompat[]`
ArrayReturn: androidx.webkit.WebViewCompat#createWebMessageChannel(android.webkit.WebView):
diff --git a/webkit/webkit/api/current.txt b/webkit/webkit/api/current.txt
index 30fe4d1..748c00e 100644
--- a/webkit/webkit/api/current.txt
+++ b/webkit/webkit/api/current.txt
@@ -16,6 +16,7 @@
}
public abstract class JavaScriptReplyProxy {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(byte[]);
method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
}
@@ -123,10 +124,16 @@
}
public class WebMessageCompat {
+ ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[]);
+ ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[], androidx.webkit.WebMessagePortCompat![]?);
ctor public WebMessageCompat(String?);
ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
+ method public byte[] getArrayBuffer();
method public String? getData();
method public androidx.webkit.WebMessagePortCompat![]? getPorts();
+ method public int getType();
+ field public static final int TYPE_ARRAY_BUFFER = 1; // 0x1
+ field public static final int TYPE_STRING = 0; // 0x0
}
public abstract class WebMessagePortCompat {
@@ -285,6 +292,7 @@
field public static final String START_SAFE_BROWSING = "START_SAFE_BROWSING";
field public static final String TRACING_CONTROLLER_BASIC_USAGE = "TRACING_CONTROLLER_BASIC_USAGE";
field public static final String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
+ field public static final String WEB_MESSAGE_ARRAY_BUFFER = "WEB_MESSAGE_ARRAY_BUFFER";
field public static final String WEB_MESSAGE_CALLBACK_ON_MESSAGE = "WEB_MESSAGE_CALLBACK_ON_MESSAGE";
field public static final String WEB_MESSAGE_LISTENER = "WEB_MESSAGE_LISTENER";
field public static final String WEB_MESSAGE_PORT_CLOSE = "WEB_MESSAGE_PORT_CLOSE";
diff --git a/webkit/webkit/api/restricted_current.txt b/webkit/webkit/api/restricted_current.txt
index 30fe4d1..748c00e 100644
--- a/webkit/webkit/api/restricted_current.txt
+++ b/webkit/webkit/api/restricted_current.txt
@@ -16,6 +16,7 @@
}
public abstract class JavaScriptReplyProxy {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(byte[]);
method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
}
@@ -123,10 +124,16 @@
}
public class WebMessageCompat {
+ ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[]);
+ ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[], androidx.webkit.WebMessagePortCompat![]?);
ctor public WebMessageCompat(String?);
ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
+ method public byte[] getArrayBuffer();
method public String? getData();
method public androidx.webkit.WebMessagePortCompat![]? getPorts();
+ method public int getType();
+ field public static final int TYPE_ARRAY_BUFFER = 1; // 0x1
+ field public static final int TYPE_STRING = 0; // 0x0
}
public abstract class WebMessagePortCompat {
@@ -285,6 +292,7 @@
field public static final String START_SAFE_BROWSING = "START_SAFE_BROWSING";
field public static final String TRACING_CONTROLLER_BASIC_USAGE = "TRACING_CONTROLLER_BASIC_USAGE";
field public static final String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
+ field public static final String WEB_MESSAGE_ARRAY_BUFFER = "WEB_MESSAGE_ARRAY_BUFFER";
field public static final String WEB_MESSAGE_CALLBACK_ON_MESSAGE = "WEB_MESSAGE_CALLBACK_ON_MESSAGE";
field public static final String WEB_MESSAGE_LISTENER = "WEB_MESSAGE_LISTENER";
field public static final String WEB_MESSAGE_PORT_CLOSE = "WEB_MESSAGE_PORT_CLOSE";
diff --git a/webkit/webkit/src/androidTest/java/androidx/webkit/WebMessageCompatUnitTest.java b/webkit/webkit/src/androidTest/java/androidx/webkit/WebMessageCompatUnitTest.java
new file mode 100644
index 0000000..fb4d328
--- /dev/null
+++ b/webkit/webkit/src/androidTest/java/androidx/webkit/WebMessageCompatUnitTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.webkit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.function.ThrowingRunnable;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link WebMessageCompat} basic usages.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WebMessageCompatUnitTest {
+
+ @Test
+ public void testArrayBufferUsage() {
+ final byte[] bytes = {1, 2, 3};
+ final WebMessageCompat message = new WebMessageCompat(bytes);
+ Assert.assertEquals(WebMessageCompat.TYPE_ARRAY_BUFFER, message.getType());
+ Assert.assertArrayEquals(bytes, message.getArrayBuffer());
+ Assert.assertThrows(IllegalStateException.class, new ThrowingRunnable() {
+ @Override
+ public void run() throws Throwable {
+ message.getData();
+ }
+ });
+ }
+
+ @Test
+ public void testStringUsage() {
+ final String string = "Hello";
+ final WebMessageCompat message = new WebMessageCompat(string);
+ Assert.assertEquals(WebMessageCompat.TYPE_STRING, message.getType());
+ Assert.assertEquals(string, message.getData());
+ Assert.assertThrows(IllegalStateException.class, new ThrowingRunnable() {
+ @Override
+ public void run() throws Throwable {
+ message.getArrayBuffer();
+ }
+ });
+ }
+}
diff --git a/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java b/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
index dcdf0c2..b283da8 100644
--- a/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
+++ b/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
@@ -121,6 +121,7 @@
* be reflected in that test as necessary. See http://go/modifying-webview-cts.
*/
@Test
+ @SuppressWarnings("deprecation")
public void testSuppressedErrorPage() throws Throwable {
WebkitUtils.checkFeature(WebViewFeature.SUPPRESS_ERROR_PAGE);
diff --git a/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewDocumentStartJavaScriptTest.java b/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewDocumentStartJavaScriptTest.java
index b8ae25db..0ed9655 100644
--- a/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewDocumentStartJavaScriptTest.java
+++ b/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewDocumentStartJavaScriptTest.java
@@ -106,6 +106,7 @@
}
@Test
+ @SuppressWarnings("deprecation") // To be removed in 1.9.0
public void testAddDocumentStartJavaScriptBasicUsage() throws Exception {
mWebViewOnUiThread.addWebMessageListener(JS_OBJECT_NAME, MATCH_EXAMPLE_COM, mListener);
mWebViewOnUiThread.addDocumentStartJavaScript(BASIC_SCRIPT, MATCH_EXAMPLE_COM);
@@ -118,6 +119,7 @@
}
@Test
+ @SuppressWarnings("deprecation") // To be removed in 1.9.0
public void testAddDocumentStartJavaScriptRemoveScript() throws Exception {
mWebViewOnUiThread.addWebMessageListener(JS_OBJECT_NAME, MATCH_EXAMPLE_COM, mListener);
ScriptHandler scriptHandler =
diff --git a/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java b/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
index f28c63c..69f6cd5 100644
--- a/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
+++ b/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
@@ -272,6 +272,8 @@
}
@NonNull
+ @Deprecated
+ @SuppressWarnings("deprecation") // To be removed in 1.9.0
public ScriptHandler addDocumentStartJavaScript(
@NonNull String script, @NonNull Set<String> allowedOriginRules) {
return WebkitUtils.onMainThreadSync(() -> WebViewCompat.addDocumentStartJavaScript(
diff --git a/webkit/webkit/src/main/java/androidx/webkit/JavaScriptReplyProxy.java b/webkit/webkit/src/main/java/androidx/webkit/JavaScriptReplyProxy.java
index 358b473..40fb9e3 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/JavaScriptReplyProxy.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/JavaScriptReplyProxy.java
@@ -48,14 +48,14 @@
/**
* Post a ArrayBuffer message to the injected JavaScript object which sent this
- * {@link JavaScriptReplyProxy}.
+ * {@link JavaScriptReplyProxy}. Be aware that large byte buffers can lead to out-of-memory
+ * crashes on low-end devices.
*
- * @param arrayBuffer The ArrayBuffer to send to the JavaScript context.
- * @hide
+ * @param arrayBuffer The ArrayBuffer to send to the JavaScript context. An empty ArrayBuffer
+ * is supported.
*/
@RequiresFeature(name = WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public abstract void postMessage(@NonNull byte[] arrayBuffer);
/**
diff --git a/webkit/webkit/src/main/java/androidx/webkit/WebMessageCompat.java b/webkit/webkit/src/main/java/androidx/webkit/WebMessageCompat.java
index 413f807..d382c22 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/WebMessageCompat.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/WebMessageCompat.java
@@ -36,12 +36,10 @@
/**
* Indicates the payload of WebMessageCompat is String.
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final int TYPE_STRING = 0;
/**
* Indicates the payload of WebMessageCompat is JavaScript ArrayBuffer.
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final int TYPE_ARRAY_BUFFER = 1;
private final @Nullable WebMessagePortCompat[] mPorts;
private final @Nullable String mString;
@@ -75,7 +73,6 @@
*
* @param arrayBuffer the array buffer data of the message.
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresFeature(name = WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public WebMessageCompat(@NonNull byte[] arrayBuffer) {
@@ -88,7 +85,6 @@
* @param arrayBuffer the array buffer data of the message.
* @param ports the ports that are sent with the message.
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresFeature(name = WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public WebMessageCompat(@NonNull byte[] arrayBuffer,
@@ -102,26 +98,49 @@
/**
* Returns the payload type of the message.
+ *
* @return the payload type of WebMessageCompat.
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public @Type int getType() {
return mType;
}
/**
* Returns the ArrayBuffer data of message. A ArrayBuffer or Transferable ArrayBuffer can be
- * received from JavaScript.
+ * received from JavaScript. This should only be called when {@link #getType()} returns
+ * {@link #TYPE_ARRAY_BUFFER}. Example:
+ * <pre class="prettyprint">
+ * WebMessageCompat message = ... // The WebMessageCompat received or prepared.
+ * if (message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) {
+ * byte[] arrayBuffer = message.getArrayBuffer();
+ * // Access arrayBuffer data here.
+ * }
+ * </pre>
+ *
+ * @return ArrayBuffer payload data.
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public @Nullable byte[] getArrayBuffer() {
+ public @NonNull byte[] getArrayBuffer() {
+ checkType(TYPE_ARRAY_BUFFER);
+ // Required for null check. ArrayBuffer is always non-null when mType == TYPE_ARRAY_BUFFER.
+ Objects.requireNonNull(mArrayBuffer);
return mArrayBuffer;
}
/**
- * Returns the String data of the message.
+ * Returns the String data of the message. This should only be called when {@link #getType()}
+ * returns {@link #TYPE_STRING}. Example:
+ * <pre class="prettyprint">
+ * WebMessageCompat message = ... // The WebMessageCompat received or prepared.
+ * if (message.getType() == WebMessageCompat.TYPE_STRING) {
+ * String string = message.getData();
+ * // Access string data here.
+ * }
+ * </pre>
+ *
+ * @return String payload data.
*/
public @Nullable String getData() {
+ checkType(TYPE_STRING);
return mString;
}
@@ -134,8 +153,27 @@
return mPorts;
}
+ private @NonNull String typeToString(@Type int type) {
+ switch (type) {
+ case TYPE_STRING:
+ return "String";
+ case TYPE_ARRAY_BUFFER:
+ return "ArrayBuffer";
+ default:
+ return "Unknown";
+ }
+ }
+
+ private void checkType(@Type int typeForGetter) {
+ if (typeForGetter != mType) {
+ throw new IllegalStateException("Wrong data accessor type detected. "
+ + typeToString(mType) + " expected, but got " + typeToString(typeForGetter));
+ }
+ }
+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@IntDef({TYPE_STRING, TYPE_ARRAY_BUFFER})
@Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
+ public @interface Type {
+ }
}
diff --git a/webkit/webkit/src/main/java/androidx/webkit/WebMessagePortCompat.java b/webkit/webkit/src/main/java/androidx/webkit/WebMessagePortCompat.java
index 5d113af..3518eb5 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/WebMessagePortCompat.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/WebMessagePortCompat.java
@@ -93,6 +93,19 @@
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#WEB_MESSAGE_PORT_POST_MESSAGE}.
*
+ * <p>
+ * When posting a {@link WebMessageCompat} with type {@link WebMessageCompat#TYPE_ARRAY_BUFFER},
+ * this method should check if {@link WebViewFeature#isFeatureSupported(String)} returns true
+ * for {@link WebViewFeature#WEB_MESSAGE_ARRAY_BUFFER}. Example:
+ * <pre class="prettyprint">
+ * if (message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) {
+ * if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER) {
+ * // ArrayBuffer message is supported, send message here.
+ * port.postMessage(message);
+ * }
+ * }
+ * </pre>
+ *
* @param message the message from Java to JS.
*
* @throws IllegalStateException If message port is already transferred or closed.
diff --git a/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java b/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
index 595d73c..5c25673f 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
@@ -231,9 +231,9 @@
* returns true for {@link WebViewFeature#SUPPRESS_ERROR_PAGE}.
*
* @param suppressed whether the WebView should suppress its internal error page
- *
- * TODO(cricke): unhide
+ * @deprecated unreleased API will be removed in 1.9.0
*/
+ @Deprecated
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresFeature(name = WebViewFeature.SUPPRESS_ERROR_PAGE,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
@@ -258,9 +258,9 @@
*
* @return true if the WebView will suppress its internal error page
* @see #setWillSuppressErrorPage
- *
- * TODO(cricke): unhide
+ * @deprecated unreleased API will be removed in 1.9.0
*/
+ @Deprecated
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresFeature(name = WebViewFeature.SUPPRESS_ERROR_PAGE,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
diff --git a/webkit/webkit/src/main/java/androidx/webkit/WebViewCompat.java b/webkit/webkit/src/main/java/androidx/webkit/WebViewCompat.java
index d110b42..a7c2377 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/WebViewCompat.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/WebViewCompat.java
@@ -484,6 +484,19 @@
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#POST_WEB_MESSAGE}.
*
+ * <p>
+ * When posting a {@link WebMessageCompat} with type {@link WebMessageCompat#TYPE_ARRAY_BUFFER},
+ * this method should check if {@link WebViewFeature#isFeatureSupported(String)} returns true
+ * for {@link WebViewFeature#WEB_MESSAGE_ARRAY_BUFFER}. Example:
+ * <pre class="prettyprint">
+ * if (message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) {
+ * if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER) {
+ * // ArrayBuffer message is supported, send message here.
+ * WebViewCompat.postWebMessage(webview, message, ...);
+ * }
+ * }
+ * </pre
+ *
* @param message the WebMessage
* @param targetOrigin the target origin.
*/
@@ -796,13 +809,13 @@
* @throws IllegalArgumentException If one of the {@code allowedOriginRules} is invalid.
* @see #addWebMessageListener(WebView, String, Set, WebMessageListener)
* @see ScriptHandler
- *
- * TODO(swestphal): unhide when ready.
+ * @deprecated unreleased API will be removed in 1.9.0
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresFeature(
name = WebViewFeature.DOCUMENT_START_SCRIPT,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
+ @Deprecated
public static @NonNull ScriptHandler addDocumentStartJavaScript(
@NonNull WebView webview,
@NonNull String script,
diff --git a/webkit/webkit/src/main/java/androidx/webkit/WebViewFeature.java b/webkit/webkit/src/main/java/androidx/webkit/WebViewFeature.java
index 28bc43f..df43989 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/WebViewFeature.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/WebViewFeature.java
@@ -350,10 +350,10 @@
/**
* Feature for {@link #isFeatureSupported(String)}.
* This feature covers
- * {@link WebMessagePortCompat#postMessage(WebMessageCompat)} with ArrayBuffer type, and
- * {@link WebViewCompat#postWebMessage(WebView, WebMessageCompat, Uri)} with ArrayBuffer type.
+ * {@link WebMessagePortCompat#postMessage(WebMessageCompat)} with ArrayBuffer type,
+ * {@link WebViewCompat#postWebMessage(WebView, WebMessageCompat, Uri)} with ArrayBuffer type,
+ * and {@link JavaScriptReplyProxy#postMessage(byte[])}.
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final String WEB_MESSAGE_ARRAY_BUFFER = "WEB_MESSAGE_ARRAY_BUFFER";
/**
diff --git a/window/extensions/extensions/api/current.txt b/window/extensions/extensions/api/current.txt
index 490edb0..20f4ee8 100644
--- a/window/extensions/extensions/api/current.txt
+++ b/window/extensions/extensions/api/current.txt
@@ -16,13 +16,31 @@
package androidx.window.extensions.area {
+ public interface ExtensionWindowAreaPresentation {
+ method public android.content.Context getPresentationContext();
+ method public void setPresentationView(android.view.View);
+ }
+
+ public interface ExtensionWindowAreaStatus {
+ method public android.util.DisplayMetrics getWindowAreaDisplayMetrics();
+ method public int getWindowAreaStatus();
+ }
+
public interface WindowAreaComponent {
+ method public default void addRearDisplayPresentationStatusListener(androidx.window.extensions.core.util.function.Consumer<androidx.window.extensions.area.ExtensionWindowAreaStatus!>);
method public void addRearDisplayStatusListener(androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public default void endRearDisplayPresentationSession();
method public void endRearDisplaySession();
+ method public default android.util.DisplayMetrics getRearDisplayMetrics();
+ method public default androidx.window.extensions.area.ExtensionWindowAreaPresentation? getRearDisplayPresentation();
+ method public default void removeRearDisplayPresentationStatusListener(androidx.window.extensions.core.util.function.Consumer<androidx.window.extensions.area.ExtensionWindowAreaStatus!>);
method public void removeRearDisplayStatusListener(androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public default void startRearDisplayPresentationSession(android.app.Activity, androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
method public void startRearDisplaySession(android.app.Activity, androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
field public static final int SESSION_STATE_ACTIVE = 1; // 0x1
+ field public static final int SESSION_STATE_CONTENT_VISIBLE = 2; // 0x2
field public static final int SESSION_STATE_INACTIVE = 0; // 0x0
+ field public static final int STATUS_ACTIVE = 3; // 0x3
field public static final int STATUS_AVAILABLE = 2; // 0x2
field public static final int STATUS_UNAVAILABLE = 1; // 0x1
field public static final int STATUS_UNSUPPORTED = 0; // 0x0
diff --git a/window/extensions/extensions/api/restricted_current.txt b/window/extensions/extensions/api/restricted_current.txt
index 490edb0..20f4ee8 100644
--- a/window/extensions/extensions/api/restricted_current.txt
+++ b/window/extensions/extensions/api/restricted_current.txt
@@ -16,13 +16,31 @@
package androidx.window.extensions.area {
+ public interface ExtensionWindowAreaPresentation {
+ method public android.content.Context getPresentationContext();
+ method public void setPresentationView(android.view.View);
+ }
+
+ public interface ExtensionWindowAreaStatus {
+ method public android.util.DisplayMetrics getWindowAreaDisplayMetrics();
+ method public int getWindowAreaStatus();
+ }
+
public interface WindowAreaComponent {
+ method public default void addRearDisplayPresentationStatusListener(androidx.window.extensions.core.util.function.Consumer<androidx.window.extensions.area.ExtensionWindowAreaStatus!>);
method public void addRearDisplayStatusListener(androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public default void endRearDisplayPresentationSession();
method public void endRearDisplaySession();
+ method public default android.util.DisplayMetrics getRearDisplayMetrics();
+ method public default androidx.window.extensions.area.ExtensionWindowAreaPresentation? getRearDisplayPresentation();
+ method public default void removeRearDisplayPresentationStatusListener(androidx.window.extensions.core.util.function.Consumer<androidx.window.extensions.area.ExtensionWindowAreaStatus!>);
method public void removeRearDisplayStatusListener(androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public default void startRearDisplayPresentationSession(android.app.Activity, androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
method public void startRearDisplaySession(android.app.Activity, androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
field public static final int SESSION_STATE_ACTIVE = 1; // 0x1
+ field public static final int SESSION_STATE_CONTENT_VISIBLE = 2; // 0x2
field public static final int SESSION_STATE_INACTIVE = 0; // 0x0
+ field public static final int STATUS_ACTIVE = 3; // 0x3
field public static final int STATUS_AVAILABLE = 2; // 0x2
field public static final int STATUS_UNAVAILABLE = 1; // 0x1
field public static final int STATUS_UNSUPPORTED = 0; // 0x0
diff --git a/window/extensions/extensions/build.gradle b/window/extensions/extensions/build.gradle
index 4941b4f2..5d477b7 100644
--- a/window/extensions/extensions/build.gradle
+++ b/window/extensions/extensions/build.gradle
@@ -26,7 +26,7 @@
api(libs.kotlinStdlib)
implementation("androidx.annotation:annotation:1.6.0")
implementation("androidx.annotation:annotation-experimental:1.1.0")
- implementation("androidx.window.extensions.core:core:1.0.0-rc01")
+ implementation("androidx.window.extensions.core:core:1.0.0")
testImplementation(libs.robolectric)
testImplementation(libs.testExtJunit)
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaPresentation.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaPresentation.java
new file mode 100644
index 0000000..ddb8e8a
--- /dev/null
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaPresentation.java
@@ -0,0 +1,44 @@
+/*
+ * 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.window.extensions.area;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+
+/**
+ * An interface representing a container in an extension window area in which app content can be
+ * shown.
+ *
+ * @since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_3}
+ * @see WindowAreaComponent#getRearDisplayPresentation()
+ */
+public interface ExtensionWindowAreaPresentation {
+
+ /**
+ * Returns the {@link Context} for the window that is being used
+ * to display the additional content provided from the application.
+ */
+ @NonNull
+ Context getPresentationContext();
+
+ /**
+ * Sets the {@link View} that the application wants to display in the extension window area.
+ */
+ void setPresentationView(@NonNull View view);
+}
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaStatus.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaStatus.java
new file mode 100644
index 0000000..2f521bc
--- /dev/null
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaStatus.java
@@ -0,0 +1,44 @@
+/*
+ * 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.window.extensions.area;
+
+import android.util.DisplayMetrics;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Interface to provide information around the current status of a window area feature.
+ *
+ * @since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_3}
+ * @see WindowAreaComponent#addRearDisplayPresentationStatusListener
+ */
+public interface ExtensionWindowAreaStatus {
+
+ /**
+ * Returns the {@link androidx.window.extensions.area.WindowAreaComponent.WindowAreaStatus}
+ * value that relates to the current status of a feature.
+ */
+ @WindowAreaComponent.WindowAreaStatus
+ int getWindowAreaStatus();
+
+ /**
+ * Returns the {@link DisplayMetrics} that corresponds to the window area that a feature
+ * interacts with. This is converted to size class information provided to developers.
+ */
+ @NonNull
+ DisplayMetrics getWindowAreaDisplayMetrics();
+}
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java
index 21d5a95..e20584c 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java
@@ -17,9 +17,11 @@
package androidx.window.extensions.area;
import android.app.Activity;
+import android.util.DisplayMetrics;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.window.extensions.WindowExtensions;
import androidx.window.extensions.core.util.function.Consumer;
@@ -40,11 +42,12 @@
* @see WindowExtensions#getWindowLayoutComponent()
*/
public interface WindowAreaComponent {
-
/**
* WindowArea status constant to signify that the feature is
* unsupported on this device. Could be due to the device not supporting that
* specific feature.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
*/
int STATUS_UNSUPPORTED = 0;
@@ -53,22 +56,35 @@
* currently unavailable but is supported on this device. This value could signify
* that the current device state does not support the specific feature or another
* process is currently enabled in that feature.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
*/
int STATUS_UNAVAILABLE = 1;
/**
* WindowArea status constant to signify that the feature is
* available to be entered or enabled.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
*/
int STATUS_AVAILABLE = 2;
+ /**
+ * WindowArea status constant to signify that the feature is
+ * already enabled.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ int STATUS_ACTIVE = 3;
+
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@IntDef({
STATUS_UNSUPPORTED,
STATUS_UNAVAILABLE,
- STATUS_AVAILABLE
+ STATUS_AVAILABLE,
+ STATUS_ACTIVE
})
@interface WindowAreaStatus {}
@@ -80,19 +96,27 @@
int SESSION_STATE_INACTIVE = 0;
/**
- * Session state constant to represent that there is an
- * active session currently in progress. Used by the library to
- * know when to return the session object to the developer when the
- * session is created and active.
+ * Session state constant to represent that there is currently an active session. The library
+ * uses this state to know when a session is created and active. Note that this state is
+ * different from SESSION_STATE_CONTENT_VISIBLE, because the presentation content in this state
+ * is not visible.
*/
int SESSION_STATE_ACTIVE = 1;
+ /**
+ * Session state constant to represent that there is an
+ * active presentation session currently in progress, and the content provided by the
+ * application is visible.
+ */
+ int SESSION_STATE_CONTENT_VISIBLE = 2;
+
@RestrictTo(RestrictTo.Scope.LIBRARY)
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@IntDef({
SESSION_STATE_ACTIVE,
- SESSION_STATE_INACTIVE
+ SESSION_STATE_INACTIVE,
+ SESSION_STATE_CONTENT_VISIBLE
})
@interface WindowAreaSessionState {}
@@ -106,21 +130,22 @@
* correspond to the [WindowAreaStatus] value that aligns with the current status
* of the rear display.
* @param consumer interested in receiving updates to WindowAreaStatus.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
*/
- void addRearDisplayStatusListener(@NonNull Consumer<@WindowAreaStatus Integer> consumer);
+ void addRearDisplayStatusListener(@NonNull Consumer<Integer> consumer);
/**
* Removes a listener no longer interested in receiving updates.
* @param consumer no longer interested in receiving updates to WindowAreaStatus
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
*/
- void removeRearDisplayStatusListener(@NonNull Consumer<@WindowAreaStatus Integer> consumer);
+ void removeRearDisplayStatusListener(@NonNull Consumer<Integer> consumer);
/**
* Creates and starts a rear display session and sends state updates to the
* consumer provided. This consumer will receive a constant represented by
* [WindowAreaSessionState] to represent the state of the current rear display
- * session. We will translate the values from the {@link Consumer} to a developer-friendly
- * interface in the developer facing API.
+ * session. We will translate to a more friendly interface in the library.
*
* Because this is being called from the OEM provided extensions, the library
* will post the result of the listener on the executor provided by the developer.
@@ -133,7 +158,9 @@
* @throws UnsupportedOperationException if this method is called when RearDisplay
* mode is not available. This could be to an incompatible device state or when
* another process is currently in this mode.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
*/
+ @SuppressWarnings("ExecutorRegistration") // Jetpack will post it on the app-provided executor.
void startRearDisplaySession(@NonNull Activity activity,
@NonNull Consumer<@WindowAreaSessionState Integer> consumer);
@@ -141,6 +168,109 @@
* Ends a RearDisplaySession and sends [STATE_INACTIVE] to the consumer
* provided in the {@code startRearDisplaySession} method. This method is only
* called through the {@code RearDisplaySession} provided to the developer.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
*/
void endRearDisplaySession();
+
+ /**
+ * Adds a listener interested in receiving updates on the rear display presentation status
+ * of the device. Because this is being called from the OEM provided
+ * extensions, the library will post the result of the listener on the executor
+ * provided by the developer.
+ *
+ * The listener provided will receive {@link ExtensionWindowAreaStatus} values that
+ * correspond to the current status of the feature.
+ *
+ * @param consumer interested in receiving updates to {@link ExtensionWindowAreaStatus}.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ default void addRearDisplayPresentationStatusListener(
+ @NonNull Consumer<ExtensionWindowAreaStatus> consumer) {
+ throw new UnsupportedOperationException("This method must not be called unless there is a"
+ + " corresponding override implementation on the device.");
+ }
+
+ /**
+ * Removes a listener no longer interested in receiving updates.
+ *
+ * @param consumer no longer interested in receiving updates to WindowAreaStatus
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ default void removeRearDisplayPresentationStatusListener(
+ @NonNull Consumer<ExtensionWindowAreaStatus> consumer) {
+ throw new UnsupportedOperationException("This method must not be called unless there is a"
+ + " corresponding override implementation on the device.");
+ }
+
+ /**
+ * Creates and starts a rear display presentation session and sends state updates to the
+ * consumer provided. This consumer will receive a constant represented by
+ * {@link WindowAreaSessionState} to represent the state of the current rear display
+ * session. We will translate to a more friendly interface in the library.
+ *
+ * Because this is being called from the OEM provided extensions, the library
+ * will post the result of the listener on the executor provided by the developer.
+ *
+ * Rear display presentation mode refers to a feature where an {@link Activity} can present
+ * additional content on a device with a second display that is facing the same direction
+ * as the rear camera (i.e. the cover display on a fold-in style device). The calling
+ * {@link Activity} stays on the user-facing display.
+ *
+ * @param activity that the OEM implementation will use as a base
+ * context and to identify the source display area of the request.
+ * The reference to the activity instance must not be stored in the OEM
+ * implementation to prevent memory leaks.
+ * @param consumer to provide updates to the client on the status of the session
+ * @throws UnsupportedOperationException if this method is called when rear display presentation
+ * mode is not available. This could be to an incompatible device state or when
+ * another process is currently in this mode.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ default void startRearDisplayPresentationSession(@NonNull Activity activity,
+ @NonNull Consumer<@WindowAreaSessionState Integer> consumer) {
+ throw new UnsupportedOperationException("This method must not be called unless there is a"
+ + " corresponding override implementation on the device.");
+ }
+
+ /**
+ * Ends the current rear display presentation session and provides updates to the
+ * callback provided. When this is ended, the presented content from the calling
+ * {@link Activity} will also be removed from the rear facing display.
+ * Because this is being called from the OEM provided extensions, the result of the listener
+ * will be posted on the executor provided by the developer at the initial call site.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ default void endRearDisplayPresentationSession() {
+ throw new UnsupportedOperationException("This method must not be called unless there is a"
+ + " corresponding override implementation on the device.");
+ }
+
+ /**
+ * Returns the {@link ExtensionWindowAreaPresentation} connected to the active
+ * rear display presentation session. If there is no session currently active, then it will
+ * return null.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ @Nullable
+ default ExtensionWindowAreaPresentation getRearDisplayPresentation() {
+ throw new UnsupportedOperationException("This method must not be called unless there is a"
+ + " corresponding override implementation on the device.");
+ }
+
+ /**
+ * Returns the {@link android.util.DisplayMetrics} associated with the rear facing display. If
+ * there is no rear facing display available on the device, returns an empty
+ * {@link android.util.DisplayMetrics} object.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ // TODO(b/273807238): Investigate how we can provide a listener to get runtime changes in
+ // rear display metrics to better support other form-factors in the future.
+ @NonNull
+ default DisplayMetrics getRearDisplayMetrics() {
+ throw new UnsupportedOperationException("This method must not be called unless there is a"
+ + " corresponding override implementation on the device.");
+ }
}
diff --git a/window/window-demos/demo/build.gradle b/window/window-demos/demo/build.gradle
index cd3bcf4..9addea3 100644
--- a/window/window-demos/demo/build.gradle
+++ b/window/window-demos/demo/build.gradle
@@ -84,6 +84,7 @@
androidx {
name = "WM Samples"
type = LibraryType.SAMPLES
+ mavenVersion = LibraryVersions.WINDOW
inceptionYear = "2023"
description = "Samples for the WM Jetpack Library"
}
diff --git a/window/window-testing/api/current.txt b/window/window-testing/api/current.txt
index 97bc7cf..847a9e8 100644
--- a/window/window-testing/api/current.txt
+++ b/window/window-testing/api/current.txt
@@ -48,6 +48,11 @@
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);
diff --git a/window/window-testing/api/restricted_current.txt b/window/window-testing/api/restricted_current.txt
index 97bc7cf..847a9e8 100644
--- a/window/window-testing/api/restricted_current.txt
+++ b/window/window-testing/api/restricted_current.txt
@@ -48,6 +48,11 @@
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);
diff --git a/window/window-testing/src/androidTest/java/androidx/window/testing/layout/WindowLayoutInfoPublisherRuleTest.kt b/window/window-testing/src/androidTest/java/androidx/window/testing/layout/WindowLayoutInfoPublisherRuleTest.kt
index 3b00629..8f2df43 100644
--- a/window/window-testing/src/androidTest/java/androidx/window/testing/layout/WindowLayoutInfoPublisherRuleTest.kt
+++ b/window/window-testing/src/androidTest/java/androidx/window/testing/layout/WindowLayoutInfoPublisherRuleTest.kt
@@ -16,6 +16,7 @@
package androidx.window.testing.layout
+import android.content.Context
import android.graphics.Rect
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.rules.ActivityScenarioRule
@@ -45,7 +46,7 @@
@LargeTest
@RunWith(AndroidJUnit4::class)
-public class WindowLayoutInfoPublisherRuleTest {
+class WindowLayoutInfoPublisherRuleTest {
private val activityRule = ActivityScenarioRule(TestActivity::class.java)
private val publisherRule = WindowLayoutInfoPublisherRule()
@@ -53,7 +54,7 @@
private val testScope = TestScope(UnconfinedTestDispatcher())
@get:Rule
- public val testRule: TestRule
+ val testRule: TestRule
init {
testRule = RuleChain.outerRule(publisherRule).around(activityRule)
@@ -61,7 +62,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@Test
- public fun testWindowLayoutInfo_relayValue(): Unit = testScope.runTest {
+ fun testWindowLayoutInfo_relayValue(): Unit = testScope.runTest {
val expected = WindowLayoutInfo(emptyList())
activityRule.scenario.onActivity { activity ->
val value = testScope.async {
@@ -77,7 +78,26 @@
@OptIn(ExperimentalCoroutinesApi::class)
@Test
- public fun testException_resetsFactoryMethod() {
+ fun testWindowLayoutInfo_fromContext_relayValue(): Unit = testScope.runTest {
+ val expected = WindowLayoutInfo(emptyList())
+ activityRule.scenario.onActivity { activity ->
+ val context: Context = activity
+ val value = testScope.async {
+ WindowInfoTracker.getOrCreate(context)
+ .windowLayoutInfo(context)
+ .first()
+ }
+ publisherRule.overrideWindowLayoutInfo(expected)
+ runTest(UnconfinedTestDispatcher(testScheduler)) {
+ val actual = value.await()
+ assertEquals(expected, actual)
+ }
+ }
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun testException_resetsFactoryMethod() {
ActivityScenario.launch(TestActivity::class.java).onActivity { activity ->
WindowInfoTracker.reset()
try {
@@ -98,7 +118,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@Test
- public fun testWindowLayoutInfo_multipleValues(): Unit = testScope.runTest {
+ fun testWindowLayoutInfo_multipleValues(): Unit = testScope.runTest {
val feature1 = object : DisplayFeature {
override val bounds: Rect
get() = Rect()
@@ -128,5 +148,38 @@
}
}
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun testWindowLayoutInfo_fromContext_multipleValues(): Unit = testScope.runTest {
+ val feature1 = object : DisplayFeature {
+ override val bounds: Rect
+ get() = Rect()
+ }
+ val feature2 = object : DisplayFeature {
+ override val bounds: Rect
+ get() = Rect()
+ }
+ val expected1 = WindowLayoutInfo(listOf(feature1))
+ val expected2 = WindowLayoutInfo(listOf(feature2))
+ activityRule.scenario.onActivity { activity ->
+ val context: Context = activity
+ val values = mutableListOf<WindowLayoutInfo>()
+ val value = testScope.async {
+ WindowInfoTracker.getOrCreate(context).windowLayoutInfo(context).take(4)
+ .toCollection(values)
+ }
+ publisherRule.overrideWindowLayoutInfo(expected1)
+ publisherRule.overrideWindowLayoutInfo(expected2)
+ publisherRule.overrideWindowLayoutInfo(expected1)
+ publisherRule.overrideWindowLayoutInfo(expected2)
+ runTest(UnconfinedTestDispatcher(testScheduler)) {
+ assertEquals(
+ listOf(expected1, expected2, expected1, expected2),
+ value.await().toList()
+ )
+ }
+ }
+ }
+
private object TestException : Exception("TEST EXCEPTION")
}
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/testing/layout/DisplayFeatureTesting.kt b/window/window-testing/src/main/java/androidx/window/testing/layout/DisplayFeatureTesting.kt
index 802279b..5bf4fac 100644
--- a/window/window-testing/src/main/java/androidx/window/testing/layout/DisplayFeatureTesting.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/layout/DisplayFeatureTesting.kt
@@ -29,6 +29,19 @@
import androidx.window.layout.FoldingFeature.State
import androidx.window.layout.FoldingFeature.State.Companion.HALF_OPENED
import androidx.window.layout.WindowMetricsCalculator
+import androidx.window.testing.layout.FoldingFeatureTestingConstants.FOLDING_FEATURE_CENTER_DEFAULT
+
+/**
+ * A class to contain all the constants related to testing
+ * [androidx.window.layout.DisplayFeature]s.
+ */
+object FoldingFeatureTestingConstants {
+ /**
+ * A constant that denotes the center of a [androidx.window.layout.FoldingFeature] should be
+ * calculated the aligned with either the vertical or horizontal center of the given window.
+ */
+ const val FOLDING_FEATURE_CENTER_DEFAULT = -1
+}
/**
* A convenience method to get a test fold with default values provided. With the default values
@@ -42,9 +55,8 @@
* ([size] / 2) and the bottom-left y-coordinate is center - ([size] / 2). The folding features
* always cover the window in one dimension and that determines the other coordinates.
*
- * The [center] is bounded below by -1. For values greater than -1 it will be set as the center.
- * For -1 it signals that the center should be calculated. The calculation is the center of the
- * [Activity] window bounds.
+ * Use [FOLDING_FEATURE_CENTER_DEFAULT] to default to the center of [Activity] window bounds.
+ * Otherwise, use values greater than or equal to 0 to specify the center.
*
* @param activity that will house the [FoldingFeature].
* @param center the center of the fold complementary to the orientation in px. For a
@@ -62,7 +74,7 @@
fun FoldingFeature(
activity: Activity,
@IntRange(from = -1)
- center: Int = -1,
+ center: Int = FOLDING_FEATURE_CENTER_DEFAULT,
size: Int = 0,
state: State = HALF_OPENED,
orientation: Orientation = HORIZONTAL
@@ -90,9 +102,8 @@
* ([size] / 2) and the bottom-left y-coordinate is center - ([size] / 2). The folding features
* always cover the window in one dimension and that determines the other coordinates.
*
- * The [center] is bounded below by -1. For values greater than -1 it will be set as the center.
- * For -1 it signals that the center should be calculated. The calculation is the center of the
- * [Activity] window bounds.
+ * Use [FOLDING_FEATURE_CENTER_DEFAULT] to default to the center of [Activity] window bounds.
+ * Otherwise, use values greater than or equal to 0 to specify the center.
*
* @param windowBounds that will contain the [FoldingFeature].
* @param center the center of the fold complementary to the orientation in px. For a
@@ -110,7 +121,7 @@
fun FoldingFeature(
windowBounds: Rect,
@IntRange(from = -1)
- center: Int = -1,
+ center: Int = FOLDING_FEATURE_CENTER_DEFAULT,
size: Int = 0,
state: State = HALF_OPENED,
orientation: Orientation = HORIZONTAL
diff --git a/window/window-testing/src/main/java/androidx/window/testing/layout/PublishLayoutInfoTracker.kt b/window/window-testing/src/main/java/androidx/window/testing/layout/PublishLayoutInfoTracker.kt
index 0f83547..22b4af7 100644
--- a/window/window-testing/src/main/java/androidx/window/testing/layout/PublishLayoutInfoTracker.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/layout/PublishLayoutInfoTracker.kt
@@ -17,6 +17,8 @@
package androidx.window.testing.layout
import android.app.Activity
+import android.content.Context
+import androidx.annotation.UiContext
import androidx.window.layout.WindowInfoTracker
import androidx.window.layout.WindowLayoutInfo
import kotlinx.coroutines.flow.Flow
@@ -29,4 +31,8 @@
override fun windowLayoutInfo(activity: Activity): Flow<WindowLayoutInfo> {
return flow
}
+
+ override fun windowLayoutInfo(@UiContext context: Context): Flow<WindowLayoutInfo> {
+ return flow
+ }
}
\ No newline at end of file
diff --git a/window/window/build.gradle b/window/window/build.gradle
index 402be78..b85bd94 100644
--- a/window/window/build.gradle
+++ b/window/window/build.gradle
@@ -49,8 +49,8 @@
implementation("androidx.collection:collection:1.1.0")
implementation("androidx.core:core:1.8.0")
- def extensions_core_version = "androidx.window.extensions.core:core:1.0.0-rc01"
- def extensions_version = "androidx.window.extensions:extensions:1.1.0-rc01"
+ def extensions_core_version = "androidx.window.extensions.core:core:1.0.0"
+ def extensions_version = "androidx.window.extensions:extensions:1.1.0"
implementation(extensions_core_version)
compileOnly(project(":window:sidecar:sidecar"))
compileOnly(extensions_version)
diff --git a/work/integration-tests/testapp/src/main/AndroidManifest.xml b/work/integration-tests/testapp/src/main/AndroidManifest.xml
index ab76a90..fde3cf6 100644
--- a/work/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/work/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -63,6 +63,15 @@
android:exported="false"
android:process=":remote"
tools:ignore="MissingServiceExportedEqualsTrue" />
+ <receiver
+ android:name=".DirectBootReceiver"
+ android:directBootAware="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
</application>
+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
</manifest>
diff --git a/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/DirectBootReceiver.kt b/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/DirectBootReceiver.kt
new file mode 100644
index 0000000..4c382dc
--- /dev/null
+++ b/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/DirectBootReceiver.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.integration.testapp
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import androidx.work.WorkManager
+
+class DirectBootReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context, p1: Intent?) {
+ // this will fail because this receiver has `directBootAware=true` and storage isn't
+ // accessible yet.
+ println("request a workmanager: ${WorkManager.getInstance(context)}")
+ }
+}
\ No newline at end of file
diff --git a/work/work-runtime-ktx/api/api_lint.ignore b/work/work-runtime-ktx/api/api_lint.ignore
deleted file mode 100644
index 7a1b7a5..0000000
--- a/work/work-runtime-ktx/api/api_lint.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-// Baseline format: 1.0
-AsyncSuffixFuture: androidx.work.CoroutineWorker#startWork():
- Methods returning com.google.common.util.concurrent.ListenableFuture should have a suffix *Async to reserve unmodified name for a suspend function
diff --git a/work/work-runtime-ktx/api/current.ignore b/work/work-runtime-ktx/api/current.ignore
index 8aff62a..4725263 100644
--- a/work/work-runtime-ktx/api/current.ignore
+++ b/work/work-runtime-ktx/api/current.ignore
@@ -1,3 +1,3 @@
// Baseline format: 1.0
-RemovedClass: androidx.work.ListenableFutureKt:
- Removed class androidx.work.ListenableFutureKt
+RemovedPackage: androidx.work:
+ Removed package androidx.work
diff --git a/work/work-runtime-ktx/api/current.txt b/work/work-runtime-ktx/api/current.txt
index c3c6e5c..e6f50d0 100644
--- a/work/work-runtime-ktx/api/current.txt
+++ b/work/work-runtime-ktx/api/current.txt
@@ -1,27 +1 @@
// Signature format: 4.0
-package androidx.work {
-
- public abstract class CoroutineWorker extends androidx.work.ListenableWorker {
- ctor public CoroutineWorker(android.content.Context appContext, androidx.work.WorkerParameters params);
- method public abstract suspend Object? doWork(kotlin.coroutines.Continuation<? super androidx.work.ListenableWorker.Result>);
- method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
- method public suspend Object? getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo>);
- method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ForegroundInfo> getForegroundInfoAsync();
- method public final void onStopped();
- method public final suspend Object? setForeground(androidx.work.ForegroundInfo foregroundInfo, kotlin.coroutines.Continuation<? super kotlin.Unit>);
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit>);
- method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result> startWork();
- property @Deprecated public kotlinx.coroutines.CoroutineDispatcher coroutineContext;
- }
-
- public final class DataKt {
- method public static inline <reified T> boolean hasKeyWithValueOfType(androidx.work.Data, String key);
- method public static inline androidx.work.Data workDataOf(kotlin.Pair<java.lang.String,?>... pairs);
- }
-
- public final class OperationKt {
- method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS>);
- }
-
-}
-
diff --git a/work/work-runtime-ktx/api/restricted_current.ignore b/work/work-runtime-ktx/api/restricted_current.ignore
index 8aff62a..4725263 100644
--- a/work/work-runtime-ktx/api/restricted_current.ignore
+++ b/work/work-runtime-ktx/api/restricted_current.ignore
@@ -1,3 +1,3 @@
// Baseline format: 1.0
-RemovedClass: androidx.work.ListenableFutureKt:
- Removed class androidx.work.ListenableFutureKt
+RemovedPackage: androidx.work:
+ Removed package androidx.work
diff --git a/work/work-runtime-ktx/api/restricted_current.txt b/work/work-runtime-ktx/api/restricted_current.txt
index c3c6e5c..e6f50d0 100644
--- a/work/work-runtime-ktx/api/restricted_current.txt
+++ b/work/work-runtime-ktx/api/restricted_current.txt
@@ -1,27 +1 @@
// Signature format: 4.0
-package androidx.work {
-
- public abstract class CoroutineWorker extends androidx.work.ListenableWorker {
- ctor public CoroutineWorker(android.content.Context appContext, androidx.work.WorkerParameters params);
- method public abstract suspend Object? doWork(kotlin.coroutines.Continuation<? super androidx.work.ListenableWorker.Result>);
- method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
- method public suspend Object? getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo>);
- method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ForegroundInfo> getForegroundInfoAsync();
- method public final void onStopped();
- method public final suspend Object? setForeground(androidx.work.ForegroundInfo foregroundInfo, kotlin.coroutines.Continuation<? super kotlin.Unit>);
- method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit>);
- method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result> startWork();
- property @Deprecated public kotlinx.coroutines.CoroutineDispatcher coroutineContext;
- }
-
- public final class DataKt {
- method public static inline <reified T> boolean hasKeyWithValueOfType(androidx.work.Data, String key);
- method public static inline androidx.work.Data workDataOf(kotlin.Pair<java.lang.String,?>... pairs);
- }
-
- public final class OperationKt {
- method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS>);
- }
-
-}
-
diff --git a/work/work-runtime-ktx/build.gradle b/work/work-runtime-ktx/build.gradle
index 34051b4..654de76 100644
--- a/work/work-runtime-ktx/build.gradle
+++ b/work/work-runtime-ktx/build.gradle
@@ -25,18 +25,6 @@
dependencies {
api project(":work:work-runtime")
- api(libs.kotlinStdlib)
- api(libs.kotlinCoroutinesAndroid)
-
- androidTestImplementation("androidx.concurrent:concurrent-futures:1.0.0")
- androidTestImplementation(libs.testExtJunit)
- androidTestImplementation(libs.testCore)
- androidTestImplementation(libs.testRunner)
- androidTestImplementation(libs.espressoCore)
- androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has its own MockMaker
- androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has its own MockMaker
- androidTestImplementation("androidx.room:room-testing:2.5.0")
- testImplementation(libs.junit)
}
androidx {
diff --git a/work/work-runtime-ktx/src/androidTest/java/androidx/work/CoroutineWorkerTest.kt b/work/work-runtime-ktx/src/androidTest/java/androidx/work/CoroutineWorkerTest.kt
deleted file mode 100644
index 34e716c..0000000
--- a/work/work-runtime-ktx/src/androidTest/java/androidx/work/CoroutineWorkerTest.kt
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.work
-
-import android.content.Context
-import android.util.Log
-import androidx.arch.core.executor.ArchTaskExecutor
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
-import androidx.test.filters.SmallTest
-import androidx.work.impl.WorkDatabase
-import androidx.work.impl.WorkManagerImpl
-import androidx.work.impl.utils.SerialExecutorImpl
-import androidx.work.impl.utils.WorkProgressUpdater
-import androidx.work.impl.utils.futures.SettableFuture
-import androidx.work.impl.utils.taskexecutor.TaskExecutor
-import androidx.work.workers.ProgressUpdatingWorker
-import java.util.UUID
-import java.util.concurrent.Executor
-import kotlinx.coroutines.asCoroutineDispatcher
-import kotlinx.coroutines.runBlocking
-import org.hamcrest.CoreMatchers.instanceOf
-import org.hamcrest.CoreMatchers.`is`
-import org.hamcrest.CoreMatchers.nullValue
-import org.hamcrest.MatcherAssert.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.any
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class CoroutineWorkerTest {
-
- private lateinit var context: Context
- private lateinit var configuration: Configuration
- private lateinit var database: WorkDatabase
- private lateinit var workManagerImpl: WorkManagerImpl
- private lateinit var progressUpdater: ProgressUpdater
- private lateinit var mForegroundUpdater: ForegroundUpdater
-
- @Before
- fun setUp() {
- ArchTaskExecutor.getInstance()
- .setDelegate(object : androidx.arch.core.executor.TaskExecutor() {
- override fun executeOnDiskIO(runnable: Runnable) {
- runnable.run()
- }
-
- override fun postToMainThread(runnable: Runnable) {
- runnable.run()
- }
-
- override fun isMainThread(): Boolean {
- return true
- }
- })
-
- context = ApplicationProvider.getApplicationContext()
- configuration = Configuration.Builder()
- .setExecutor(SynchronousExecutor())
- .setMinimumLoggingLevel(Log.DEBUG)
- .build()
- workManagerImpl = WorkManagerImpl(
- context, configuration,
- InstantWorkTaskExecutor()
- )
- WorkManagerImpl.setDelegate(workManagerImpl)
- database = workManagerImpl.workDatabase
- // No op
- progressUpdater = ProgressUpdater { _, _, _ ->
- val future = SettableFuture.create<Void>()
- future.set(null)
- future
- }
- mForegroundUpdater = mock(ForegroundUpdater::class.java)
- }
-
- @After
- fun tearDown() {
- WorkManagerImpl.setDelegate(null)
- ArchTaskExecutor.getInstance().setDelegate(null)
- }
-
- @Test
- fun testCoroutineWorker_basicUsage() {
- val workerFactory = WorkerFactory.getDefaultWorkerFactory()
- val worker = workerFactory.createWorkerWithDefaultFallback(
- context,
- SynchronousCoroutineWorker::class.java.name,
- WorkerParameters(workerFactory)
- ) as SynchronousCoroutineWorker
-
- assertThat(worker.job.isCompleted, `is`(false))
-
- val future = worker.startWork()
- val result = future.get()
-
- assertThat(future.isDone, `is`(true))
- assertThat(future.isCancelled, `is`(false))
- assertThat(result, `is`(instanceOf(ListenableWorker.Result.Success::class.java)))
- assertThat(
- (result as ListenableWorker.Result.Success).outputData.getLong(
- "output", 0L
- ),
- `is`(999L)
- )
- }
-
- @Test
- fun testCoroutineWorker_cancellingFutureCancelsJob() {
- val workerFactory = WorkerFactory.getDefaultWorkerFactory()
- val worker = workerFactory.createWorkerWithDefaultFallback(
- context,
- SynchronousCoroutineWorker::class.java.name,
- WorkerParameters(workerFactory)
- ) as SynchronousCoroutineWorker
-
- assertThat(worker.job.isCancelled, `is`(false))
- worker.future.cancel(true)
- assertThat(worker.job.isCancelled, `is`(true))
- }
-
- @Test
- @LargeTest
- fun testProgressUpdates() {
- val workerFactory = WorkerFactory.getDefaultWorkerFactory()
- val progressUpdater = spy(WorkProgressUpdater(database, workManagerImpl.workTaskExecutor))
- val workRequest = OneTimeWorkRequestBuilder<ProgressUpdatingWorker>().build()
- database.workSpecDao().insertWorkSpec(workRequest.workSpec)
- val worker = workerFactory.createWorkerWithDefaultFallback(
- context,
- ProgressUpdatingWorker::class.java.name,
- WorkerParameters(
- workerFactory,
- workRequest.id,
- progressUpdater,
- )
- ) as ProgressUpdatingWorker
-
- runBlocking {
- val result = worker.doWork()
- val captor = ArgumentCaptor.forClass(Data::class.java)
- verify(progressUpdater, times(2))
- .updateProgress(
- any(Context::class.java),
- any(UUID::class.java),
- captor.capture()
- )
- assertThat(result, `is`(instanceOf(ListenableWorker.Result.Success::class.java)))
- val recent = captor.allValues.lastOrNull()
- assertThat(recent?.getInt(ProgressUpdatingWorker.Progress, 0), `is`(100))
- val progress = database.workProgressDao().getProgressForWorkSpecId(workRequest.stringId)
- assertThat(progress, nullValue())
- }
- }
-
- @Test
- @LargeTest
- fun testProgressUpdatesForRetry() {
- val workerFactory = WorkerFactory.getDefaultWorkerFactory()
- val progressUpdater = spy(WorkProgressUpdater(database, workManagerImpl.workTaskExecutor))
- val input = workDataOf(ProgressUpdatingWorker.Expected to "Retry")
- val workRequest = OneTimeWorkRequestBuilder<ProgressUpdatingWorker>()
- .setInputData(input)
- .build()
- database.workSpecDao().insertWorkSpec(workRequest.workSpec)
- val worker = workerFactory.createWorkerWithDefaultFallback(
- context,
- ProgressUpdatingWorker::class.java.name,
- WorkerParameters(
- workerFactory,
- workRequest.id,
- progressUpdater,
- )
- ) as ProgressUpdatingWorker
-
- runBlocking {
- val result = worker.doWork()
- val captor = ArgumentCaptor.forClass(Data::class.java)
- verify(progressUpdater, times(2))
- .updateProgress(
- any(Context::class.java),
- any(UUID::class.java),
- captor.capture()
- )
- assertThat(result, `is`(instanceOf(ListenableWorker.Result.Success::class.java)))
- val recent = captor.allValues.lastOrNull()
- assertThat(recent?.getInt(ProgressUpdatingWorker.Progress, 0), `is`(100))
- val progress = database.workProgressDao().getProgressForWorkSpecId(workRequest.stringId)
- assertThat(progress, nullValue())
- }
- }
-
- class SynchronousExecutor : Executor {
-
- override fun execute(command: Runnable) {
- command.run()
- }
- }
-
- class InstantWorkTaskExecutor : TaskExecutor {
-
- private val mSynchronousExecutor = SynchronousExecutor()
- private val mSerialExecutor = SerialExecutorImpl(mSynchronousExecutor)
-
- override fun getMainThreadExecutor(): Executor {
- return mSynchronousExecutor
- }
-
- override fun getSerialTaskExecutor(): SerialExecutorImpl {
- return mSerialExecutor
- }
- }
-
- class SynchronousCoroutineWorker(context: Context, params: WorkerParameters) :
- CoroutineWorker(context, params) {
-
- override suspend fun doWork(): Result {
- return Result.success(workDataOf("output" to 999L))
- }
-
- @Deprecated(message = "use withContext(...) inside doWork() instead.")
- override val coroutineContext = SynchronousExecutor().asCoroutineDispatcher()
- }
-
- fun WorkerParameters(
- workerFactory: WorkerFactory,
- id: UUID = UUID.randomUUID(),
- progressUpdater: ProgressUpdater = this.progressUpdater,
- ) = WorkerParameters(
- id,
- Data.EMPTY,
- emptyList(),
- WorkerParameters.RuntimeExtras(),
- 1,
- 1,
- configuration.executor,
- workManagerImpl.workTaskExecutor,
- workerFactory,
- progressUpdater,
- mForegroundUpdater
- )
-}
\ No newline at end of file
diff --git a/work/work-runtime-ktx/src/androidTest/java/androidx/work/OneTimeWorkRequestTest.kt b/work/work-runtime-ktx/src/androidTest/java/androidx/work/OneTimeWorkRequestTest.kt
deleted file mode 100644
index 579a282..0000000
--- a/work/work-runtime-ktx/src/androidTest/java/androidx/work/OneTimeWorkRequestTest.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.work
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import androidx.work.workers.TestWorker
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class OneTimeWorkRequestTest {
- @Test
- fun testOneTimeWorkRequestBuilder() {
- val builder = OneTimeWorkRequestBuilder<TestWorker>()
- builder.setInputMerger(ArrayCreatingInputMerger::class)
- val request = builder.build()
- assertEquals(request.workSpec.workerClassName, TestWorker::class.java.name)
- assertEquals(
- request.workSpec.inputMergerClassName,
- ArrayCreatingInputMerger::class.java.name
- )
- }
-
- @Test
- fun testOneTimeWorkRequestBuilderDefaults() {
- val builder = OneTimeWorkRequestBuilder<TestWorker>()
- val request = builder.build()
- assertEquals(request.workSpec.workerClassName, TestWorker::class.java.name)
- assertEquals(
- request.workSpec.inputMergerClassName,
- OverwritingInputMerger::class.java.name
- )
- }
-}
diff --git a/work/work-runtime-ktx/src/androidTest/java/androidx/work/PeriodicWorkRequestTest.kt b/work/work-runtime-ktx/src/androidTest/java/androidx/work/PeriodicWorkRequestTest.kt
deleted file mode 100644
index 685151b..0000000
--- a/work/work-runtime-ktx/src/androidTest/java/androidx/work/PeriodicWorkRequestTest.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.work
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import androidx.test.filters.SmallTest
-import androidx.work.workers.TestWorker
-import java.time.Duration
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.TimeUnit.HOURS
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotEquals
-import org.junit.Assert.assertThrows
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class PeriodicWorkRequestTest {
- @Test
- fun testPeriodicWorkRequestBuilder() {
- val builder = PeriodicWorkRequestBuilder<TestWorker>(
- repeatInterval = 15L,
- repeatIntervalTimeUnit = TimeUnit.MINUTES
- )
- val workRequest = builder.build()
- assertEquals(workRequest.workSpec.workerClassName, TestWorker::class.java.name)
- assertEquals(workRequest.workSpec.isPeriodic, true)
- assertEquals(workRequest.workSpec.intervalDuration, TimeUnit.MINUTES.toMillis(15))
- assertEquals(workRequest.workSpec.flexDuration, TimeUnit.MINUTES.toMillis(15))
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 26)
- fun testPeriodicWorkRequestBuilder_withDuration() {
- val repeatInterval = Duration.ofDays(2).plusHours(3)
- val builder = PeriodicWorkRequestBuilder<TestWorker>(repeatInterval)
- val workRequest = builder.build()
- assertEquals(workRequest.workSpec.workerClassName, TestWorker::class.java.name)
- assertEquals(workRequest.workSpec.isPeriodic, true)
- assertEquals(workRequest.workSpec.intervalDuration, repeatInterval.toMillis())
- assertEquals(workRequest.workSpec.flexDuration, repeatInterval.toMillis())
- }
-
- @Test
- fun testPeriodicWorkRequestBuilder_withFlexTime() {
- val builder = PeriodicWorkRequestBuilder<TestWorker>(
- repeatInterval = 15L,
- repeatIntervalTimeUnit = TimeUnit.MINUTES,
- flexTimeInterval = 10L,
- flexTimeIntervalUnit = TimeUnit.MINUTES
- )
- val workRequest = builder.build()
- assertEquals(workRequest.workSpec.workerClassName, TestWorker::class.java.name)
- assertEquals(workRequest.workSpec.isPeriodic, true)
- assertEquals(workRequest.workSpec.flexDuration, TimeUnit.MINUTES.toMillis(10))
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 26)
- fun testPeriodicWorkRequestBuilder_withFlexTimeandDuration() {
- val repeatInterval = Duration.ofHours(3).plusMinutes(25)
- val flexInterval = repeatInterval.minusMinutes(15)
- val builder = PeriodicWorkRequestBuilder<TestWorker>(
- repeatInterval = repeatInterval,
- flexTimeInterval = flexInterval
- )
- val workRequest = builder.build()
- assertEquals(workRequest.workSpec.workerClassName, TestWorker::class.java.name)
- assertEquals(workRequest.workSpec.isPeriodic, true)
- assertEquals(workRequest.workSpec.intervalDuration, repeatInterval.toMillis())
- assertEquals(workRequest.workSpec.flexDuration, flexInterval.toMillis())
- }
-
- @Test
- fun testPeriodicWorkRequestBuilder_noNextScheduleTimeOverride_noGeneration() {
- val builder = PeriodicWorkRequestBuilder<TestWorker>(
- HOURS.toMillis(15L), HOURS
- )
- assertEquals(builder.build().workSpec.nextScheduleTimeOverride, Long.MAX_VALUE)
- assertEquals(builder.build().workSpec.nextScheduleTimeOverrideGeneration, 0)
- }
-
- @Test
- fun testPeriodicWorkRequestBuilder_nextScheduleTimeOverride_setsGeneration() {
- val builder = PeriodicWorkRequestBuilder<TestWorker>(
- HOURS.toMillis(15L), HOURS
- )
- builder.setNextScheduleTimeOverride(123456)
- assertEquals(builder.build().workSpec.nextScheduleTimeOverride, 123456L)
- assertEquals(builder.build().workSpec.nextScheduleTimeOverrideGeneration, 1)
- }
-
- @Test
- fun testPeriodicWorkRequestBuilder_nextScheduleTimeOverride_maxLongNotAllowed() {
- val builder = PeriodicWorkRequestBuilder<TestWorker>(
- HOURS.toMillis(15L), HOURS
- )
- assertThrows(IllegalArgumentException::class.java) {
- builder.setNextScheduleTimeOverride(Long.MAX_VALUE)
- }
- }
-
- @Test
- fun testPeriodicWorkRequest_clearNextScheduleTimeOverride_setsGeneration() {
- val plainRequest = PeriodicWorkRequestBuilder<TestWorker>(
- HOURS.toMillis(15L), HOURS
- ).build()
-
- val clearedRequest = PeriodicWorkRequestBuilder<TestWorker>(
- HOURS.toMillis(15L), HOURS
- )
- .setNextScheduleTimeOverride(123456)
- .clearNextScheduleTimeOverride().build()
-
- // The generation should stay incremented, since the request still has to clear any override
- // that has been already set in the database.
- assertNotEquals(plainRequest, clearedRequest)
- }
-}
diff --git a/work/work-runtime-ktx/src/androidTest/java/androidx/work/workers/ProgressUpdatingWorker.kt b/work/work-runtime-ktx/src/androidTest/java/androidx/work/workers/ProgressUpdatingWorker.kt
deleted file mode 100644
index 8a17d1f..0000000
--- a/work/work-runtime-ktx/src/androidTest/java/androidx/work/workers/ProgressUpdatingWorker.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.work.workers
-
-import android.content.Context
-import androidx.work.CoroutineWorker
-import androidx.work.Data
-import androidx.work.WorkerParameters
-import kotlinx.coroutines.delay
-
-class ProgressUpdatingWorker(context: Context, parameters: WorkerParameters) :
- CoroutineWorker(context, parameters) {
-
- companion object {
- const val Expected = "Expected"
- const val Progress = "Progress"
- private const val delayDuration = 1L
- }
-
- override suspend fun doWork(): Result {
- val firstUpdate = Data.Builder().putInt(Progress, 10).build()
- val lastUpdate = Data.Builder().putInt(Progress, 100).build()
- val expected = inputData.getString(Expected)
- setProgress(firstUpdate)
- delay(delayDuration)
- setProgress(lastUpdate)
- return when (expected) {
- "Failure" -> Result.failure()
- "Retry" -> Result.retry()
- else -> Result.success()
- }
- }
-}
\ No newline at end of file
diff --git a/work/work-runtime-ktx/src/androidTest/java/androidx/work/workers/TestWorker.kt b/work/work-runtime-ktx/src/androidTest/java/androidx/work/workers/TestWorker.kt
deleted file mode 100644
index 478a0a5..0000000
--- a/work/work-runtime-ktx/src/androidTest/java/androidx/work/workers/TestWorker.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.work.workers
-
-import android.content.Context
-import androidx.work.Worker
-import androidx.work.WorkerParameters
-
-class TestWorker(appContext: Context, params: WorkerParameters) : Worker(appContext, params) {
- override fun doWork(): Result {
- return Result.success()
- }
-}
diff --git a/work/work-runtime-ktx/src/androidTest/res/values/values.xml b/work/work-runtime-ktx/src/androidTest/res/values/values.xml
deleted file mode 100644
index bb6fa33..0000000
--- a/work/work-runtime-ktx/src/androidTest/res/values/values.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources>
- <bool name="workmanager_test_configuration">true</bool>
-</resources>
diff --git a/work/work-runtime/api/api_lint.ignore b/work/work-runtime/api/api_lint.ignore
index 95007bb..191ab3b 100644
--- a/work/work-runtime/api/api_lint.ignore
+++ b/work/work-runtime/api/api_lint.ignore
@@ -7,6 +7,8 @@
Acronyms should not be capitalized in class names: was `SUCCESS`, should this be `Success`?
+AsyncSuffixFuture: androidx.work.CoroutineWorker#startWork():
+ Methods returning com.google.common.util.concurrent.ListenableFuture should have a suffix *Async to reserve unmodified name for a suspend function
AsyncSuffixFuture: androidx.work.ListenableWorker#startWork():
Methods returning com.google.common.util.concurrent.ListenableFuture should have a suffix *Async to reserve unmodified name for a suspend function
AsyncSuffixFuture: androidx.work.Operation#getResult():
@@ -127,18 +129,6 @@
W does not declare a `getInputData()` method matching method androidx.work.WorkRequest.Builder.setInputData(androidx.work.Data)
-MissingNullability: androidx.work.OneTimeWorkRequestKt#OneTimeWorkRequestBuilder():
- Missing nullability on method `OneTimeWorkRequestBuilder` return
-MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(java.time.Duration):
- Missing nullability on method `PeriodicWorkRequestBuilder` return
-MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(java.time.Duration, java.time.Duration):
- Missing nullability on method `PeriodicWorkRequestBuilder` return
-MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(long, java.util.concurrent.TimeUnit):
- Missing nullability on method `PeriodicWorkRequestBuilder` return
-MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit):
- Missing nullability on method `PeriodicWorkRequestBuilder` return
-
-
NoByteOrShort: androidx.work.Data#getByte(String, byte):
Should avoid odd sized primitives; use `int` instead of `byte` in method androidx.work.Data.getByte(String,byte)
NoByteOrShort: androidx.work.Data#getByte(String, byte) parameter #1:
diff --git a/work/work-runtime/api/current.txt b/work/work-runtime/api/current.txt
index 2986124..93f40a4 100644
--- a/work/work-runtime/api/current.txt
+++ b/work/work-runtime/api/current.txt
@@ -112,6 +112,19 @@
property public final android.net.Uri uri;
}
+ public abstract class CoroutineWorker extends androidx.work.ListenableWorker {
+ ctor public CoroutineWorker(android.content.Context appContext, androidx.work.WorkerParameters params);
+ method public abstract suspend Object? doWork(kotlin.coroutines.Continuation<? super androidx.work.ListenableWorker.Result>);
+ method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
+ method public suspend Object? getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo>);
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ForegroundInfo> getForegroundInfoAsync();
+ method public final void onStopped();
+ method public final suspend Object? setForeground(androidx.work.ForegroundInfo foregroundInfo, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result> startWork();
+ property @Deprecated public kotlinx.coroutines.CoroutineDispatcher coroutineContext;
+ }
+
public final class Data {
ctor public Data(androidx.work.Data);
method @androidx.room.TypeConverter public static androidx.work.Data fromByteArray(byte[]);
@@ -157,6 +170,11 @@
method public androidx.work.Data.Builder putStringArray(String, String![]);
}
+ public final class DataKt {
+ method public static inline <reified T> boolean hasKeyWithValueOfType(androidx.work.Data, String key);
+ method public static inline androidx.work.Data workDataOf(kotlin.Pair<java.lang.String,?>... pairs);
+ }
+
public class DelegatingWorkerFactory extends androidx.work.WorkerFactory {
ctor public DelegatingWorkerFactory();
method public final void addFactory(androidx.work.WorkerFactory);
@@ -281,6 +299,10 @@
public static final class Operation.State.SUCCESS extends androidx.work.Operation.State {
}
+ public final class OperationKt {
+ method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS>);
+ }
+
public enum OutOfQuotaPolicy {
method public static androidx.work.OutOfQuotaPolicy valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
method public static androidx.work.OutOfQuotaPolicy[] values();
diff --git a/work/work-runtime/api/restricted_current.txt b/work/work-runtime/api/restricted_current.txt
index 2986124..93f40a4 100644
--- a/work/work-runtime/api/restricted_current.txt
+++ b/work/work-runtime/api/restricted_current.txt
@@ -112,6 +112,19 @@
property public final android.net.Uri uri;
}
+ public abstract class CoroutineWorker extends androidx.work.ListenableWorker {
+ ctor public CoroutineWorker(android.content.Context appContext, androidx.work.WorkerParameters params);
+ method public abstract suspend Object? doWork(kotlin.coroutines.Continuation<? super androidx.work.ListenableWorker.Result>);
+ method @Deprecated public kotlinx.coroutines.CoroutineDispatcher getCoroutineContext();
+ method public suspend Object? getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo>);
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ForegroundInfo> getForegroundInfoAsync();
+ method public final void onStopped();
+ method public final suspend Object? setForeground(androidx.work.ForegroundInfo foregroundInfo, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result> startWork();
+ property @Deprecated public kotlinx.coroutines.CoroutineDispatcher coroutineContext;
+ }
+
public final class Data {
ctor public Data(androidx.work.Data);
method @androidx.room.TypeConverter public static androidx.work.Data fromByteArray(byte[]);
@@ -157,6 +170,11 @@
method public androidx.work.Data.Builder putStringArray(String, String![]);
}
+ public final class DataKt {
+ method public static inline <reified T> boolean hasKeyWithValueOfType(androidx.work.Data, String key);
+ method public static inline androidx.work.Data workDataOf(kotlin.Pair<java.lang.String,?>... pairs);
+ }
+
public class DelegatingWorkerFactory extends androidx.work.WorkerFactory {
ctor public DelegatingWorkerFactory();
method public final void addFactory(androidx.work.WorkerFactory);
@@ -281,6 +299,10 @@
public static final class Operation.State.SUCCESS extends androidx.work.Operation.State {
}
+ public final class OperationKt {
+ method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS>);
+ }
+
public enum OutOfQuotaPolicy {
method public static androidx.work.OutOfQuotaPolicy valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
method public static androidx.work.OutOfQuotaPolicy[] values();
diff --git a/work/work-runtime/build.gradle b/work/work-runtime/build.gradle
index ff562a1..70c05ae 100644
--- a/work/work-runtime/build.gradle
+++ b/work/work-runtime/build.gradle
@@ -61,10 +61,9 @@
}
dependencies {
- implementation("androidx.core:core:1.9.0")
ksp("androidx.room:room-compiler:2.5.0")
+ implementation("androidx.core:core:1.9.0")
implementation("androidx.room:room-ktx:2.5.0")
- androidTestImplementation("androidx.room:room-testing:2.5.0")
implementation("androidx.sqlite:sqlite-framework:2.3.0")
api("androidx.annotation:annotation-experimental:1.0.0")
api(libs.guavaListenableFuture)
@@ -72,12 +71,14 @@
api("androidx.startup:startup-runtime:1.1.1")
implementation("androidx.lifecycle:lifecycle-service:2.5.1")
api(libs.kotlinStdlib)
+ api(libs.kotlinCoroutinesAndroid)
androidTestImplementation(libs.multidex)
androidTestImplementation(libs.truth)
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.testCore)
androidTestImplementation("androidx.arch.core:core-testing:2.2.0")
androidTestImplementation(projectOrArtifact(":lifecycle:lifecycle-runtime-testing"))
+ androidTestImplementation("androidx.room:room-testing:2.5.0")
androidTestImplementation(libs.testRunner)
androidTestImplementation(libs.espressoCore)
androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has its own MockMaker
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/CoroutineWorkerTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/CoroutineWorkerTest.kt
new file mode 100644
index 0000000..7d3bdbc
--- /dev/null
+++ b/work/work-runtime/src/androidTest/java/androidx/work/CoroutineWorkerTest.kt
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work
+
+import android.content.Context
+import android.util.Log
+import androidx.arch.core.executor.ArchTaskExecutor
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SmallTest
+import androidx.work.impl.WorkDatabase
+import androidx.work.impl.WorkManagerImpl
+import androidx.work.impl.utils.SerialExecutorImpl
+import androidx.work.impl.utils.WorkProgressUpdater
+import androidx.work.impl.utils.futures.SettableFuture
+import androidx.work.impl.utils.taskexecutor.TaskExecutor
+import androidx.work.worker.ProgressUpdatingWorker
+import java.util.UUID
+import java.util.concurrent.Executor
+import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.runBlocking
+import org.hamcrest.CoreMatchers.instanceOf
+import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.CoreMatchers.nullValue
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.any
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class CoroutineWorkerTest {
+
+ private lateinit var context: Context
+ private lateinit var configuration: Configuration
+ private lateinit var database: WorkDatabase
+ private lateinit var workManagerImpl: WorkManagerImpl
+ private lateinit var progressUpdater: ProgressUpdater
+ private lateinit var mForegroundUpdater: ForegroundUpdater
+
+ @Before
+ fun setUp() {
+ ArchTaskExecutor.getInstance()
+ .setDelegate(object : androidx.arch.core.executor.TaskExecutor() {
+ override fun executeOnDiskIO(runnable: Runnable) {
+ runnable.run()
+ }
+
+ override fun postToMainThread(runnable: Runnable) {
+ runnable.run()
+ }
+
+ override fun isMainThread(): Boolean {
+ return true
+ }
+ })
+
+ context = ApplicationProvider.getApplicationContext()
+ configuration = Configuration.Builder()
+ .setExecutor(SynchronousExecutor())
+ .setMinimumLoggingLevel(Log.DEBUG)
+ .build()
+ workManagerImpl = WorkManagerImpl(
+ context, configuration,
+ InstantWorkTaskExecutor()
+ )
+ WorkManagerImpl.setDelegate(workManagerImpl)
+ database = workManagerImpl.workDatabase
+ // No op
+ progressUpdater = ProgressUpdater { _, _, _ ->
+ val future = SettableFuture.create<Void>()
+ future.set(null)
+ future
+ }
+ mForegroundUpdater = mock(ForegroundUpdater::class.java)
+ }
+
+ @After
+ fun tearDown() {
+ WorkManagerImpl.setDelegate(null)
+ ArchTaskExecutor.getInstance().setDelegate(null)
+ }
+
+ @Test
+ fun testCoroutineWorker_basicUsage() {
+ val workerFactory = WorkerFactory.getDefaultWorkerFactory()
+ val worker = workerFactory.createWorkerWithDefaultFallback(
+ context,
+ SynchronousCoroutineWorker::class.java.name,
+ WorkerParameters(workerFactory)
+ ) as SynchronousCoroutineWorker
+
+ assertThat(worker.job.isCompleted, `is`(false))
+
+ val future = worker.startWork()
+ val result = future.get()
+
+ assertThat(future.isDone, `is`(true))
+ assertThat(future.isCancelled, `is`(false))
+ assertThat(result, `is`(instanceOf(ListenableWorker.Result.Success::class.java)))
+ assertThat(
+ (result as ListenableWorker.Result.Success).outputData.getLong(
+ "output", 0L
+ ),
+ `is`(999L)
+ )
+ }
+
+ @Test
+ fun testCoroutineWorker_cancellingFutureCancelsJob() {
+ val workerFactory = WorkerFactory.getDefaultWorkerFactory()
+ val worker = workerFactory.createWorkerWithDefaultFallback(
+ context,
+ SynchronousCoroutineWorker::class.java.name,
+ WorkerParameters(workerFactory)
+ ) as SynchronousCoroutineWorker
+
+ assertThat(worker.job.isCancelled, `is`(false))
+ worker.future.cancel(true)
+ assertThat(worker.job.isCancelled, `is`(true))
+ }
+
+ @Test
+ @LargeTest
+ fun testProgressUpdates() {
+ val workerFactory = WorkerFactory.getDefaultWorkerFactory()
+ val progressUpdater = spy(WorkProgressUpdater(database, workManagerImpl.workTaskExecutor))
+ val workRequest = OneTimeWorkRequestBuilder<ProgressUpdatingWorker>().build()
+ database.workSpecDao().insertWorkSpec(workRequest.workSpec)
+ val worker = workerFactory.createWorkerWithDefaultFallback(
+ context,
+ ProgressUpdatingWorker::class.java.name,
+ WorkerParameters(
+ workerFactory,
+ workRequest.id,
+ progressUpdater,
+ )
+ ) as ProgressUpdatingWorker
+
+ runBlocking {
+ val result = worker.doWork()
+ val captor = ArgumentCaptor.forClass(Data::class.java)
+ verify(progressUpdater, times(2))
+ .updateProgress(
+ any(Context::class.java),
+ any(UUID::class.java),
+ captor.capture()
+ )
+ assertThat(result, `is`(instanceOf(ListenableWorker.Result.Success::class.java)))
+ val recent = captor.allValues.lastOrNull()
+ assertThat(recent?.getInt(ProgressUpdatingWorker.Progress, 0), `is`(100))
+ val progress = database.workProgressDao().getProgressForWorkSpecId(workRequest.stringId)
+ assertThat(progress, nullValue())
+ }
+ }
+
+ @Test
+ @LargeTest
+ fun testProgressUpdatesForRetry() {
+ val workerFactory = WorkerFactory.getDefaultWorkerFactory()
+ val progressUpdater = spy(WorkProgressUpdater(database, workManagerImpl.workTaskExecutor))
+ val input = workDataOf(ProgressUpdatingWorker.Expected to "Retry")
+ val workRequest = OneTimeWorkRequestBuilder<ProgressUpdatingWorker>()
+ .setInputData(input)
+ .build()
+ database.workSpecDao().insertWorkSpec(workRequest.workSpec)
+ val worker = workerFactory.createWorkerWithDefaultFallback(
+ context,
+ ProgressUpdatingWorker::class.java.name,
+ WorkerParameters(
+ workerFactory,
+ workRequest.id,
+ progressUpdater,
+ )
+ ) as ProgressUpdatingWorker
+
+ runBlocking {
+ val result = worker.doWork()
+ val captor = ArgumentCaptor.forClass(Data::class.java)
+ verify(progressUpdater, times(2))
+ .updateProgress(
+ any(Context::class.java),
+ any(UUID::class.java),
+ captor.capture()
+ )
+ assertThat(result, `is`(instanceOf(ListenableWorker.Result.Success::class.java)))
+ val recent = captor.allValues.lastOrNull()
+ assertThat(recent?.getInt(ProgressUpdatingWorker.Progress, 0), `is`(100))
+ val progress = database.workProgressDao().getProgressForWorkSpecId(workRequest.stringId)
+ assertThat(progress, nullValue())
+ }
+ }
+
+ class SynchronousExecutor : Executor {
+
+ override fun execute(command: Runnable) {
+ command.run()
+ }
+ }
+
+ class InstantWorkTaskExecutor : TaskExecutor {
+
+ private val mSynchronousExecutor = SynchronousExecutor()
+ private val mSerialExecutor = SerialExecutorImpl(mSynchronousExecutor)
+
+ override fun getMainThreadExecutor(): Executor {
+ return mSynchronousExecutor
+ }
+
+ override fun getSerialTaskExecutor(): SerialExecutorImpl {
+ return mSerialExecutor
+ }
+ }
+
+ class SynchronousCoroutineWorker(context: Context, params: WorkerParameters) :
+ CoroutineWorker(context, params) {
+
+ override suspend fun doWork(): Result {
+ return Result.success(workDataOf("output" to 999L))
+ }
+
+ @Deprecated(message = "use withContext(...) inside doWork() instead.")
+ override val coroutineContext = SynchronousExecutor().asCoroutineDispatcher()
+ }
+
+ fun WorkerParameters(
+ workerFactory: WorkerFactory,
+ id: UUID = UUID.randomUUID(),
+ progressUpdater: ProgressUpdater = this.progressUpdater,
+ ) = WorkerParameters(
+ id,
+ Data.EMPTY,
+ emptyList(),
+ WorkerParameters.RuntimeExtras(),
+ 1,
+ 1,
+ configuration.executor,
+ workManagerImpl.workTaskExecutor,
+ workerFactory,
+ progressUpdater,
+ mForegroundUpdater
+ )
+}
\ No newline at end of file
diff --git a/work/work-runtime-ktx/src/androidTest/java/androidx/work/DataTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/DataTest.kt
similarity index 100%
rename from work/work-runtime-ktx/src/androidTest/java/androidx/work/DataTest.kt
rename to work/work-runtime/src/androidTest/java/androidx/work/DataTest.kt
diff --git a/work/work-runtime-ktx/src/androidTest/java/androidx/work/ListenableFutureTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/ListenableFutureTest.kt
similarity index 100%
rename from work/work-runtime-ktx/src/androidTest/java/androidx/work/ListenableFutureTest.kt
rename to work/work-runtime/src/androidTest/java/androidx/work/ListenableFutureTest.kt
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/OneTimeWorkRequestTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/OneTimeWorkRequestTest.kt
new file mode 100644
index 0000000..5b7f4b6
--- /dev/null
+++ b/work/work-runtime/src/androidTest/java/androidx/work/OneTimeWorkRequestTest.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.work.worker.TestWorker
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class OneTimeWorkRequestTest {
+ @Test
+ fun testOneTimeWorkRequestBuilder() {
+ val builder = OneTimeWorkRequestBuilder<TestWorker>()
+ builder.setInputMerger(ArrayCreatingInputMerger::class)
+ val request = builder.build()
+ assertEquals(request.workSpec.workerClassName, TestWorker::class.java.name)
+ assertEquals(
+ request.workSpec.inputMergerClassName,
+ ArrayCreatingInputMerger::class.java.name
+ )
+ }
+
+ @Test
+ fun testOneTimeWorkRequestBuilderDefaults() {
+ val builder = OneTimeWorkRequestBuilder<TestWorker>()
+ val request = builder.build()
+ assertEquals(request.workSpec.workerClassName, TestWorker::class.java.name)
+ assertEquals(
+ request.workSpec.inputMergerClassName,
+ OverwritingInputMerger::class.java.name
+ )
+ }
+}
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/PeriodicWorkRequestTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/PeriodicWorkRequestTest.kt
new file mode 100644
index 0000000..4fa6dff
--- /dev/null
+++ b/work/work-runtime/src/androidTest/java/androidx/work/PeriodicWorkRequestTest.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import androidx.work.worker.TestWorker
+import java.time.Duration
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeUnit.HOURS
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class PeriodicWorkRequestTest {
+ @Test
+ fun testPeriodicWorkRequestBuilder() {
+ val builder = PeriodicWorkRequestBuilder<TestWorker>(
+ repeatInterval = 15L,
+ repeatIntervalTimeUnit = TimeUnit.MINUTES
+ )
+ val workRequest = builder.build()
+ assertEquals(workRequest.workSpec.workerClassName, TestWorker::class.java.name)
+ assertEquals(workRequest.workSpec.isPeriodic, true)
+ assertEquals(workRequest.workSpec.intervalDuration, TimeUnit.MINUTES.toMillis(15))
+ assertEquals(workRequest.workSpec.flexDuration, TimeUnit.MINUTES.toMillis(15))
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 26)
+ fun testPeriodicWorkRequestBuilder_withDuration() {
+ val repeatInterval = Duration.ofDays(2).plusHours(3)
+ val builder = PeriodicWorkRequestBuilder<TestWorker>(repeatInterval)
+ val workRequest = builder.build()
+ assertEquals(workRequest.workSpec.workerClassName, TestWorker::class.java.name)
+ assertEquals(workRequest.workSpec.isPeriodic, true)
+ assertEquals(workRequest.workSpec.intervalDuration, repeatInterval.toMillis())
+ assertEquals(workRequest.workSpec.flexDuration, repeatInterval.toMillis())
+ }
+
+ @Test
+ fun testPeriodicWorkRequestBuilder_withFlexTime() {
+ val builder = PeriodicWorkRequestBuilder<TestWorker>(
+ repeatInterval = 15L,
+ repeatIntervalTimeUnit = TimeUnit.MINUTES,
+ flexTimeInterval = 10L,
+ flexTimeIntervalUnit = TimeUnit.MINUTES
+ )
+ val workRequest = builder.build()
+ assertEquals(workRequest.workSpec.workerClassName, TestWorker::class.java.name)
+ assertEquals(workRequest.workSpec.isPeriodic, true)
+ assertEquals(workRequest.workSpec.flexDuration, TimeUnit.MINUTES.toMillis(10))
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 26)
+ fun testPeriodicWorkRequestBuilder_withFlexTimeandDuration() {
+ val repeatInterval = Duration.ofHours(3).plusMinutes(25)
+ val flexInterval = repeatInterval.minusMinutes(15)
+ val builder = PeriodicWorkRequestBuilder<TestWorker>(
+ repeatInterval = repeatInterval,
+ flexTimeInterval = flexInterval
+ )
+ val workRequest = builder.build()
+ assertEquals(workRequest.workSpec.workerClassName, TestWorker::class.java.name)
+ assertEquals(workRequest.workSpec.isPeriodic, true)
+ assertEquals(workRequest.workSpec.intervalDuration, repeatInterval.toMillis())
+ assertEquals(workRequest.workSpec.flexDuration, flexInterval.toMillis())
+ }
+
+ @Test
+ fun testPeriodicWorkRequestBuilder_noNextScheduleTimeOverride_noGeneration() {
+ val builder = PeriodicWorkRequestBuilder<TestWorker>(
+ HOURS.toMillis(15L), HOURS
+ )
+ assertEquals(builder.build().workSpec.nextScheduleTimeOverride, Long.MAX_VALUE)
+ assertEquals(builder.build().workSpec.nextScheduleTimeOverrideGeneration, 0)
+ }
+
+ @Test
+ fun testPeriodicWorkRequestBuilder_nextScheduleTimeOverride_setsGeneration() {
+ val builder = PeriodicWorkRequestBuilder<TestWorker>(
+ HOURS.toMillis(15L), HOURS
+ )
+ builder.setNextScheduleTimeOverride(123456)
+ assertEquals(builder.build().workSpec.nextScheduleTimeOverride, 123456L)
+ assertEquals(builder.build().workSpec.nextScheduleTimeOverrideGeneration, 1)
+ }
+
+ @Test
+ fun testPeriodicWorkRequestBuilder_nextScheduleTimeOverride_maxLongNotAllowed() {
+ val builder = PeriodicWorkRequestBuilder<TestWorker>(
+ HOURS.toMillis(15L), HOURS
+ )
+ assertThrows(IllegalArgumentException::class.java) {
+ builder.setNextScheduleTimeOverride(Long.MAX_VALUE)
+ }
+ }
+
+ @Test
+ fun testPeriodicWorkRequest_clearNextScheduleTimeOverride_setsGeneration() {
+ val plainRequest = PeriodicWorkRequestBuilder<TestWorker>(
+ HOURS.toMillis(15L), HOURS
+ ).build()
+
+ val clearedRequest = PeriodicWorkRequestBuilder<TestWorker>(
+ HOURS.toMillis(15L), HOURS
+ )
+ .setNextScheduleTimeOverride(123456)
+ .clearNextScheduleTimeOverride().build()
+
+ // The generation should stay incremented, since the request still has to clear any override
+ // that has been already set in the database.
+ assertNotEquals(plainRequest, clearedRequest)
+ }
+}
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/ProcessorTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/ProcessorTest.java
index 05c3313..bf5958b 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/ProcessorTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/ProcessorTest.java
@@ -63,7 +63,7 @@
@SmallTest
public void testStopWork_invalidWorkId() {
WorkGenerationalId id = new WorkGenerationalId("INVALID_WORK_ID", 0);
- assertThat(mProcessor.stopWork(new StartStopToken(id)), is(false));
+ assertThat(mProcessor.stopWork(new StartStopToken(id), 0), is(false));
}
@Test
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/ProcessorTests.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/ProcessorTests.kt
index 4e14382..8c2df9c 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/ProcessorTests.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/ProcessorTests.kt
@@ -106,7 +106,7 @@
val blockedThread = Executors.newSingleThreadExecutor()
blockedThread.execute {
// gonna stall for 10 seconds
- processor.stopWork(startStopToken)
+ processor.stopWork(startStopToken, 0)
}
assertTrue((firstWorker as StopLatchWorker).awaitOnStopCall())
// onStop call results in onExecuted. It happens on "main thread", which is instant
@@ -150,7 +150,7 @@
val info = ForegroundInfo(1, notification)
processor.startForeground(startStopToken.id.workSpecId, info)
// won't actually stopWork, because stopForeground should be used
- processor.stopWork(startStopToken)
+ processor.stopWork(startStopToken, 0)
processor.startWork(StartStopToken(request.workSpec.generationalId()))
assertTrue(processor.isEnqueued(startStopToken.id.workSpecId))
val firstWorker = factory.awaitWorker(request.id)
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/GreedySchedulerTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/GreedySchedulerTest.java
index 8bdb4dc..e4c3a10 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/GreedySchedulerTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/GreedySchedulerTest.java
@@ -18,6 +18,7 @@
import static androidx.work.WorkRequest.DEFAULT_BACKOFF_DELAY_MILLIS;
import static androidx.work.impl.model.WorkSpecKt.generationalId;
+import static androidx.work.impl.testutils.TestConstraintsKt.getConstraintsNotMet;
import static com.google.common.truth.Truth.assertThat;
@@ -164,10 +165,14 @@
// in order to stop the work, we should start it first.
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
mGreedyScheduler.onConstraintsStateChanged(work.getWorkSpec(), ConstraintsMet.INSTANCE);
- mGreedyScheduler.onConstraintsStateChanged(work.getWorkSpec(), ConstraintsNotMet.INSTANCE);
- ArgumentCaptor<StartStopToken> captor = ArgumentCaptor.forClass(StartStopToken.class);
- verify(mWorkLauncher).stopWork(captor.capture());
- assertThat(captor.getValue().getId().getWorkSpecId()).isEqualTo(work.getWorkSpec().id);
+ mGreedyScheduler.onConstraintsStateChanged(work.getWorkSpec(), getConstraintsNotMet());
+ ArgumentCaptor<StartStopToken> captorToken = ArgumentCaptor.forClass(StartStopToken.class);
+ ArgumentCaptor<ConstraintsNotMet> captorConstraints =
+ ArgumentCaptor.forClass(ConstraintsNotMet.class);
+ verify(mWorkLauncher).stopWork(captorToken.capture(), captorConstraints.capture());
+ assertThat(captorToken.getValue().getId().getWorkSpecId()).isEqualTo(work.getWorkSpec().id);
+ // doing this check because java vs inline classes
+ assertThat(captorConstraints.getValue()).isEqualTo(getConstraintsNotMet());
}
@Test
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/constraints/WorkConstraintsTrackerTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/constraints/WorkConstraintsTrackerTest.kt
index 817a060..48ff014 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/constraints/WorkConstraintsTrackerTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/constraints/WorkConstraintsTrackerTest.kt
@@ -18,9 +18,9 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.work.impl.constraints.ConstraintsState.ConstraintsMet
-import androidx.work.impl.constraints.ConstraintsState.ConstraintsNotMet
import androidx.work.impl.constraints.trackers.ConstraintTracker
import androidx.work.impl.model.WorkSpec
+import androidx.work.impl.testutils.ConstraintsNotMet
import androidx.work.impl.testutils.TestConstraintController
import androidx.work.impl.testutils.TestConstraintTracker
import androidx.work.testutils.launchTester
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/constraints/controllers/ConstraintControllerTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/constraints/controllers/ConstraintControllerTest.kt
index 932f872..f514d4a 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/constraints/controllers/ConstraintControllerTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/constraints/controllers/ConstraintControllerTest.kt
@@ -16,12 +16,14 @@
package androidx.work.impl.constraints.controllers
+import android.app.job.JobParameters.STOP_REASON_CONSTRAINT_DEVICE_IDLE
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import androidx.work.Constraints
import androidx.work.OneTimeWorkRequest
+import androidx.work.StopReason
import androidx.work.impl.constraints.ConstraintsState.ConstraintsMet
import androidx.work.impl.constraints.ConstraintsState.ConstraintsNotMet
import androidx.work.impl.constraints.trackers.ConstraintTracker
@@ -70,6 +72,8 @@
private class TestDeviceIdleConstraintController(
tracker: ConstraintTracker<Boolean>
) : ConstraintController<Boolean>(tracker) {
+ override val reason = StopReason(STOP_REASON_CONSTRAINT_DEVICE_IDLE)
+
override fun hasConstraint(workSpec: WorkSpec): Boolean {
return workSpec.constraints.requiresDeviceIdle()
}
@@ -103,4 +107,8 @@
override fun readSystemState() = deviceIdle
}
-}
\ No newline at end of file
+}
+
+private val ConstraintsNotMet: ConstraintsNotMet = ConstraintsNotMet(
+ StopReason(STOP_REASON_CONSTRAINT_DEVICE_IDLE)
+)
\ No newline at end of file
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
index 1ec33c1..74d5fcb 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
@@ -434,7 +434,7 @@
val intent = createStartForegroundIntent(context,
WorkGenerationalId(request.stringId, 0), metadata)
dispatcher.onStartCommand(intent)
- processor.stopWork(StartStopToken(WorkGenerationalId(request.stringId, 0)))
+ processor.stopWork(StartStopToken(WorkGenerationalId(request.stringId, 0)), 0)
val state = workDatabase.workSpecDao().getState(request.stringId)
assertThat(state, `is`(WorkInfo.State.RUNNING))
val stopAndCancelIntent = createCancelWorkIntent(context, request.stringId)
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/testutils/TestConstraints.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/testutils/TestConstraints.kt
index da4d479..e7050c9 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/testutils/TestConstraints.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/testutils/TestConstraints.kt
@@ -18,6 +18,8 @@
import android.content.Context
import androidx.test.core.app.ApplicationProvider
+import androidx.work.StopReason
+import androidx.work.impl.constraints.ConstraintsState
import androidx.work.impl.constraints.controllers.ConstraintController
import androidx.work.impl.constraints.trackers.ConstraintTracker
import androidx.work.impl.model.WorkSpec
@@ -55,6 +57,12 @@
tracker: ConstraintTracker<Boolean>,
private val constrainedIds: List<String>
) : ConstraintController<Boolean>(tracker) {
+ override val reason = StopReason.ConstraintTest
override fun hasConstraint(workSpec: WorkSpec) = workSpec.id in constrainedIds
override fun isConstrained(value: Boolean) = !value
}
+
+val ConstraintsNotMet = ConstraintsState.ConstraintsNotMet(StopReason.ConstraintTest)
+
+val StopReason.Companion.ConstraintTest
+ get() = StopReason(234234234)
\ No newline at end of file
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/worker/ProgressUpdatingWorker.kt b/work/work-runtime/src/androidTest/java/androidx/work/worker/ProgressUpdatingWorker.kt
new file mode 100644
index 0000000..2cd3acb
--- /dev/null
+++ b/work/work-runtime/src/androidTest/java/androidx/work/worker/ProgressUpdatingWorker.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work.worker
+
+import android.content.Context
+import androidx.work.CoroutineWorker
+import androidx.work.Data
+import androidx.work.WorkerParameters
+import kotlinx.coroutines.delay
+
+class ProgressUpdatingWorker(context: Context, parameters: WorkerParameters) :
+ CoroutineWorker(context, parameters) {
+
+ companion object {
+ const val Expected = "Expected"
+ const val Progress = "Progress"
+ private const val delayDuration = 1L
+ }
+
+ override suspend fun doWork(): Result {
+ val firstUpdate = Data.Builder().putInt(Progress, 10).build()
+ val lastUpdate = Data.Builder().putInt(Progress, 100).build()
+ val expected = inputData.getString(Expected)
+ setProgress(firstUpdate)
+ delay(delayDuration)
+ setProgress(lastUpdate)
+ return when (expected) {
+ "Failure" -> Result.failure()
+ "Retry" -> Result.retry()
+ else -> Result.success()
+ }
+ }
+}
\ No newline at end of file
diff --git a/work/work-runtime-ktx/src/main/java/androidx/work/CoroutineWorker.kt b/work/work-runtime/src/main/java/androidx/work/CoroutineWorker.kt
similarity index 100%
rename from work/work-runtime-ktx/src/main/java/androidx/work/CoroutineWorker.kt
rename to work/work-runtime/src/main/java/androidx/work/CoroutineWorker.kt
diff --git a/work/work-runtime/src/main/java/androidx/work/Data.java b/work/work-runtime/src/main/java/androidx/work/Data.java
index dcd71d9..bfe97f1 100644
--- a/work/work-runtime/src/main/java/androidx/work/Data.java
+++ b/work/work-runtime/src/main/java/androidx/work/Data.java
@@ -921,7 +921,7 @@
mValues.put(key, convertPrimitiveDoubleArray((double[]) value));
} else {
throw new IllegalArgumentException(
- "Key " + key + "has invalid type " + valueType);
+ "Key " + key + " has invalid type " + valueType);
}
}
return this;
diff --git a/work/work-runtime-ktx/src/main/java/androidx/work/Data.kt b/work/work-runtime/src/main/java/androidx/work/Data.kt
similarity index 100%
rename from work/work-runtime-ktx/src/main/java/androidx/work/Data.kt
rename to work/work-runtime/src/main/java/androidx/work/Data.kt
diff --git a/work/work-runtime-ktx/src/main/java/androidx/work/DirectExecutor.kt b/work/work-runtime/src/main/java/androidx/work/DirectExecutor.kt
similarity index 100%
rename from work/work-runtime-ktx/src/main/java/androidx/work/DirectExecutor.kt
rename to work/work-runtime/src/main/java/androidx/work/DirectExecutor.kt
diff --git a/work/work-runtime-ktx/src/main/java/androidx/work/ListenableFuture.kt b/work/work-runtime/src/main/java/androidx/work/ListenableFuture.kt
similarity index 100%
rename from work/work-runtime-ktx/src/main/java/androidx/work/ListenableFuture.kt
rename to work/work-runtime/src/main/java/androidx/work/ListenableFuture.kt
diff --git a/work/work-runtime-ktx/src/main/java/androidx/work/Operation.kt b/work/work-runtime/src/main/java/androidx/work/Operation.kt
similarity index 100%
rename from work/work-runtime-ktx/src/main/java/androidx/work/Operation.kt
rename to work/work-runtime/src/main/java/androidx/work/Operation.kt
diff --git a/work/work-runtime/src/main/java/androidx/work/StopReason.kt b/work/work-runtime/src/main/java/androidx/work/StopReason.kt
new file mode 100644
index 0000000..d3d0a75
--- /dev/null
+++ b/work/work-runtime/src/main/java/androidx/work/StopReason.kt
@@ -0,0 +1,36 @@
+/*
+ * 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
+
+import android.app.job.JobParameters.STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW
+import android.app.job.JobParameters.STOP_REASON_CONSTRAINT_CHARGING
+import android.app.job.JobParameters.STOP_REASON_CONSTRAINT_CONNECTIVITY
+import android.app.job.JobParameters.STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW
+import android.app.job.JobParameters.STOP_REASON_UNDEFINED
+import androidx.annotation.RestrictTo
+
+@JvmInline
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+value class StopReason internal constructor(val value: Int) {
+ companion object {
+ val ConstraintBatteryNotLow = StopReason(STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW)
+ val ConstraintCharging = StopReason(STOP_REASON_CONSTRAINT_CHARGING)
+ val ConstraintConnectivity = StopReason(STOP_REASON_CONSTRAINT_CONNECTIVITY)
+ val ConstraintStorageNotLow = StopReason(STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW)
+ val Undefined = StopReason(STOP_REASON_UNDEFINED)
+ }
+}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/Processor.java b/work/work-runtime/src/main/java/androidx/work/impl/Processor.java
index 83b6d7a..633dc65 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/Processor.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/Processor.java
@@ -229,7 +229,7 @@
* @param runId The work id to stop
* @return {@code true} if the work was stopped successfully
*/
- public boolean stopWork(@NonNull StartStopToken runId) {
+ public boolean stopWork(@NonNull StartStopToken runId, int reason) {
String id = runId.getId().getWorkSpecId();
WorkerWrapper wrapper = null;
synchronized (mLock) {
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/WorkLauncher.kt b/work/work-runtime/src/main/java/androidx/work/impl/WorkLauncher.kt
index 5a249dd..1f7c9a5 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/WorkLauncher.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/WorkLauncher.kt
@@ -16,8 +16,10 @@
package androidx.work.impl
+import androidx.work.StopReason
import androidx.work.WorkerParameters
import androidx.work.WorkerParameters.RuntimeExtras
+import androidx.work.impl.constraints.ConstraintsState.ConstraintsNotMet
import androidx.work.impl.model.WorkSpec
import androidx.work.impl.utils.StartWorkRunnable
import androidx.work.impl.utils.StopWorkRunnable
@@ -38,7 +40,15 @@
/**
* @param workSpecId The [WorkSpec] id to stop
*/
- fun stopWork(workSpecId: StartStopToken)
+ fun stopWork(workSpecId: StartStopToken) {
+ stopWork(workSpecId, StopReason.Undefined)
+ }
+
+ fun stopWork(workSpecId: StartStopToken, reason: StopReason)
+
+ // compat scheme for java callers
+ fun stopWork(workSpecId: StartStopToken, constraintsNotMet: ConstraintsNotMet) =
+ stopWork(workSpecId, constraintsNotMet.reason)
}
class WorkLauncherImpl(
@@ -50,7 +60,9 @@
workTaskExecutor.executeOnTaskThread(startWork)
}
- override fun stopWork(workSpecId: StartStopToken) {
- workTaskExecutor.executeOnTaskThread(StopWorkRunnable(processor, workSpecId, false))
+ override fun stopWork(workSpecId: StartStopToken, reason: StopReason) {
+ workTaskExecutor.executeOnTaskThread(
+ StopWorkRunnable(processor, workSpecId, false, reason)
+ )
}
}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/GreedyScheduler.java b/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/GreedyScheduler.java
index 97b2c19..5788629 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/GreedyScheduler.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/GreedyScheduler.java
@@ -234,7 +234,7 @@
Logger.get().debug(TAG, "Constraints not met: Cancelling work ID " + id);
StartStopToken runId = mStartStopTokens.remove(id);
if (runId != null) {
- mWorkLauncher.stopWork(runId);
+ mWorkLauncher.stopWork(runId, (ConstraintsState.ConstraintsNotMet) state);
}
}
}
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/constraints/WorkConstraintsTracker.kt b/work/work-runtime/src/main/java/androidx/work/impl/constraints/WorkConstraintsTracker.kt
index 3ecadff..f52a0f5 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/constraints/WorkConstraintsTracker.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/constraints/WorkConstraintsTracker.kt
@@ -16,6 +16,7 @@
package androidx.work.impl.constraints
import androidx.work.Logger
+import androidx.work.StopReason
import androidx.work.impl.constraints.ConstraintsState.ConstraintsMet
import androidx.work.impl.constraints.controllers.BatteryChargingController
import androidx.work.impl.constraints.controllers.BatteryNotLowController
@@ -37,9 +38,7 @@
sealed class ConstraintsState {
object ConstraintsMet : ConstraintsState()
-
- // TODO: will have a reason
- object ConstraintsNotMet : ConstraintsState()
+ data class ConstraintsNotMet(val reason: StopReason) : ConstraintsState()
}
fun WorkConstraintsTracker.listen(
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/constraints/controllers/ContraintControllers.kt b/work/work-runtime/src/main/java/androidx/work/impl/constraints/controllers/ContraintControllers.kt
index 2f9ad21..0308c47 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/constraints/controllers/ContraintControllers.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/constraints/controllers/ContraintControllers.kt
@@ -21,6 +21,7 @@
import androidx.work.NetworkType
import androidx.work.NetworkType.TEMPORARILY_UNMETERED
import androidx.work.NetworkType.UNMETERED
+import androidx.work.StopReason
import androidx.work.impl.constraints.ConstraintListener
import androidx.work.impl.constraints.ConstraintsState
import androidx.work.impl.constraints.ConstraintsState.ConstraintsMet
@@ -36,13 +37,15 @@
abstract class ConstraintController<T>(
private val tracker: ConstraintTracker<T>
) {
+ abstract val reason: StopReason
abstract fun hasConstraint(workSpec: WorkSpec): Boolean
abstract fun isConstrained(value: T): Boolean
fun track(): Flow<ConstraintsState> = callbackFlow {
val listener = object : ConstraintListener<T> {
override fun onConstraintChanged(newValue: T) {
- val value = if (isConstrained(newValue)) ConstraintsNotMet else ConstraintsMet
+ val value = if (isConstrained(newValue))
+ ConstraintsNotMet(reason) else ConstraintsMet
channel.trySend(value)
}
}
@@ -62,6 +65,7 @@
*/
class BatteryChargingController(tracker: ConstraintTracker<Boolean>) :
ConstraintController<Boolean>(tracker) {
+ override val reason = StopReason.ConstraintCharging
override fun hasConstraint(workSpec: WorkSpec) = workSpec.constraints.requiresCharging()
override fun isConstrained(value: Boolean) = !value
@@ -72,6 +76,7 @@
*/
class BatteryNotLowController(tracker: BatteryNotLowTracker) :
ConstraintController<Boolean>(tracker) {
+ override val reason = StopReason.ConstraintBatteryNotLow
override fun hasConstraint(workSpec: WorkSpec) = workSpec.constraints.requiresBatteryNotLow()
override fun isConstrained(value: Boolean) = !value
@@ -82,6 +87,7 @@
*/
class NetworkUnmeteredController(tracker: ConstraintTracker<NetworkState>) :
ConstraintController<NetworkState>(tracker) {
+ override val reason = StopReason.ConstraintConnectivity
override fun hasConstraint(workSpec: WorkSpec): Boolean {
val requiredNetworkType = workSpec.constraints.requiredNetworkType
return requiredNetworkType == UNMETERED ||
@@ -96,7 +102,7 @@
*/
class StorageNotLowController(tracker: ConstraintTracker<Boolean>) :
ConstraintController<Boolean>(tracker) {
-
+ override val reason = StopReason.ConstraintStorageNotLow
override fun hasConstraint(workSpec: WorkSpec) = workSpec.constraints.requiresStorageNotLow()
override fun isConstrained(value: Boolean) = !value
@@ -107,6 +113,7 @@
*/
class NetworkNotRoamingController(tracker: ConstraintTracker<NetworkState>) :
ConstraintController<NetworkState>(tracker) {
+ override val reason = StopReason.ConstraintConnectivity
override fun hasConstraint(workSpec: WorkSpec): Boolean {
return workSpec.constraints.requiredNetworkType == NetworkType.NOT_ROAMING
}
@@ -142,6 +149,7 @@
*/
class NetworkConnectedController(tracker: ConstraintTracker<NetworkState>) :
ConstraintController<NetworkState>(tracker) {
+ override val reason = StopReason.ConstraintConnectivity
override fun hasConstraint(workSpec: WorkSpec) =
workSpec.constraints.requiredNetworkType == NetworkType.CONNECTED
@@ -158,6 +166,7 @@
*/
class NetworkMeteredController(tracker: ConstraintTracker<NetworkState>) :
ConstraintController<NetworkState>(tracker) {
+ override val reason = StopReason.ConstraintConnectivity
override fun hasConstraint(workSpec: WorkSpec) =
workSpec.constraints.requiredNetworkType == NetworkType.METERED
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java b/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
index 71a2547..85881c8 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
@@ -48,6 +48,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
+import androidx.core.os.UserManagerCompat;
import androidx.core.util.Consumer;
import androidx.work.Configuration;
import androidx.work.Logger;
@@ -146,8 +147,17 @@
// PackageManager bugs are attributed to ForceStopRunnable, which is
// unfortunate. This gives the developer a better error
// message.
- String message = "The file system on the device is in a bad state. "
- + "WorkManager cannot access the app's internal data store.";
+ String message;
+ if (UserManagerCompat.isUserUnlocked(mContext)) {
+ message = "The file system on the device is in a bad state. "
+ + "WorkManager cannot access the app's internal data store.";
+ } else {
+ message = "WorkManager can't be accessed from direct boot, because "
+ + "credential encrypted storage isn't accessible.\n"
+ + "Don't access or initialise WorkManager from directAware "
+ + "components. See "
+ + "https://developer.android.com/training/articles/direct-boot";
+ }
Logger.get().error(TAG, message, exception);
IllegalStateException throwable = new IllegalStateException(message,
exception);
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/StopWorkRunnable.kt b/work/work-runtime/src/main/java/androidx/work/impl/utils/StopWorkRunnable.kt
index cc9ee9d..d466967 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/utils/StopWorkRunnable.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/utils/StopWorkRunnable.kt
@@ -17,6 +17,7 @@
import androidx.annotation.RestrictTo
import androidx.work.Logger
+import androidx.work.StopReason
import androidx.work.impl.Processor
import androidx.work.impl.StartStopToken
@@ -27,15 +28,25 @@
class StopWorkRunnable(
private val processor: Processor,
private val token: StartStopToken,
- private val stopInForeground: Boolean
+ private val stopInForeground: Boolean,
+ private val reason: StopReason,
) : Runnable {
+
+ // java compatibility, can't use default args because @JvmOverloads doesn't work with
+ // inline classes
+ constructor(
+ processor: Processor,
+ token: StartStopToken,
+ stopInForeground: Boolean,
+ ) : this(processor, token, stopInForeground, StopReason.Undefined)
+
override fun run() {
val isStopped = if (stopInForeground) {
processor.stopForegroundWork(token)
} else {
// This call is safe to make for foreground work because Processor ignores requests
// to stop for foreground work.
- processor.stopWork(token)
+ processor.stopWork(token, reason.value)
}
Logger.get().debug(
Logger.tagWithPrefix("StopWorkRunnable"),
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/workers/ConstraintTrackingWorker.kt b/work/work-runtime/src/main/java/androidx/work/impl/workers/ConstraintTrackingWorker.kt
index 520f184..404af80 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/workers/ConstraintTrackingWorker.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/workers/ConstraintTrackingWorker.kt
@@ -146,7 +146,7 @@
override fun onConstraintsStateChanged(workSpec: WorkSpec, state: ConstraintsState) {
// If at any point, constraints are not met mark it so we can retry the work.
Logger.get().debug(TAG, "Constraints changed for $workSpec")
- if (state == ConstraintsNotMet) {
+ if (state is ConstraintsNotMet) {
synchronized(lock) { areConstraintsUnmet = true }
}
}
diff --git a/work/work-testing/api/current.txt b/work/work-testing/api/current.txt
index e6473bb..fda4ffa 100644
--- a/work/work-testing/api/current.txt
+++ b/work/work-testing/api/current.txt
@@ -46,8 +46,13 @@
method public static androidx.work.testing.TestDriver? getTestDriver(android.content.Context);
method public static void initializeTestWorkManager(android.content.Context);
method public static void initializeTestWorkManager(android.content.Context, androidx.work.Configuration);
- method public static void initializeTestWorkManagerWithRealExecutors(android.content.Context);
- method public static void initializeTestWorkManagerWithRealExecutors(android.content.Context, androidx.work.Configuration);
+ method public static void initializeTestWorkManager(android.content.Context, androidx.work.Configuration, androidx.work.testing.WorkManagerTestInitHelper.ExecutorsMode);
+ method public static void initializeTestWorkManager(android.content.Context, androidx.work.testing.WorkManagerTestInitHelper.ExecutorsMode);
+ }
+
+ public enum WorkManagerTestInitHelper.ExecutorsMode {
+ enum_constant public static final androidx.work.testing.WorkManagerTestInitHelper.ExecutorsMode LEGACY_OVERRIDE_WITH_SYNCHRONOUS_EXECUTORS;
+ enum_constant public static final androidx.work.testing.WorkManagerTestInitHelper.ExecutorsMode PRESERVE_EXECUTORS;
}
}
diff --git a/work/work-testing/api/restricted_current.txt b/work/work-testing/api/restricted_current.txt
index e6473bb..fda4ffa 100644
--- a/work/work-testing/api/restricted_current.txt
+++ b/work/work-testing/api/restricted_current.txt
@@ -46,8 +46,13 @@
method public static androidx.work.testing.TestDriver? getTestDriver(android.content.Context);
method public static void initializeTestWorkManager(android.content.Context);
method public static void initializeTestWorkManager(android.content.Context, androidx.work.Configuration);
- method public static void initializeTestWorkManagerWithRealExecutors(android.content.Context);
- method public static void initializeTestWorkManagerWithRealExecutors(android.content.Context, androidx.work.Configuration);
+ method public static void initializeTestWorkManager(android.content.Context, androidx.work.Configuration, androidx.work.testing.WorkManagerTestInitHelper.ExecutorsMode);
+ method public static void initializeTestWorkManager(android.content.Context, androidx.work.testing.WorkManagerTestInitHelper.ExecutorsMode);
+ }
+
+ public enum WorkManagerTestInitHelper.ExecutorsMode {
+ enum_constant public static final androidx.work.testing.WorkManagerTestInitHelper.ExecutorsMode LEGACY_OVERRIDE_WITH_SYNCHRONOUS_EXECUTORS;
+ enum_constant public static final androidx.work.testing.WorkManagerTestInitHelper.ExecutorsMode PRESERVE_EXECUTORS;
}
}
diff --git a/work/work-testing/build.gradle b/work/work-testing/build.gradle
index 52a3ba4..66ef58e 100644
--- a/work/work-testing/build.gradle
+++ b/work/work-testing/build.gradle
@@ -23,7 +23,7 @@
}
dependencies {
- api(project(":work:work-runtime-ktx"))
+ api(project(":work:work-runtime"))
implementation("androidx.lifecycle:lifecycle-livedata-core:2.5.1")
implementation("androidx.room:room-runtime:2.5.0")
diff --git a/work/work-testing/src/androidTest/java/androidx/work/testing/TestSchedulerRealExecutorTest.kt b/work/work-testing/src/androidTest/java/androidx/work/testing/TestSchedulerRealExecutorTest.kt
index 78b5732..db35c0e 100644
--- a/work/work-testing/src/androidTest/java/androidx/work/testing/TestSchedulerRealExecutorTest.kt
+++ b/work/work-testing/src/androidTest/java/androidx/work/testing/TestSchedulerRealExecutorTest.kt
@@ -33,6 +33,7 @@
import androidx.work.impl.WorkManagerImpl
import androidx.work.impl.model.WorkSpec
import androidx.work.impl.utils.taskexecutor.SerialExecutor
+import androidx.work.testing.WorkManagerTestInitHelper.ExecutorsMode.PRESERVE_EXECUTORS
import androidx.work.testing.workers.CountingTestWorker
import androidx.work.testing.workers.RetryWorker
import androidx.work.testing.workers.TestWorker
@@ -49,7 +50,7 @@
val context = ApplicationProvider.getApplicationContext<Context>()
init {
- WorkManagerTestInitHelper.initializeTestWorkManagerWithRealExecutors(context)
+ WorkManagerTestInitHelper.initializeTestWorkManager(context, PRESERVE_EXECUTORS)
CountingTestWorker.COUNT.set(0)
}
diff --git a/work/work-testing/src/main/java/androidx/work/testing/WorkManagerTestInitHelper.java b/work/work-testing/src/main/java/androidx/work/testing/WorkManagerTestInitHelper.java
index 22155ed..8abaefb 100644
--- a/work/work-testing/src/main/java/androidx/work/testing/WorkManagerTestInitHelper.java
+++ b/work/work-testing/src/main/java/androidx/work/testing/WorkManagerTestInitHelper.java
@@ -17,6 +17,7 @@
package androidx.work.testing;
import static androidx.work.testing.TestWorkManagerImplKt.createTestWorkManagerImpl;
+import static androidx.work.testing.WorkManagerTestInitHelper.ExecutorsMode.LEGACY_OVERRIDE_WITH_SYNCHRONOUS_EXECUTORS;
import android.content.Context;
@@ -57,48 +58,82 @@
public static void initializeTestWorkManager(
@NonNull Context context,
@NonNull Configuration configuration) {
+ initializeTestWorkManager(context, configuration,
+ LEGACY_OVERRIDE_WITH_SYNCHRONOUS_EXECUTORS);
+ }
- // Check if the configuration being used has overridden the task executor. If not,
- // swap to SynchronousExecutor. This is to preserve existing behavior.
- SerialExecutor serialExecutor;
- if (configuration.isUsingDefaultTaskExecutor()) {
- Configuration.Builder builder = new Configuration.Builder(configuration)
- .setTaskExecutor(new SynchronousExecutor());
- configuration = builder.build();
- serialExecutor = new SynchronousSerialExecutor();
+ /**
+ * Modes that control which executors are used in tests.
+ */
+ public enum ExecutorsMode {
+ /**
+ * Use executors as they are configured in passed {@link Configuration} and preserving
+ * real main thread.
+ */
+ PRESERVE_EXECUTORS,
+
+ /**
+ * Preserve old behavior of {@link #initializeTestWorkManager(Context)} and
+ * {@link #initializeTestWorkManager(Context, Configuration)}.
+ *
+ * <p> In this mode {@link SynchronousExecutor} is used instead of main thread. Similarly,
+ * {@link SynchronousExecutor} is used as {@link Configuration#getTaskExecutor()}, unless
+ * {@link Configuration#getTaskExecutor()} was explicitly set in {@code configuration}
+ * passed in {@link #initializeTestWorkManager(Context, Configuration, ExecutorsMode)}
+ */
+ LEGACY_OVERRIDE_WITH_SYNCHRONOUS_EXECUTORS
+ }
+
+ /**
+ * Initializes a test {@link androidx.work.WorkManager} that can be controlled via {@link
+ * TestDriver}.
+ *
+ * @param context The application {@link Context}
+ * @param configuration test configuration of WorkManager
+ * @param executorsMode mode controlling executors used by WorkManager in tests. See
+ * documentation of modes in {@link ExecutorsMode}
+ */
+ public static void initializeTestWorkManager(@NonNull Context context,
+ @NonNull Configuration configuration, @NonNull ExecutorsMode executorsMode) {
+ WorkManagerImpl workManager;
+ if (executorsMode == LEGACY_OVERRIDE_WITH_SYNCHRONOUS_EXECUTORS) {
+ SerialExecutor serialExecutor;
+ if (configuration.isUsingDefaultTaskExecutor()) {
+ Configuration.Builder builder = new Configuration.Builder(configuration)
+ .setTaskExecutor(new SynchronousExecutor());
+ configuration = builder.build();
+ serialExecutor = new SynchronousSerialExecutor();
+ } else {
+ serialExecutor = new SerialExecutorImpl(configuration.getTaskExecutor());
+ }
+ workManager = createTestWorkManagerImpl(context, configuration, serialExecutor);
} else {
- serialExecutor = new SerialExecutorImpl(configuration.getTaskExecutor());
+ workManager = createTestWorkManagerImpl(context, configuration);
}
-
- WorkManagerImpl.setDelegate(
- createTestWorkManagerImpl(context, configuration, serialExecutor)
- );
+ WorkManagerImpl.setDelegate(workManager);
}
/**
- * Initializes a test {@link androidx.work.WorkManager} with a default configuration and
- * real threading unlike {@link #initializeTestWorkManager(Context)} that uses a
- * {@link SynchronousExecutor} as main thread and both executors
- * (see {@link Configuration#getTaskExecutor()} and {@link Configuration#getExecutor()}).
+ * Initializes a test {@link androidx.work.WorkManager} that can be controlled via {@link
+ * TestDriver}.
*
* @param context The application {@link Context}
+ * @param executorsMode mode controlling executors used by WorkManager in tests. See
+ * documentation of modes in {@link ExecutorsMode}
*/
- public static void initializeTestWorkManagerWithRealExecutors(@NonNull Context context) {
- Configuration configuration = new Configuration.Builder().build();
- WorkManagerImpl.setDelegate(createTestWorkManagerImpl(context, configuration));
- }
-
- /**
- * Initializes a test {@link androidx.work.WorkManager} with a default configuration and
- * real threading unlike {@link #initializeTestWorkManager(Context, Configuration)} that uses a
- * {@link SynchronousExecutor} as main thread.
- *
- * @param context The application {@link Context}
- * @param configuration The {@link androidx.work.Configuration}
- */
- public static void initializeTestWorkManagerWithRealExecutors(
- @NonNull Context context, @NonNull Configuration configuration) {
- WorkManagerImpl.setDelegate(createTestWorkManagerImpl(context, configuration));
+ public static void initializeTestWorkManager(@NonNull Context context,
+ @NonNull ExecutorsMode executorsMode) {
+ Configuration configuration;
+ if (executorsMode == LEGACY_OVERRIDE_WITH_SYNCHRONOUS_EXECUTORS) {
+ SynchronousExecutor synchronousExecutor = new SynchronousExecutor();
+ configuration = new Configuration.Builder()
+ .setExecutor(synchronousExecutor)
+ .setTaskExecutor(synchronousExecutor)
+ .build();
+ } else {
+ configuration = new Configuration.Builder().build();
+ }
+ initializeTestWorkManager(context, configuration, executorsMode);
}
/**